🎤Speaking at KubeCon EU 2026Lessons Learned Orchestrating Multi-Tenant GPUs on OpenShift AIView Session
Deployments intermediate ⏱ 15 minutes K8s 1.28+

How to Use Sidecar Containers Effectively

Implement sidecar containers for logging, monitoring, proxying, and configuration management. Learn common sidecar patterns for microservices.

By Luca Berton

How to Use Sidecar Containers Effectively

Sidecar containers extend and enhance your main application containers. Use them for logging, monitoring, proxying, and configuration management without modifying your application code.

Logging Sidecar

# logging-sidecar.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-with-logging
spec:
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        # Main application
        - name: app
          image: myapp:v1
          volumeMounts:
            - name: logs
              mountPath: /var/log/app
        
        # Logging sidecar - ships logs to central system
        - name: log-shipper
          image: fluent/fluent-bit:latest
          volumeMounts:
            - name: logs
              mountPath: /var/log/app
              readOnly: true
            - name: fluent-config
              mountPath: /fluent-bit/etc
          resources:
            requests:
              cpu: 50m
              memory: 64Mi
            limits:
              cpu: 100m
              memory: 128Mi
      
      volumes:
        - name: logs
          emptyDir: {}
        - name: fluent-config
          configMap:
            name: fluent-bit-config
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: fluent-bit-config
data:
  fluent-bit.conf: |
    [INPUT]
        Name tail
        Path /var/log/app/*.log
        Tag app.logs
    [OUTPUT]
        Name forward
        Match *
        Host fluentd.logging
        Port 24224

Envoy Proxy Sidecar

# envoy-sidecar.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-with-envoy
spec:
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        # Main application
        - name: app
          image: myapp:v1
          ports:
            - containerPort: 8080
          env:
            - name: LISTEN_PORT
              value: "8080"
        
        # Envoy proxy sidecar
        - name: envoy
          image: envoyproxy/envoy:v1.28-latest
          ports:
            - containerPort: 9901  # Admin
            - containerPort: 10000 # Ingress
          volumeMounts:
            - name: envoy-config
              mountPath: /etc/envoy
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
      
      volumes:
        - name: envoy-config
          configMap:
            name: envoy-config

Config Reload Sidecar

# config-reload-sidecar.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-with-reload
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        # Main nginx
        - name: nginx
          image: nginx:1.25
          volumeMounts:
            - name: config
              mountPath: /etc/nginx/conf.d
        
        # Config reloader sidecar
        - name: config-reloader
          image: jimmidyson/configmap-reload:v0.9.0
          args:
            - --volume-dir=/etc/nginx/conf.d
            - --webhook-url=http://localhost:80/-/reload
            - --webhook-method=POST
          volumeMounts:
            - name: config
              mountPath: /etc/nginx/conf.d
              readOnly: true
          resources:
            requests:
              cpu: 10m
              memory: 16Mi
      
      volumes:
        - name: config
          configMap:
            name: nginx-config

Metrics Exporter Sidecar

# metrics-sidecar.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-with-exporter
spec:
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9121"
    spec:
      containers:
        # Main Redis
        - name: redis
          image: redis:7
          ports:
            - containerPort: 6379
        
        # Prometheus exporter sidecar
        - name: exporter
          image: oliver006/redis_exporter:latest
          ports:
            - containerPort: 9121
          env:
            - name: REDIS_ADDR
              value: "localhost:6379"
          resources:
            requests:
              cpu: 50m
              memory: 64Mi

Security Sidecar (Vault Agent)

# vault-agent-sidecar.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-with-vault
spec:
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/role: "myapp"
        vault.hashicorp.com/agent-inject-secret-config: "secret/data/myapp/config"
    spec:
      serviceAccountName: myapp
      containers:
        - name: app
          image: myapp:v1
          volumeMounts:
            - name: secrets
              mountPath: /vault/secrets
              readOnly: true
      
      volumes:
        - name: secrets
          emptyDir:
            medium: Memory

Cloud SQL Proxy Sidecar

# cloudsql-sidecar.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-with-cloudsql
spec:
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        # Main application
        - name: app
          image: myapp:v1
          env:
            - name: DATABASE_HOST
              value: "127.0.0.1"
            - name: DATABASE_PORT
              value: "5432"
        
        # Cloud SQL Proxy sidecar
        - name: cloudsql-proxy
          image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.8.0
          args:
            - "--structured-logs"
            - "--private-ip"
            - "project:region:instance"
          securityContext:
            runAsNonRoot: true
          resources:
            requests:
              cpu: 100m
              memory: 128Mi

Shared Process Namespace

# shared-namespace.yaml
apiVersion: v1
kind: Pod
metadata:
  name: debug-sidecar
spec:
  shareProcessNamespace: true  # Containers can see each other's processes
  containers:
    - name: app
      image: myapp:v1
    
    - name: debug
      image: busybox:1.28
      securityContext:
        capabilities:
          add:
            - SYS_PTRACE
      stdin: true
      tty: true
      command: ['sh']

Native Sidecar Containers (Kubernetes 1.28+)

# native-sidecar.yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-with-native-sidecar
spec:
  initContainers:
    # Native sidecar - runs for pod lifetime
    - name: log-shipper
      image: fluent/fluent-bit:latest
      restartPolicy: Always  # Makes it a sidecar
      volumeMounts:
        - name: logs
          mountPath: /var/log/app
  
  containers:
    - name: app
      image: myapp:v1
      volumeMounts:
        - name: logs
          mountPath: /var/log/app
  
  volumes:
    - name: logs
      emptyDir: {}

Sidecar Resource Management

# resource-aware-sidecar.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-with-sidecars
spec:
  template:
    spec:
      containers:
        - name: app
          image: myapp:v1
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
            limits:
              cpu: 1000m
              memory: 1Gi
        
        - name: sidecar-1
          image: sidecar:v1
          resources:
            requests:
              cpu: 50m
              memory: 64Mi
            limits:
              cpu: 100m
              memory: 128Mi
        
        - name: sidecar-2
          image: sidecar:v2
          resources:
            requests:
              cpu: 50m
              memory: 64Mi
            limits:
              cpu: 100m
              memory: 128Mi
      
      # Total pod resources: 600m CPU, 640Mi memory requests

Summary

Sidecar containers handle cross-cutting concerns without modifying application code. Use them for logging, metrics export, proxy, secrets management, and configuration reload. Share data via volumes, communicate via localhost, and use native sidecars (Kubernetes 1.28+) for better lifecycle management. Keep sidecars lightweight and well-resourced.


📘 Go Further with Kubernetes Recipes

Love this recipe? There’s so much more! This is just one of 100+ hands-on recipes in our comprehensive Kubernetes Recipes book.

Inside the book, you’ll master:

  • ✅ Production-ready deployment strategies
  • ✅ Advanced networking and security patterns
  • ✅ Observability, monitoring, and troubleshooting
  • ✅ Real-world best practices from industry experts

“The practical, recipe-based approach made complex Kubernetes concepts finally click for me.”

👉 Get Your Copy Now — Start building production-grade Kubernetes skills today!

#sidecar #patterns #containers #logging #proxy

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.