Building CI/CD Pipelines with GitHub Actions
A complete guide to building production-grade deployment pipelines with automated testing, security scanning, and multi-stage deployments.
Building CI/CD Pipelines with GitHub Actions
GitHub Actions has become my go-to CI/CD platform for most projects. It's deeply integrated with GitHub, has an extensive marketplace of actions, and the YAML-based workflow syntax is intuitive once you understand the core concepts.
A Production-Grade Workflow
Here's a workflow structure I use for deploying containerized applications to AKS:
name: Deploy to Production
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
REGISTRY: myregistry.azurecr.io
IMAGE_NAME: web-api
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm test -- --coverage
- uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
build-and-push:
needs: [test, security-scan]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- run: az acr login --name myregistry
- name: Build and push
run: |
docker build -t $REGISTRY/$IMAGE_NAME:${{ github.sha }} .
docker push $REGISTRY/$IMAGE_NAME:${{ github.sha }}
deploy:
needs: build-and-push
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- uses: azure/aks-set-context@v4
with:
resource-group: rg-prod
cluster-name: aks-prod
- run: |
kubectl set image deployment/web-api \
api=$REGISTRY/$IMAGE_NAME:${{ github.sha }}
kubectl rollout status deployment/web-api --timeout=300s
Key Design Decisions
Parallel jobs for speed: The test and security-scan jobs run in parallel since they don't depend on each other. The build-and-push job waits for both to pass before proceeding.
Environment protection rules: The deploy job targets the production environment, which can be configured in GitHub with required reviewers, wait timers, and branch restrictions.
Image tagging with SHA: Using the Git SHA as the image tag creates an immutable, traceable link between the deployed container and the exact code commit.
Secrets Management
Never hardcode credentials. Use GitHub's encrypted secrets and, for Azure, prefer OIDC-based authentication over service principal secrets:
permissions:
id-token: write
contents: read
steps:
- uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
OIDC eliminates the need to rotate secrets and reduces the blast radius of a compromised workflow.
Reusable Workflows
For organizations with multiple repositories, extract common patterns into reusable workflows:
# .github/workflows/reusable-deploy.yml
on:
workflow_call:
inputs:
environment:
required: true
type: string
image-tag:
required: true
type: string
secrets:
AZURE_CREDENTIALS:
required: true
This keeps your CI/CD DRY and ensures consistent deployment practices across all projects.
Monitoring Deployments
After deploy, I always add a notification step — whether it's a Slack message, a Teams webhook, or an annotation in Grafana. Knowing exactly when a deployment happened is invaluable for correlating metrics changes with code changes.
A well-designed CI/CD pipeline is the backbone of reliable software delivery. Invest time in getting it right, and it will pay dividends every single day.
Need help with your infrastructure?
Let's discuss your project and find the best solution together.
Get in touchRelated articles
Progressive Delivery in DevOps: Canary, Blue-Green, and Feature Flags
How to reduce deployment risk with progressive delivery patterns and measurable rollback criteria.
Cloud Architecture Through the Shared Responsibility Model
How to design cloud systems with clear provider/customer boundaries for security, reliability, and operations.