Skip to content
Latchkey

CI/CD for a Microservice with Docker and GitHub Actions

A Dockerized microservice tests against its dependencies, then builds and pushes a versioned image with layer caching.

This recipe builds a GitHub Actions pipeline for a containerized microservice. It tests against Postgres, builds a multi-stage image with Buildx layer caching, and pushes to a registry on main.

What the pipeline does

  • Test against Postgres
  • Set up Buildx
  • Build a multi-stage image with cache
  • Log in to the registry
  • Push the tagged image on main

The workflow

docker/build-push-action with GitHub Actions cache (type=gha) reuses layers across runs.

.github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: svc_test
        ports: ["5432:5432"]
        options: >-
          --health-cmd "pg_isready -U postgres"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    env:
      DATABASE_URL: postgres://postgres:postgres@localhost:5432/svc_test
    steps:
      - uses: actions/checkout@v4
      - run: docker compose -f docker-compose.test.yml run --rm test
  build-push:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          registry: ${{ secrets.REGISTRY }}
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_TOKEN }}
      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ${{ secrets.REGISTRY }}/svc:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Testing against dependencies

Tests need the same backing services the microservice uses. Either declare them as service: containers (Postgres at localhost:5432 here) or stand them up with docker compose and run the test container against them. Compose keeps the test topology identical to local development. Tag images with github.sha so every deploy is traceable to a commit.

Deploying

After the image is pushed, trigger a rollout: update a Kubernetes deployment, an ECS service, or a docker compose stack on a host. Reference the github.sha tag so the rollout is immutable. Layer caching plus managed runners that auto-retry transient registry pushes keep builds fast and green, at about 69% less than GitHub-hosted runners.

Key takeaways

  • Use type=gha Buildx cache to reuse layers across CI runs.
  • Tag images with github.sha for traceable, immutable deploys.
  • docker compose keeps the CI test topology identical to local dev.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →