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.
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=maxTesting 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.