GitHub Actions Tutorial — Deployments Exercises

3 minute read

Practice Exercises — Deployments

Test your understanding of AWS deployments, Azure deployments, Kubernetes, Docker images, and deployment protection with these hands-on exercises.


Exercise 1 — S3 Static Site Deployment

Task: Write a workflow that:

  1. Triggers on push to main
  2. Uses OIDC to authenticate with AWS
  3. Builds a React app (npm ci && npm run build)
  4. Syncs the build/ directory to an S3 bucket
  5. Invalidates the CloudFront distribution cache
Show Solution

name: Deploy Static Site

on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci && npm run build

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - name: Sync to S3
        run: aws s3 sync build/ s3://${{ secrets.S3_BUCKET }} --delete

      - name: Invalidate CloudFront
        run: |
          aws cloudfront create-invalidation \
            --distribution-id ${{ secrets.CF_DISTRIBUTION_ID }} \
            --paths "/*"


Exercise 2 — Docker Build and Push to GHCR

Task: Write a workflow that:

  1. Triggers on push to main and on semver tags (v*)
  2. Logs in to GitHub Container Registry
  3. Generates tags: SHA, branch name, and semver version (if tag push)
  4. Builds and pushes a multi-platform image (amd64 + arm64)
  5. Uses GitHub Actions cache for Docker layers
Show Solution

name: Build and Push

on:
  push:
    branches: [main]
    tags: ['v*']

permissions:
  contents: read
  packages: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-qemu-action@v3

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - uses: docker/metadata-action@v5
        id: meta
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=sha
            type=ref,event=branch
            type=semver,pattern={{version}}

      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          platforms: linux/amd64,linux/arm64
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max


Exercise 3 — Kubernetes Helm Deployment

Task: Write a workflow that:

  1. Authenticates to AWS and configures EKS kubeconfig
  2. Runs helm upgrade --install with the commit SHA as the image tag
  3. Waits for the rollout to complete
  4. Prints the pod status after deployment
Show Solution

name: Helm Deploy

on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - name: Configure EKS
        run: aws eks update-kubeconfig --name my-cluster --region us-east-1

      - name: Helm deploy
        run: |
          helm upgrade --install my-app ./charts/my-app \
            --namespace production \
            --set image.tag=${{ github.sha }} \
            --wait --timeout 5m

      - name: Verify
        run: kubectl get pods -n production -l app=my-app


Exercise 4 — Multi-Environment Pipeline

Task: Design a workflow with four stages:

  1. test — run unit tests
  2. deploy-staging — deploy to staging environment (no approvals)
  3. smoke-test — run health check against staging
  4. deploy-production — deploy to production (requires approval, main branch only)

Include the proper needs: dependencies and environment configuration.

Show Solution

name: Deploy Pipeline

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test

  deploy-staging:
    needs: test
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/checkout@v4
      - run: echo "Deploying to staging..."
      # staging deploy commands

  smoke-test:
    needs: deploy-staging
    runs-on: ubuntu-latest
    steps:
      - run: |
          curl -sf ${{ vars.STAGING_URL }}/health || exit 1
          echo "Staging health check passed"

  deploy-production:
    needs: smoke-test
    runs-on: ubuntu-latest
    environment: production     # requires approval + main branch only
    steps:
      - uses: actions/checkout@v4
      - run: echo "Deploying to production..."
      # production deploy commands

Environment configuration (in GitHub Settings):

  • staging — no protection rules, has STAGING_URL variable
  • production — required reviewers: @lead-dev; branch policy: main only; wait timer: 5 min

Exercise 5 — Deployment Protection Audit

Task: You have a production environment. List the protection rules you would configure and explain why:

  1. Required reviewers
  2. Wait timer
  3. Branch restrictions
  4. Deployment branch policy
Show Solution

Recommended production environment configuration:

Protection Rule Setting Why
Required reviewers 2 reviewers from @devops-team Four-eyes principle — no single person can deploy to production
Wait timer 10 minutes Gives time to abort if staging shows issues after approval
Branch restrictions main only Prevents feature branches from deploying to production
Deployment branch policy Selected branches: main Only the default branch should reach production

Additional recommendations:

  • Use environment-specific secrets (production DB credentials separate from staging)
  • Enable audit logs for deployment approvals
  • Set up Slack/Teams notifications for pending approvals
  • Consider adding a smoke test job between staging and production

← Back to: Chapter 13: Deployments

Next Chapter: Chapter 14: Troubleshooting →

Updated: