#Lab: Advanced GitHub Actions Pipeline
Build a production-ready CI/CD pipeline with GitHub Actions.
#🎯 Objectives
- Create multi-stage deployment pipeline
- Implement matrix builds for multiple environments
- Set up environment protection rules
- Use reusable workflows
#📋 Prerequisites
- GitHub repository
- Basic GitHub Actions knowledge
#⏱️ Duration: 45 minutes
#Task 1: Multi-Stage Pipeline (15 min)
Create .github/workflows/production-pipeline.yml:
yaml
1name: Production Pipeline
2
3on:
4 push:
5 branches: [main, develop]
6 pull_request:
7 branches: [main]
8
9env:
10 REGISTRY: ghcr.io
11 IMAGE_NAME: ${{ github.repository }}
12
13jobs:
14 # Stage 1: Build and Test
15 test:
16 runs-on: ubuntu-latest
17 steps:
18 - uses: actions/checkout@v4
19
20 - name: Setup Node.js
21 uses: actions/setup-node@v4
22 with:
23 node-version: '20'
24 cache: 'npm'
25
26 - name: Install dependencies
27 run: npm ci
28
29 - name: Run tests
30 run: npm test
31
32 - name: Run linting
33 run: npm run lint
34
35 # Stage 2: Build Docker Image
36 build:
37 needs: test
38 runs-on: ubuntu-latest
39 outputs:
40 image-tag: ${{ steps.meta.outputs.tags }}
41 steps:
42 - uses: actions/checkout@v4
43
44 - name: Set up Docker Buildx
45 uses: docker/setup-buildx-action@v3
46
47 - name: Login to Container Registry
48 uses: docker/login-action@v3
49 with:
50 registry: ${{ env.REGISTRY }}
51 username: ${{ github.actor }}
52 password: ${{ secrets.GITHUB_TOKEN }}
53
54 - name: Extract metadata
55 id: meta
56 uses: docker/metadata-action@v5
57 with:
58 images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
59 tags: |
60 type=sha,prefix=
61 type=ref,event=branch
62
63 - name: Build and push
64 uses: docker/build-push-action@v5
65 with:
66 context: .
67 push: true
68 tags: ${{ steps.meta.outputs.tags }}
69 cache-from: type=gha
70 cache-to: type=gha,mode=max
71
72 # Stage 3: Deploy to Staging
73 deploy-staging:
74 needs: build
75 runs-on: ubuntu-latest
76 environment: staging
77 steps:
78 - name: Deploy to staging
79 run: |
80 echo "Deploying to staging..."
81 # kubectl set image deployment/app app=${{ needs.build.outputs.image-tag }}
82
83 # Stage 4: Deploy to Production
84 deploy-production:
85 needs: [build, deploy-staging]
86 runs-on: ubuntu-latest
87 environment: production
88 if: github.ref == 'refs/heads/main'
89 steps:
90 - name: Deploy to production
91 run: |
92 echo "Deploying to production..."#Task 2: Matrix Builds (10 min)
yaml
1name: Matrix Build
2
3on: push
4
5jobs:
6 test:
7 runs-on: ${{ matrix.os }}
8 strategy:
9 matrix:
10 os: [ubuntu-latest, windows-latest, macos-latest]
11 node-version: [18, 20, 21]
12 exclude:
13 - os: windows-latest
14 node-version: 21
15
16 steps:
17 - uses: actions/checkout@v4
18
19 - name: Use Node.js ${{ matrix.node-version }}
20 uses: actions/setup-node@v4
21 with:
22 node-version: ${{ matrix.node-version }}
23
24 - run: npm ci
25 - run: npm test#Task 3: Reusable Workflow (10 min)
Create .github/workflows/deploy-template.yml:
yaml
1name: Reusable Deploy
2
3on:
4 workflow_call:
5 inputs:
6 environment:
7 required: true
8 type: string
9 image-tag:
10 required: true
11 type: string
12 secrets:
13 DEPLOY_TOKEN:
14 required: true
15
16jobs:
17 deploy:
18 runs-on: ubuntu-latest
19 environment: ${{ inputs.environment }}
20 steps:
21 - name: Deploy
22 run: |
23 echo "Deploying ${{ inputs.image-tag }} to ${{ inputs.environment }}"Call it from another workflow:
yaml
1jobs:
2 deploy:
3 uses: ./.github/workflows/deploy-template.yml
4 with:
5 environment: staging
6 image-tag: myapp:latest
7 secrets:
8 DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}#Task 4: Conditional Jobs (10 min)
yaml
1jobs:
2 changes:
3 runs-on: ubuntu-latest
4 outputs:
5 backend: ${{ steps.filter.outputs.backend }}
6 frontend: ${{ steps.filter.outputs.frontend }}
7 steps:
8 - uses: actions/checkout@v4
9 - uses: dorny/paths-filter@v2
10 id: filter
11 with:
12 filters: |
13 backend:
14 - 'backend/**'
15 frontend:
16 - 'frontend/**'
17
18 backend:
19 needs: changes
20 if: ${{ needs.changes.outputs.backend == 'true' }}
21 runs-on: ubuntu-latest
22 steps:
23 - run: echo "Backend changed"
24
25 frontend:
26 needs: changes
27 if: ${{ needs.changes.outputs.frontend == 'true' }}
28 runs-on: ubuntu-latest
29 steps:
30 - run: echo "Frontend changed"#✅ Success Criteria
- Multi-stage pipeline created
- Matrix builds working
- Reusable workflow implemented
- Conditional jobs based on path changes