> ## 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.

# Build Docker Image

> Using Docker-in-Docker to build container images

This example demonstrates how to build a Docker image within a Tekton Task using a Docker-in-Docker (DinD) sidecar.

## Example

```yaml theme={null}
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  generateName: dind-sidecar-
spec:
  taskSpec:
    steps:
    - image: mirror.gcr.io/library/docker@sha256:0752ca4e936da012c173c119217c0f9599b3b191c1557e53206d5d06d2627580
      name: client
      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 `docker build` it.
          cat > Dockerfile << EOF
          FROM ubuntu
          RUN apt-get update
          ENTRYPOINT ["echo", "hello"]
          EOF
          docker build -t hello .
          docker images

          # ...then run it!
          docker run hello
      volumeMounts:
      - mountPath: /certs/client
        name: dind-certs

    sidecars:
    - image: mirror.gcr.io/library/docker@sha256:0752ca4e936da012c173c119217c0f9599b3b191c1557e53206d5d06d2627580
      name: server
      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 it will share with the
      # client. StartupProbe handles slow Docker daemon initialization.
      startupProbe:
        periodSeconds: 1
        failureThreshold: 30  # Allow up to 30 seconds for Docker daemon to start
        exec:
          command: ['ls', '/certs/client/ca.pem']
      # ReadinessProbe verifies Docker daemon is actually ready to accept commands.
      # Note: With k8s native sidecar support, startupProbe is honored but
      # readinessProbe may not be.
      readinessProbe:
        periodSeconds: 2
        exec:
          command: ['docker', 'info']

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

## How It Works

<Steps>
  <Step title="Sidecar Starts Docker Daemon">
    The sidecar container runs a Docker daemon with TLS enabled. It generates certificates and writes them to a shared volume at `/certs/client`.
  </Step>

  <Step title="Startup Probes Wait for Daemon">
    The `startupProbe` waits for the certificates to be generated (up to 30 seconds). The `readinessProbe` verifies the daemon is ready to accept commands.
  </Step>

  <Step title="Client Connects to Daemon">
    The client step configures the Docker CLI to connect to the sidecar daemon using environment variables:

    * `DOCKER_HOST=tcp://localhost:2376` - Connect via TCP
    * `DOCKER_TLS_VERIFY=1` - Enable TLS verification
    * `DOCKER_CERT_PATH=/certs/client` - Use shared certificates
  </Step>

  <Step title="Build and Run Docker Image">
    The client step:

    1. Runs a simple busybox container to verify connectivity
    2. Creates a Dockerfile
    3. Builds an image tagged as `hello`
    4. Runs the newly built image
  </Step>
</Steps>

## Security Considerations

<Warning>
  The Docker daemon sidecar requires `privileged: true` to function. This grants significant permissions to the container. Only use this in trusted environments.
</Warning>

## Docker Daemon Configuration

The daemon is configured with specific arguments:

* `--storage-driver=vfs` - Uses VFS storage driver (slower but more compatible)
* `--userland-proxy=false` - Disables userland proxy
* `--debug` - Enables debug logging

## TLS Certificate Sharing

The pattern for sharing TLS certificates:

1. Sidecar sets `DOCKER_TLS_CERTDIR=/certs` to generate certs
2. Both containers mount the same `dind-certs` volume
3. Client reads certificates from `/certs/client`
4. Docker CLI automatically uses these certificates

## Expected Output

```
hello

Sending build context to Docker daemon...
Step 1/3 : FROM ubuntu
Step 2/3 : RUN apt-get update
Step 3/3 : ENTRYPOINT ["echo", "hello"]
Successfully built...
Successfully tagged hello:latest

REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
hello        latest    abc123def456   1 second ago    77.8MB

hello
```

## Alternative Approaches

For production use, consider:

* **Kaniko**: Builds images without requiring privileged mode
* **Buildah**: Daemonless container builds
* **BuildKit**: Modern Docker build backend with better caching

These alternatives are more secure and work better in restricted environments.

## Key Concepts

* **Sidecars**: Containers that run alongside task steps to provide services
* **Docker-in-Docker (DinD)**: Running Docker daemon inside a container
* **Startup Probes**: Wait for slow-starting containers to be ready
* **Shared Volumes**: Pass data between steps and sidecars
* **TLS Security**: Secure communication between Docker client and daemon
* **Privileged Containers**: Required for DinD but should be used carefully

## Next Steps

* See [git clone and build](/examples/real-world/git-clone-build) for a complete CI workflow
* Learn about [multi-stage pipelines](/examples/real-world/multi-stage-pipeline)
