Continuous Deployment Example

Build and deploy automatically when a version tag is pushed.

Continuous Deployment (CD) takes CI one step further: after tests pass, it ships the code automatically. This workflow builds and deploys whenever a version tag like v1.2.0 is pushed.

Key ideas

  • Trigger only on tags with on.push.tags.
  • Store deploy credentials as secrets.
  • Use an environment to require approvals or track deployments.

Example

Example · yaml
name: Deploy
on:
  push:
    tags: ["v*"]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npm run build
      - name: Deploy to server
        env:
          DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
        run: ./scripts/deploy.sh

When to use it

  • A team deploys a Docker image to AWS ECS automatically when a PR merges into main, eliminating manual deployment steps.
  • A developer uses GitHub Environments with required reviewers so every production deploy requires a human approval in the Actions UI.
  • A Kubernetes team uses a CD workflow to update an image tag in a Helm values file and push it, triggering ArgoCD to sync the cluster.

More examples

Build and push Docker image to GHCR

Logs in to GitHub Container Registry using the built-in GITHUB_TOKEN and pushes a freshly built image on every merge to main.

Example · yaml
name: CD
on:
  push:
    branches: [main]
jobs:
  build-push:
    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 }}:latest

Deploy to environment with approval gate

Referencing a GitHub Environment named 'production' pauses the job until a required reviewer approves in the Actions UI.

Example · yaml
jobs:
  deploy-prod:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/deploy.sh
        env:
          DEPLOY_KEY: ${{ secrets.PROD_DEPLOY_KEY }}

SSH deploy to a VPS on merge

Uses a community SSH action to connect to a VPS, pull the latest code, and restart the process manager — a simple zero-downtime deploy.

Example · yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.VPS_HOST }}
          username: deploy
          key: ${{ secrets.VPS_SSH_KEY }}
          script: |
            cd /app
            git pull origin main
            npm ci --production
            pm2 restart app

Discussion

  • Be the first to comment on this lesson.