> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/tektoncd/pipeline/llms.txt
> Use this file to discover all available pages before exploring further.

# Sidecar Containers

> Run helper containers alongside your Task Steps

Sidecars are containers that run alongside the Steps in your Task, providing supporting services like databases, Docker daemons, or SSH servers. This guide shows you how to use sidecars effectively.

## Overview

Sidecars enable you to:

* Run services that Steps need to communicate with
* Provide test dependencies like databases or message queues
* Run Docker-in-Docker for building container images
* Set up SSH servers or other network services
* Share resources with Steps through volumes

Sidecars start before Steps execute and run throughout the Task execution.

## Basic Sidecar Configuration

Define sidecars in the Task specification:

```yaml theme={null}
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  generateName: sidecar-example-
spec:
  taskSpec:
    steps:
      - name: main
        image: alpine
        script: |
          echo "Main step running"
          # Steps can communicate with sidecar
    sidecars:
      - name: helper
        image: nginx
```

## Docker-in-Docker Sidecar

A common use case is running Docker commands from Steps:

```yaml theme={null}
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  generateName: dind-sidecar-
spec:
  taskSpec:
    steps:
      - name: client
        image: docker
        env:
          # Connect to the sidecar over TCP, with TLS
          - name: DOCKER_HOST
            value: tcp://localhost:2376
          # Verify TLS
          - name: DOCKER_TLS_VERIFY
            value: '1'
          # Use the certs generated by the sidecar daemon
          - name: DOCKER_CERT_PATH
            value: /certs/client
        workingDir: /workspace
        script: |
          #!/usr/bin/env sh
          set -e
          # Run a Docker container
          docker run busybox echo hello

          # Write a Dockerfile and build it
          cat > Dockerfile << EOF
          FROM ubuntu
          RUN apt-get update
          ENTRYPOINT ["echo", "hello"]
          EOF
          docker build -t hello .
          docker images

          # Run the built image
          docker run hello
        volumeMounts:
          - mountPath: /certs/client
            name: dind-certs

    sidecars:
      - name: server
        image: docker:dind
        args:
          - --storage-driver=vfs
          - --userland-proxy=false
          - --debug
        computeResources:
          requests:
            memory: "512Mi"
        securityContext:
          privileged: true
        env:
          # Write generated certs to the path shared with the client
          - name: DOCKER_TLS_CERTDIR
            value: /certs
        volumeMounts:
          - mountPath: /certs/client
            name: dind-certs
        # Wait for the dind daemon to generate the certs
        startupProbe:
          periodSeconds: 1
          failureThreshold: 30
          exec:
            command: ['ls', '/certs/client/ca.pem']
        # Verify Docker daemon is ready to accept commands
        readinessProbe:
          periodSeconds: 2
          exec:
            command: ['docker', 'info']

    volumes:
      - name: dind-certs
        emptyDir: {}
```

<Warning>
  Docker-in-Docker requires privileged mode. Ensure your cluster security policies allow privileged containers.
</Warning>

## Sharing Data with Volumes

Sidecars and Steps can share data through volumes:

```yaml theme={null}
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  generateName: shared-volume-
spec:
  taskSpec:
    volumes:
      - name: messages
        emptyDir: {}
    steps:
      - name: write
        image: alpine
        volumeMounts:
          - name: messages
            mountPath: /messages
        script: |
          echo "Hello from step" > /messages/greeting.txt
      - name: read
        image: alpine
        volumeMounts:
          - name: messages
            mountPath: /messages
        script: |
          cat /messages/greeting.txt
    sidecars:
      - name: processor
        image: alpine
        volumeMounts:
          - name: messages
            mountPath: /messages
        command: ['sh', '-c']
        args:
          - |
            while true; do
              if [ -f /messages/greeting.txt ]; then
                echo "Sidecar saw: $(cat /messages/greeting.txt)"
              fi
              sleep 2
            done
```

## Sidecar Readiness

Use readiness probes to ensure sidecars are ready before Steps start:

```yaml theme={null}
sidecars:
  - name: database
    image: postgres:13
    env:
      - name: POSTGRES_PASSWORD
        value: example
    readinessProbe:
      exec:
        command:
          - pg_isready
          - -U
          - postgres
      periodSeconds: 2
      initialDelaySeconds: 5
```

<Note>
  Steps wait for sidecars with readiness probes to become ready before executing.
</Note>

## Startup Probes

Use startup probes for sidecars that need extra time to initialize:

```yaml theme={null}
sidecars:
  - name: slow-service
    image: my-slow-service
    startupProbe:
      periodSeconds: 1
      failureThreshold: 30  # Allow up to 30 seconds for startup
      exec:
        command: ['cat', '/tmp/ready']
    readinessProbe:
      periodSeconds: 2
      exec:
        command: ['curl', 'localhost:8080/health']
```

## SSH Server Sidecar

Run an SSH server for Git operations:

```yaml theme={null}
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  name: authenticating-git-commands
spec:
  serviceAccountName: ssh-key-service-account
  taskSpec:
    volumes:
      - name: messages
        emptyDir: {}
    sidecars:
      - name: server
        image: alpine/git:v2.26.2
        securityContext:
          runAsUser: 0
        volumeMounts:
          - name: messages
            mountPath: /messages
        script: |
          #!/usr/bin/env ash

          # Generate a private host key
          ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
          chmod 0600 /etc/ssh/ssh_host_rsa_key*
          HOST_PUBLIC_KEY=$(cat /etc/ssh/ssh_host_rsa_key.pub | awk '{ print $2 }')
          echo "localhost ssh-rsa $HOST_PUBLIC_KEY" > /messages/known_hosts

          # Wait for Steps to supply the server a public key
          while [ ! -f /messages/authorized_keys ] ; do
            sleep 1
          done

          # Configure SSH to allow login
          mkdir /root/.ssh
          cp /messages/authorized_keys /root/.ssh/
          sed -i s/root:!/'root:*'/g /etc/shadow

          # Create a git repo
          cd /root/
          mkdir repo
          cd repo
          git init . --bare

          # Start the sshd server
          /usr/sbin/sshd -E /var/log/sshd
          touch /messages/sshd-ready
          tail -f /var/log/sshd
    steps:
      - name: setup
        image: alpine/git:v2.26.2
        volumeMounts:
          - name: messages
            mountPath: /messages
        script: |
          # Generate authorized_keys from credentials
          ssh-keygen -y -f $(credentials.path)/.ssh/id_* > /messages/authorized_keys

          # Wait for sshd to start
          while [ ! -f /messages/sshd-ready ] ; do
            sleep 1
          done
      - name: git-clone-and-push
        image: alpine/git:v2.26.2
        volumeMounts:
          - name: messages
            mountPath: /messages
        script: |
          ln -s $(credentials.path)/.ssh /root/.ssh
          cp /messages/known_hosts /root/.ssh/
          git clone root@localhost:/root/repo ./repo
          cd repo
          echo "Hello, world!" > README
          git add README
          git commit -m "Test commit"
          git push origin master
```

## Workspaces in Sidecars

Sidecars can access Task workspaces:

```yaml theme={null}
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: sidecar-workspace-example
spec:
  workspaces:
    - name: source
  sidecars:
    - name: file-server
      image: python:3-alpine
      workingDir: $(workspaces.source.path)
      command: ['python', '-m', 'http.server', '8000']
  steps:
    - name: download
      image: alpine
      script: |
        echo "File server available at localhost:8000"
        # Step can access files via HTTP from sidecar
```

## Variable Substitution in Sidecars

Sidecars support variable substitution:

```yaml theme={null}
sidecars:
  - name: database
    image: $(params.database-image)
    env:
      - name: DB_NAME
        value: $(params.database-name)
      - name: WORKSPACE_PATH
        value: $(workspaces.data.path)
```

Supported fields:

* `spec.sidecars[].name`
* `spec.sidecars[].image`
* `spec.sidecars[].imagePullPolicy`
* `spec.sidecars[].env.value`
* `spec.sidecars[].command`
* `spec.sidecars[].args`
* `spec.sidecars[].script`
* `spec.sidecars[].volumeMounts`

## Sidecar Lifecycle

### Startup Order

1. Sidecars start first
2. Sidecars with readiness probes must become ready
3. Steps execute in order
4. Sidecars continue running during Step execution

### Shutdown

Sidecars automatically stop when:

* All Steps complete successfully
* A Step fails and the Task stops
* The TaskRun times out

<Note>
  Tekton sends a SIGTERM to sidecars to request graceful shutdown. If sidecars don't exit within the grace period, they receive SIGKILL.
</Note>

## Resource Management

Specify resource requests and limits for sidecars:

```yaml theme={null}
sidecars:
  - name: memory-intensive
    image: my-service
    computeResources:
      requests:
        memory: "512Mi"
        cpu: "500m"
      limits:
        memory: "1Gi"
        cpu: "1000m"
```

## Best Practices

### Use Readiness Probes

<Tip>
  Always configure readiness probes for sidecars that Steps depend on. This prevents race conditions where Steps try to connect before the sidecar is ready.
</Tip>

```yaml theme={null}
sidecars:
  - name: api-server
    image: my-api
    readinessProbe:
      httpGet:
        path: /health
        port: 8080
      periodSeconds: 2
```

### Minimize Sidecar Size

```yaml theme={null}
# Good: Lightweight sidecar
sidecars:
  - name: cache
    image: redis:alpine

# Avoid: Unnecessarily large images
sidecars:
  - name: cache
    image: ubuntu-with-redis
```

### Share Data via Volumes

Use volumes instead of network communication when possible:

```yaml theme={null}
volumes:
  - name: shared-data
    emptyDir: {}
steps:
  - name: producer
    volumeMounts:
      - name: shared-data
        mountPath: /data
sidecars:
  - name: consumer
    volumeMounts:
      - name: shared-data
        mountPath: /data
```

### Set Security Contexts

```yaml theme={null}
sidecars:
  - name: secure-service
    image: my-service
    securityContext:
      runAsNonRoot: true
      runAsUser: 1000
      allowPrivilegeEscalation: false
      capabilities:
        drop:
          - ALL
```

## Common Patterns

### Database for Testing

```yaml theme={null}
sidecars:
  - name: postgres
    image: postgres:13
    env:
      - name: POSTGRES_PASSWORD
        value: test
      - name: POSTGRES_DB
        value: testdb
    readinessProbe:
      exec:
        command: ['pg_isready', '-U', 'postgres']
      periodSeconds: 2
```

### Service Mesh Proxy

```yaml theme={null}
sidecars:
  - name: envoy
    image: envoyproxy/envoy:v1.20.0
    args:
      - -c
      - /config/envoy.yaml
    volumeMounts:
      - name: envoy-config
        mountPath: /config
```

### Message Queue

```yaml theme={null}
sidecars:
  - name: rabbitmq
    image: rabbitmq:3-alpine
    env:
      - name: RABBITMQ_DEFAULT_USER
        value: guest
      - name: RABBITMQ_DEFAULT_PASS
        value: guest
    readinessProbe:
      exec:
        command: ['rabbitmq-diagnostics', 'ping']
      periodSeconds: 5
```

<Accordion title="Why isn't my sidecar starting?">
  Check these common issues:

  1. **Image pull errors**: Verify the image exists and is accessible
  2. **Resource constraints**: Ensure the cluster has sufficient resources
  3. **Security policies**: Check if security contexts or policies block the sidecar
  4. **Volume mount conflicts**: Verify volume mounts don't conflict with Step mounts

  View sidecar logs:

  ```bash theme={null}
  kubectl logs <pod-name> -c <sidecar-name>
  ```
</Accordion>

<Accordion title="How do Steps communicate with sidecars?">
  Steps communicate with sidecars via:

  1. **Localhost networking**: Sidecars listen on `localhost` or `127.0.0.1`
  2. **Shared volumes**: Exchange files through mounted volumes
  3. **Environment variables**: Pass configuration via env vars

  Example:

  ```yaml theme={null}
  steps:
    - name: client
      script: |
        # Connect to sidecar on localhost
        curl http://localhost:8080/api
  ```
</Accordion>
