All posts/
DevOpsGitHub ActionsDocker

CI/CD Pipelines with GitHub Actions: Zero to Production

Oct 30, 2025·11 min read

Build production-grade pipelines that lint, test, build Docker images, push to a registry, and deploy to Kubernetes — all from a single YAML workflow file.

Anatomy of a Workflow

A GitHub Actions workflow is a YAML file in `.github/workflows/`. It consists of triggers (`on:`), jobs that run in parallel by default, and steps executed in sequence inside each job.

yaml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm lint
      - run: pnpm test --coverage

Building & Pushing a Docker Image

Use `docker/build-push-action` with GHCR (GitHub Container Registry) for free private image storage. Cache layers between runs with `cache-from` to slash build times.

yaml
  build-push:
    needs: lint-and-test
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v5
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
          cache-from: type=gha
          cache-to:   type=gha,mode=max

Deploying to Kubernetes

yaml
  deploy:
    needs: build-push
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: azure/setup-kubectl@v3
      - run: |
          kubectl set image deployment/api             api=ghcr.io/${{ github.repository }}:${{ github.sha }}
          kubectl rollout status deployment/api
        env:
          KUBECONFIG_DATA: ${{ secrets.KUBECONFIG }}

Tips for Faster Pipelines

  • Cache `node_modules` with `actions/cache` or the built-in `cache:` option of `setup-node`
  • Run lint, unit tests, and type-check in parallel jobs rather than sequentially
  • Use `paths:` filters on triggers to skip workflows when only docs change
  • Keep secrets in GitHub Environments so staging and production use different credentials
A CI pipeline that takes 20 minutes is a pipeline that developers learn to avoid. Keep it under 5.
PreviousRedis Beyond Caching: Pub/Sub, Streams, and Rate LimitingNextWebGL & Three.js: Crafting Immersive Portfolio Backgrounds