Chapter 17 • Production, Optimization & Security

Docker in CI/CD Pipelines

In modern continuous integration and delivery (CI/CD), every Git commit triggers an automated pipeline that tests, compiles, security-scans, and publishes container images. In this chapter, learn how to configure enterprise GitHub Actions workflows with BuildKit distributed caching and automated vulnerability quality gates.

1. The Automated Container Delivery Lifecycle

An enterprise container delivery pipeline enforces strict quality gates before an image ever enters a production registry:

1. Git Push
→
2. Buildx & Cache
→
3. Trivy Scan
→
4. Publish GHCR/ECR

2. Production GitHub Actions Workflow (.github/workflows/deploy.yml)

This hardened workflow leverages GitHub Actions Cache (type=gha) to reuse layer caches across runner instances (dropping build times from 6 minutes to under 30 seconds), automatically extracts SemVer tags, and breaks the build if CRITICAL security vulnerabilities are detected:

name: Build, Scan & Publish Production Container

on:
  push:
    branches: ["main"]
    tags: ["v*.*.*"]
  pull_request:
    branches: ["main"]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build-and-deliver:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      security-events: write

    steps:
      # Step 1: Checkout Git source code
      - name: Checkout Repository
        uses: actions/checkout@v4

      # Step 2: Set up QEMU for multi-architecture emulation (ARM64 & AMD64)
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      # Step 3: Set up Docker Buildx with BuildKit
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      # Step 4: Authenticate to GitHub Container Registry (GHCR)
      - name: Log in to Registry
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      # Step 5: Extract dynamic metadata, Git commit SHAs, and SemVer tags
      - name: Extract Docker Metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha,format=short
            type=raw,value=latest,enable={{is_default_branch}}

      # Step 6: Build image locally for security scanning
      - name: Build Local Image for CVE Gate
        uses: docker/build-push-action@v5
        with:
          context: .
          load: true
          tags: local-scan-target:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

      # Step 7: Security Quality Gate (Fail pipeline on CRITICAL CVEs!)
      - name: Run Trivy Vulnerability Scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: local-scan-target:latest
          format: 'table'
          exit-code: '1'
          ignore-unfixed: true
          severity: 'CRITICAL'

      # Step 8: Build and push multi-architecture image to production registry
      - name: Build and Push Multi-Platform Image
        if: github.event_name != 'pull_request'
        uses: docker/build-push-action@v5
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

3. Ephemeral Integration Testing Services

Never mock databases when running end-to-end integration tests. GitHub Actions supports nativeDocker Service Containers to spin up real, disposable PostgreSQL or Redis instances for testing:

# Inside your test job definition:
services:
  postgres:
    image: postgres:16-alpine
    env:
      POSTGRES_USER: test_user
      POSTGRES_PASSWORD: test_password
      POSTGRES_DB: integration_test
    ports:
      - 5432:5432
    options: >-
      --health-cmd pg_isready
      --health-interval 5s
      --health-timeout 2s
      --health-retries 5

Next Up: Production Deployment

In Chapter 18, discover how to deploy production containers to cloud VPS instances, configure zero-downtime rolling updates, and log drivers.

Chapter 18: Production Deployment →

Explore Related Tools

Hand-picked utilities and calculators related to this tool.

Related Tools