← Back to list

Building Production-Ready Docker Images in CI: Multi-Stage Builds, Buildx, and Automated Tagging

For many teams, containerization starts with a simple command:

SwayamOps · 2026-06-08 01:00 · 0 claps · 4.7 min read
#docker #devops #cicd #cloud-native #platform-engineering
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud 🥊 · Combat Sports

Build smarter Docker images: smaller, faster, traceable, and ready for every platform.

Build smarter Docker images: smaller, faster, traceable, and ready for every platform.

Building Production-Ready Docker Images in CI: Multi-Stage Builds, Buildx, and Automated Tagging

For many teams, containerization starts with a simple command:

docker build -t my-app .

The image builds successfully, gets pushed to a registry, and eventually reaches production.

Job done.

Or is it?

As applications grow and deployment pipelines mature, teams often encounter new challenges:

  • Container images become unnecessarily large
  • Tags become difficult to track
  • Multiple CPU architectures need support
  • Build times increase
  • Debugging deployments becomes harder

The reality is that building a Docker image is easy.

Building a production-ready Docker image pipeline is a different challenge altogether.

In this article, we’ll explore how to use multi-stage Docker builds, Docker Buildx, and automated metadata generation to create smaller, traceable, and deployment-friendly container images in CI.

Why Image Build Strategy Matters

Consider a common Dockerfile:

FROM node:20
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
CMD ["npm", "start"]

This works.

But it often produces images that contain:

  • Build dependencies
  • Source files
  • Package managers
  • Temporary artifacts

Everything used during the build ends up inside the final image.

The result?

Large Image
     ↓
Slower Pulls
     ↓
Longer Deployments
     ↓
Higher Storage Costs

A better strategy is to separate build-time requirements from runtime requirements.

Multi-Stage Builds: Build Once, Ship Less

Multi-stage builds allow you to use multiple Docker images within a single Dockerfile.

A typical pattern looks like:

Build Stage
      ↓
Compile Application
      ↓
Copy Artifacts
      ↓
Runtime Stage

Only the final runtime artifacts are included in the production image.

A Practical Example

Instead of:

FROM node:20
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
CMD ["npm", "start"]

Use:

FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

The result:

Builder Image
      ↓
Contains Tooling
      ↓      
Production Image
      ↓
Contains Only Static Assets

This often reduces image size dramatically.

Real-World Impact

A frontend application might produce:

ApproachImage SizeSingle Stage900 MBMulti-Stage90 MB

That’s a 10x reduction.

Benefits include:

  • Faster deployments
  • Lower bandwidth usage
  • Smaller attack surface
  • Reduced storage costs

These improvements become significant at scale.

Why Traditional Docker Builds Fall Short

Historically, Docker builds targeted a single platform:

docker build .

This works when all infrastructure uses the same architecture.

But today’s environments often include:

  • AMD64 cloud servers
  • ARM-based instances
  • Apple Silicon developer machines
  • Edge devices

Building separate images for each platform quickly becomes difficult to manage.

Enter Docker Buildx

Buildx extends Docker’s build capabilities and enables:

  • Multi-platform builds
  • Advanced caching
  • Faster builds
  • Improved reproducibility

Think of it as:

docker build
        +
Modern Build Features
        =
docker buildx

Building Multi-Platform Images

With Buildx:

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t my-app:1.0.0 \
  --push .

A single command produces:

linux/amd64
linux/arm64

under the same image tag.

Consumers pull the correct architecture automatically.

Why Multi-Platform Images Matter

Imagine a development team using:

MacBook M3
      ↓
ARM64

while production runs:

AWS EC2
      ↓
AMD64

Without multi-platform builds:

Works Locally
     ↓
Fails in Production

Buildx helps eliminate architecture-related surprises.

The Problem with Poor Tagging

One of the most common container management issues is:

latest

Ask yourself:

What exactly is running in production?

If the answer is:

my-app:latest

you don’t actually know.

The tag may point to different images over time.

Better Tagging Strategies

A more reliable approach combines:

  • Semantic versions
  • Git commit SHAs
  • Branch information

Example:

my-app:v2.3.1

and:

my-app:8f4e2d7

and:

my-app:main

Multiple tags provide flexibility while maintaining traceability.

