Understanding CI/CD
GitHub Actions Workflow
Basic Workflow Setup
Yaml
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run linting
run: npm run lint
Docker Integration
Building and Pushing Docker Images
Yaml
# .github/workflows/docker.yml
name: Docker Build and Push
on:
push:
branches: [main]
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: |
myapp:latest
myapp:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
Environment-Specific Deployments
Staging Deployment
Yaml
# .github/workflows/deploy-staging.yml
name: Deploy to Staging
on:
push:
branches: [develop]
jobs:
deploy-staging:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to Staging
uses: appleboy/ssh-action@v0.1.5
with:
host: ${{ secrets.STAGING_HOST }}
username: ${{ secrets.STAGING_USER }}
key: ${{ secrets.STAGING_SSH_KEY }}
script: |
cd /var/www/staging
git pull origin develop
npm ci
npm run build
pm2 restart staging-app
Production Deployment
Yaml
# .github/workflows/deploy-production.yml
name: Deploy to Production
on:
push:
tags: ['v*']
jobs:
deploy-production:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to Production
uses: appleboy/ssh-action@v0.1.5
with:
host: ${{ secrets.PRODUCTION_HOST }}
username: ${{ secrets.PRODUCTION_USER }}
key: ${{ secrets.PRODUCTION_SSH_KEY }}
script: |
cd /var/www/production
git pull origin main
npm ci --production
npm run build
pm2 restart production-app
- name: Notify Deployment
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: '#deployments'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
Database Migrations
Automated Database Updates
Yaml
# .github/workflows/migrate-database.yml
name: Database Migration
on:
push:
branches: [main]
jobs:
migrate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run database migrations
run: npm run migrate
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
- name: Verify migration
run: npm run verify-migration
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
Security Scanning
Code Security Analysis
Yaml
# .github/workflows/security.yml
name: Security Scan
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
- name: Run npm audit
run: npm audit --audit-level moderate
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
Performance Testing
Automated Performance Tests
Yaml
# .github/workflows/performance.yml
name: Performance Tests
on:
push:
branches: [main]
jobs:
performance:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
- name: Start application
run: npm start &
env:
NODE_ENV: production
- name: Wait for application to start
run: sleep 30
- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v9
with:
configPath: './lighthouse.config.js'
uploadArtifacts: true
temporaryPublicStorage: true
Notification and Monitoring
Slack Notifications
Yaml
# .github/workflows/notify.yml
name: Notify Team
on:
workflow_run:
workflows: ['CI/CD Pipeline']
types: [completed]
jobs:
notify:
runs-on: ubuntu-latest
if: always()
steps:
- name: Notify Success
if: ${{ github.event.workflow_run.conclusion == 'success' }}
uses: 8398a7/action-slack@v3
with:
status: success
channel: '#deployments'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
text: '✅ Deployment successful!'
- name: Notify Failure
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
uses: 8398a7/action-slack@v3
with:
status: failure
channel: '#deployments'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
text: '❌ Deployment failed! Check the logs.'
Best Practices
- Start simple - Begin with basic workflows and add complexity gradually
- Use secrets - Never hardcode sensitive information
- Test your pipelines - Validate workflows before deploying
- Monitor and alert - Set up notifications for failures
- Keep workflows fast - Optimize for speed and efficiency
- Version your deployments - Use semantic versioning
- Rollback strategy - Plan for quick rollbacks when needed
- Document everything - Keep your team informed about the process