Skip to content
6 min read·Lesson 10 of 10

Containers in Production: Security, CI/CD, and Beyond

Apply production practices: image scanning, signing, non-root users, CI/CD pipelines, and the path from Docker to managed container services and Kubernetes.

You can run containers on a laptop with docker run. You cannot run a fleet of customer-facing containers that way. This final lesson surveys the practices and tools that take containers from your machine to production.

Image Security

Every line in your Dockerfile is part of your supply chain. Treat it that way.

  1. Pin base images. FROM node:20.11-alpine3.19, not FROM node:latest. Better still, pin by digest.
  2. Run as non-root.
    RUN useradd -r -u 1000 -g app app
    USER app
  3. Drop capabilities. docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp — the container loses every Linux capability except the one it actually needs.
  4. Read-only root filesystem. docker run --read-only --tmpfs /tmp myapp — even if the app is compromised, an attacker can't write a webshell.
  5. Don't run privileged. --privileged hands the keys to the host. Avoid it.
  6. Scan, scan, scan. Every CI build should run a vulnerability scan and fail on critical CVEs.
  7. Sign your images. Use cosign (part of Sigstore) so consumers can verify the image is yours and unmodified.

Building Images in CI

Move all production builds into CI — never push images built on a developer laptop to production. A typical GitHub Actions workflow:

name: docker
on:
  push:
    branches: [main]
    tags: ['v*']

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/metadata-action@v5
        id: meta
        with:
          images: ghcr.io/${{ github.repository }}
      - uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Equivalent pipelines exist for GitLab CI, Azure Pipelines, AWS CodeBuild, Google Cloud Build, and CircleCI.

Where Containers Actually Run

You rarely run containers on bare docker run in production. Instead:

ServiceCloudModel
ECS (Fargate)AWSRun containers without managing servers
EKSAWSManaged Kubernetes
App RunnerAWSContainer-to-URL with autoscaling
Cloud RunGoogle CloudServerless containers, scale to zero
GKEGoogle CloudManaged Kubernetes
Azure Container AppsAzureServerless containers with KEDA autoscaling
Azure Container InstancesAzureSingle containers on demand
AKSAzureManaged Kubernetes
Fly.io / Railway / RenderIndependentContainer-first PaaS

Observability

You can't manage what you can't see. In production, every container should:

  • Log to stdout/stderr in structured JSON — log routers (Fluent Bit, Vector) ship them to Loki, CloudWatch, or Datadog.
  • Expose /healthz and /readyz endpoints so the orchestrator knows when to send traffic.
  • Emit metrics on a Prometheus-compatible endpoint or via OpenTelemetry.
  • Propagate trace headers so distributed traces are stitched together across services.

The Path Forward

You now know enough to:

  • Containerise any application you build
  • Develop locally with Compose
  • Ship images to a registry with a CI pipeline
  • Deploy to a managed container service

From here, the major directions are:

  1. Kubernetes — when a single host or simple managed service stops being enough. See our Kubernetes Basics course.
  2. Service mesh (Istio, Linkerd) — for advanced traffic management, mTLS, and observability across hundreds of services.
  3. GitOps (Argo CD, Flux) — declarative continuous delivery for Kubernetes from Git.
  4. Supply chain security (SLSA, in-toto, SBOMs) — provenance and integrity for everything you ship.

Whatever you build next, the container is the universal unit. The skills you've practised here transfer directly.

Key Takeaways

  • Run as non-root, drop Linux capabilities, mount filesystems read-only when possible.
  • Scan images for vulnerabilities (Trivy, Docker Scout, Snyk) and sign them (cosign / Sigstore).
  • Build images in CI with GitHub Actions, GitLab CI, or cloud-native build services.
  • Managed container services (ECS Fargate, Cloud Run, Azure Container Apps) run containers without managing servers.
  • Kubernetes is the dominant orchestrator at scale — your Docker skills transfer directly.
🎉

Course Complete!

You've finished Docker and Containers Basics. Now put your knowledge to the test with real exam-style practice questions.