One build, multiple architectures, complete traceability from commit to production.

One build, multiple architectures, complete traceability from commit to production.

Real-World Tagging Example

Suppose a release is built from:

Version: 2.3.1
Commit:
8f4e2d7

Generated tags:

my-app:v2.3.1
my-app:2.3
my-app:8f4e2d7
my-app:latest

Now teams can:

  • Deploy specific versions
  • Roll back quickly
  • Trace deployments to source code

Automating Metadata Generation

Managing tags manually becomes tedious.

GitHub Actions can generate image metadata automatically.

A popular approach uses:

- name: Extract Docker Metadata
  uses: docker/metadata-action@v5
  with:
    images: ghcr.io/my-org/my-app

The action automatically creates tags based on:

  • Git tags
  • Branches
  • Pull requests
  • Commit SHAs

This removes much of the manual work.

Building Images in GitHub Actions

A production-ready workflow often looks like:

name: Build Container
on:
  push:
    branches:
      - main
jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set Up Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Docker Metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/my-org/my-app
      - name: Build and Push
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          platforms: linux/amd64,linux/arm64
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

This workflow automatically:

  • Builds images
  • Generates metadata
  • Creates tags
  • Supports multiple architectures
  • Pushes to a registry

Adding Useful OCI Labels

Tags identify images.

Labels provide additional context.

Example:

labels:
  org.opencontainers.image.source=https://github.com/org/repo
  org.opencontainers.image.version=2.3.1
  org.opencontainers.image.revision=8f4e2d7

Now image metadata includes:

Repository
Version
Commit SHA
Build Source

This becomes valuable during troubleshooting and audits.

Integrating with Artifact Traceability

A mature container pipeline often produces:

Docker Image
      +
Version Metadata
      +
SBOM
      +
Vulnerability Scan Results

Everything becomes traceable back to:

Git Commit
      ↓
CI Build
      ↓
Production Deployment

This aligns closely with modern software supply chain security practices.

Common Mistakes to Avoid

Building Huge Images

If build tools end up inside production images, you’re likely missing multi-stage builds.

Using Only latest

latest is convenient.

It is not traceable.

Always include immutable version tags.

Ignoring Multi-Platform Support

Modern environments increasingly mix AMD64 and ARM64 workloads.

Buildx makes supporting both architectures straightforward.

Manually Managing Tags

Automated metadata generation reduces human error and improves consistency.

Missing Build Metadata

Without labels and version information:

Which source code created this image?

becomes difficult to answer.

A Production-Ready Container Pipeline

A mature container workflow often looks like:

Source Code
      ↓
Quality Checks
      ↓
Dockerfile Linting
      ↓
Multi-Stage Build
      ↓
Buildx Multi-Platform Build
      ↓
Metadata Generation
      ↓
SBOM Creation
      ↓
Container Scanning
      ↓
Registry Push

Each step contributes to reliability, traceability, and security.

Final Thoughts

Building Docker images is no longer just about packaging an application.

Modern CI pipelines must produce images that are:

  • Small
  • Reproducible
  • Multi-platform
  • Traceable
  • Easy to deploy and roll back

By combining multi-stage builds, Docker Buildx, automated metadata generation, and intelligent tagging strategies, teams can create container artifacts that scale with both engineering and operational requirements.

The best container pipelines don’t just build images — they create trustworthy deployment artifacts that can be traced all the way back to the source code that produced them.

How is your team currently building and tagging Docker images? Are you using Buildx, automated metadata generation, multi-platform builds, or custom tagging strategies? Share your approach and lessons learned in the comments — I’d love to hear how others are evolving their container delivery pipelines.


메타데이터
post_id
7e3dd613ba14
slug
building-production-ready-docker-images-in-ci-multi-stage-builds-buildx-and-automated-tagging-7e3dd613ba14
url
https://medium.com/@sharathkumarlokesh/building-production-ready-docker-images-in-ci-multi-stage-builds-buildx-and-automated-tagging-7e3dd613ba14
canonical_url
https://medium.com/@sharathkumarlokesh/building-production-ready-docker-images-in-ci-multi-stage-builds-buildx-and-automated-tagging-7e3dd613ba14
author_url
https://medium.com/@sharathkumarlokesh
status
ok
fetched_at
2026-06-10 10:12:36