CI/CD Fundamentals

Lesson 4 of 7

Build Artifacts and Docker Images in CI

Once tests pass, most pipelines produce something deployable, a compiled binary, a bundled frontend, or, very commonly today, a Docker image. This lesson builds and pushes one from CI.

Building and pushing an image

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Log in to registry
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_TOKEN }}
      - name: Build and push
        run: |
          docker build -t myregistry/web:${{ github.sha }} .
          docker push myregistry/web:${{ github.sha }}

secrets.REGISTRY_USER/REGISTRY_TOKEN pull encrypted repository secrets into the workflow at runtime, never hardcode credentials directly in the YAML (covered in more depth in the secrets-management lesson).

Tagging strategy

Tagging every image build matters more than it looks: it's how you know exactly what's running, and how you roll back.

Tag styleExampleTradeoff
Commit SHAweb:a1b2c3dAlways unique, traces directly to exact code, not human-friendly
Semantic versionweb:1.4.2Human-friendly, requires a versioning/release process
latestweb:latestConvenient, but ambiguous, "latest" changes meaning over time, avoid for production deploys

A common, robust approach: always tag with the commit SHA (guaranteed unique, always traceable), and additionally tag stable releases with a semantic version for human readability.

Uploading build artifacts

Not every pipeline needs a Docker image, sometimes you just need to pass a build output (a compiled bundle, a test report) from one job to another:

- uses: actions/upload-artifact@v4
  with:
    name: dist
    path: dist/

# in a later job:
- uses: actions/download-artifact@v4
  with:
    name: dist

NOTE

Artifacts uploaded with upload-artifact are how you pass files between jobs in the same workflow run (each job gets its own fresh runner with no shared filesystem), it's not for long-term storage, that's what a registry or object storage (like S3) is for.

📝 Build Artifacts & Images Quiz

Passing score: 70%
  1. 1.Why should you avoid deploying with only the latest tag in production?

  2. 2.Tagging a Docker image with the commit ____ guarantees a unique tag that always traces back to the exact code that built it.

  3. 3.Repository secrets like registry credentials should be hardcoded directly into the workflow YAML for simplicity.

  4. 4.What is actions/upload-artifact used for?

  5. 5.Each job in a workflow run gets its own fresh runner with no filesystem shared with other jobs by default.

  6. 6.What's a common, robust Docker tagging approach?