GitHub Actions Tutorial — Deployments Exercises
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:
- Triggers on push to
main - Uses OIDC to authenticate with AWS
- Builds a React app (
npm ci && npm run build) - Syncs the
build/directory to an S3 bucket - 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:
- Triggers on push to
mainand on semver tags (v*) - Logs in to GitHub Container Registry
- Generates tags: SHA, branch name, and semver version (if tag push)
- Builds and pushes a multi-platform image (amd64 + arm64)
- 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:
- Authenticates to AWS and configures EKS kubeconfig
- Runs
helm upgrade --installwith the commit SHA as the image tag - Waits for the rollout to complete
- 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:
test— run unit testsdeploy-staging— deploy to staging environment (no approvals)smoke-test— run health check against stagingdeploy-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, hasSTAGING_URLvariableproduction— required reviewers: @lead-dev; branch policy:mainonly; 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:
- Required reviewers
- Wait timer
- Branch restrictions
- 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 →