Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Kubernetes Deployment

Deploy Radar Collector in Kubernetes using Deployments, ConfigMaps, and Secrets for scalable monitoring.

Prerequisites

  • Kubernetes cluster (1.19+)
  • kubectl configured to access your cluster
  • Container image of Radar Collector

Container Image

The Radar Collector is published to GHCR:

# Pull the latest stable alpine image (recommended)
docker pull ghcr.io/redis-field-engineering/radar-collector:alpine-latest

# Or pin to a specific version (recommended for production)
docker pull ghcr.io/redis-field-engineering/radar-collector:alpine-v1.2.1

The default entrypoint and command in the published image are:

ENTRYPOINT ["/usr/local/bin/radar-collector"]
CMD ["--config", "/etc/radar/radar-collector.yml"]

Quick Start

1. Create Namespace

# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: radar-collector
  labels:
    name: radar-collector
kubectl apply -f namespace.yaml

2. Create Secrets

Store sensitive configuration in Kubernetes Secrets.

Obtaining an API key: Log in to the Radar dashboard and navigate to Settings > Access Keys to generate a new key.

# secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: radar-collector-secrets
  namespace: radar-collector
type: Opaque
stringData:
  api-key: "your-radar-api-key"
  enterprise-basic-auth: "admin@cluster.local:enterprise-password"

For Redis Software, enterprise-basic-auth must be a single username:password value because the collector uses it for REST API basic auth. For direct Redis connections such as standalone or cluster, store only the Redis password in the Secret, for example redis-password: "your-redis-password", and reference that from ${REDIS_STANDALONE_PASSWORD} or ${REDIS_CLUSTER_PASSWORD}. If you use Redis ACLs, keep the username as a separate field in the collector config.

Create radar-collector-secrets in the same namespace as the collector Deployment. This repository does not include a committed staging copy of that Secret, so if your collector runs in staging, create the Secret in staging and update the manifest namespace accordingly.

kubectl apply -f secrets.yaml

3. Create ConfigMap

Store the collector configuration:

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: radar-collector-config
  namespace: radar-collector
data:
  radar-collector.yml: |
    collector:
      id: "radar-collector-k8s-${HOSTNAME}"
      hostname: "${HOSTNAME}"
      collection_interval: "30s"
      remote_config:
        enabled: false

    server:
      grpc_url: "https://grpc.radar.redis.io:443"
      api_key: "${RADAR_API_KEY}"

    deployments:
      - id: "redis-enterprise"
        name: "Redis Software Production"
        type: "enterprise"
        rest_api:
          host: "cluster.redis.local"
          port: 9443
          use_tls: true
          insecure: true
          enterprise_admin_url: "https://cluster.redis.local:8443"
        enterprise:
          db_endpoint: external_ip
        credentials:
          rest_api:
            basic_auth: "${ENTERPRISE_BASIC_AUTH}"
kubectl apply -f configmap.yaml

4. Create Deployment

Deploy the Radar Collector:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: radar-collector
  namespace: radar-collector
  labels:
    app: radar-collector
spec:
  replicas: 1
  selector:
    matchLabels:
      app: radar-collector
  template:
    metadata:
      labels:
        app: radar-collector
    spec:
      serviceAccountName: radar-collector
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        runAsGroup: 1000
        fsGroup: 1000
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: radar-collector
          image: ghcr.io/redis-field-engineering/radar-collector:alpine-latest
          imagePullPolicy: Always

          env:
            - name: HOSTNAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: RADAR_API_KEY
              valueFrom:
                secretKeyRef:
                  name: radar-collector-secrets
                  key: api-key
            - name: ENTERPRISE_BASIC_AUTH
              valueFrom:
                secretKeyRef:
                  name: radar-collector-secrets
                  key: enterprise-basic-auth
            - name: RUST_LOG
              value: "info"

          volumeMounts:
            - name: config
              mountPath: /etc/radar
              readOnly: true

          resources:
            requests:
              memory: "64Mi"
              cpu: "50m"
            limits:
              memory: "128Mi"
              cpu: "200m"

          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop:
                - ALL

      volumes:
        - name: config
          configMap:
            name: radar-collector-config

      restartPolicy: Always
      nodeSelector:
        kubernetes.io/os: linux

5. Create ServiceAccount and RBAC

Create service account with minimal permissions:

# rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: radar-collector
  namespace: radar-collector

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: radar-collector
  namespace: radar-collector
rules:
  - apiGroups: [""]
    resources: ["configmaps", "secrets"]
    verbs: ["get", "list"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: radar-collector
  namespace: radar-collector
subjects:
  - kind: ServiceAccount
    name: radar-collector
    namespace: radar-collector
roleRef:
  kind: Role
  name: radar-collector
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f rbac.yaml
kubectl apply -f deployment.yaml

Deployment Type Reference

The examples above use Redis Software by default. If you are collecting from a different deployment type, replace the deployments entry in radar-collector.yml and update the referenced secret/env var names to match.

Redis Software (type: enterprise)

The collector connects to the Redis Software REST API to discover all databases in the cluster. It does not connect directly to individual Redis instances for collection.

- id: "redis-enterprise"
  name: "Redis Software Production"
  type: "enterprise"
  rest_api:
    host: "cluster.redis.local"     # REST API hostname
    port: 9443                       # REST API port (typically 9443)
    use_tls: true                    # Use HTTPS (recommended for production)
    insecure: true                   # Skip cert verification (for self-signed certs)
    enterprise_admin_url: "https://cluster.redis.local:8443"  # Optional management UI link
  enterprise:
    db_endpoint: external_ip         # How to report DB endpoints: external_ip, internal_ip, or dns
  credentials:
    rest_api:
      basic_auth: "${ENTERPRISE_BASIC_AUTH}"  # "username:password" format

Network requirements: The collector pod needs egress to the REST API host on port 9443 (HTTPS).

Secret value: enterprise-basic-auth: "username:password"

Standalone (type: standalone)

Connects directly to a single Redis instance. Use rediss:// for TLS.

- id: "redis-cache"
  name: "Session Cache"
  type: "standalone"
  redis_url: "redis://redis-cache.svc.cluster.local:6379"
  credentials:
    password: "${REDIS_STANDALONE_PASSWORD}"

Network requirements: Egress to the Redis host on port 6379 (or 6380 for TLS).

Secret value: redis-password: "your-redis-password"

Cluster (type: cluster)

Provide seed nodes. The collector runs CLUSTER NODES to automatically discover the full topology, then collects from every node.

- id: "redis-cluster"
  name: "Data Cluster"
  type: "cluster"
  redis_urls:
    - "redis-node-0.svc.cluster.local:7000"
    - "redis-node-1.svc.cluster.local:7000"
    - "redis-node-2.svc.cluster.local:7000"
  credentials:
    username: "radar-agent"           # Optional ACL username
    password: "${REDIS_CLUSTER_PASSWORD}"

Network requirements: Egress to every cluster node on the Redis port. Since the collector discovers nodes dynamically, ensure network policies allow traffic to all nodes in the cluster, not just the seed nodes.

Secret value: redis-cluster-password: "your-redis-password" with optional username in the collector config when ACLs are enabled.

Advanced Configuration

Multi-Environment Setup

Deploy different collectors for different environments:

# production-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: radar-collector-production
  namespace: radar-collector
spec:
  replicas: 1
  selector:
    matchLabels:
      app: radar-collector
      environment: production
  template:
    metadata:
      labels:
        app: radar-collector
        environment: production
    spec:
      containers:
        - name: radar-collector
          image: ghcr.io/redis-field-engineering/radar-collector:alpine-latest
          env:
            - name: ENVIRONMENT
              value: "production"
          volumeMounts:
            - name: config
              mountPath: /etc/radar
      volumes:
        - name: config
          configMap:
            name: radar-collector-config-production

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: radar-collector-staging
  namespace: radar-collector
spec:
  replicas: 1
  selector:
    matchLabels:
      app: radar-collector
      environment: staging
  template:
    metadata:
      labels:
        app: radar-collector
        environment: staging
    spec:
      containers:
        - name: radar-collector
          image: ghcr.io/redis-field-engineering/radar-collector:alpine-latest
          env:
            - name: ENVIRONMENT
              value: "staging"
          volumeMounts:
            - name: config
              mountPath: /etc/radar
      volumes:
        - name: config
          configMap:
            name: radar-collector-config-staging

Network Policies

Restrict network access:

# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: radar-collector-netpol
  namespace: radar-collector
spec:
  podSelector:
    matchLabels:
      app: radar-collector
  policyTypes:
    - Egress
  egress:
    # Allow DNS resolution
    - to: []
      ports:
        - protocol: UDP
          port: 53
    # Allow HTTPS/gRPC to Radar server
    - to: []
      ports:
        - protocol: TCP
          port: 443
    # Allow Redis Software REST API
    - to: []
      ports:
        - protocol: TCP
          port: 9443

If you switch the collector to type: standalone, allow egress to the Redis host on 6379 or 6380. If you switch to type: cluster, allow egress to the seed nodes and all discovered cluster nodes, commonly on port 7000.

TLS and Corporate CA Certificates

If your environment uses a corporate proxy or private CA, the collector’s TLS library cannot verify the Radar gRPC server certificate by default. Mount a complete CA bundle into the container to resolve this.

Mount CA Bundle

Add the CA bundle as a ConfigMap or Secret and mount it into the container:

apiVersion: v1
kind: ConfigMap
metadata:
  name: corporate-ca
  namespace: radar-collector
data:
  ca-bundle.crt: |
    -----BEGIN CERTIFICATE-----
    ... system and corporate CA certificates ...
    -----END CERTIFICATE-----

Then add the volume and mount to your Deployment:

spec:
  containers:
    - name: radar-collector
      image: ghcr.io/redis-field-engineering/radar-collector:alpine-latest
      volumeMounts:
        - name: config
          mountPath: /etc/radar
          readOnly: true
        - name: ca-cert
          mountPath: /etc/radar/certs/ca-bundle.crt
          subPath: ca-bundle.crt
          readOnly: true
  volumes:
    - name: config
      configMap:
        name: radar-collector-config
    - name: ca-cert
      configMap:
        name: corporate-ca

Important: Do not mount a single corporate CA certificate over /etc/ssl/certs/ca-certificates.crt unless that file is a complete CA bundle. Replacing the system bundle with a single certificate can break TLS verification for endpoints that rely on public CAs.

Using SSL_CERT_FILE

Set SSL_CERT_FILE only when it points to a complete CA bundle:

env:
  - name: SSL_CERT_FILE
    value: "/etc/radar/certs/ca-bundle.crt"

Management and Operations

View Logs

kubectl logs -n radar-collector -l app=radar-collector -f
kubectl logs -n radar-collector <pod-name> -f
kubectl logs -n radar-collector <pod-name> --previous

Update Configuration

kubectl apply -f configmap.yaml
kubectl rollout restart deployment/radar-collector -n radar-collector
kubectl rollout status deployment/radar-collector -n radar-collector

Troubleshooting

Common Issues

Pod won’t start:

kubectl get pods -n radar-collector
kubectl describe pod <pod-name> -n radar-collector
kubectl logs <pod-name> -n radar-collector

Configuration issues:

kubectl get configmap radar-collector-config -n radar-collector -o yaml
kubectl exec -it <pod-name> -n radar-collector -- radar-collector --validate --config /etc/radar/radar-collector.yml

Health Checks

kubectl get deployment radar-collector -n radar-collector
kubectl get pods -n radar-collector -l app=radar-collector
kubectl get events -n radar-collector --sort-by='.lastTimestamp'