GitHub Actions — CI/CD Complete Guide
Advertisement
GitHub Actions — CI/CD Complete Guide
GitHub Actions automates your development workflow with CI/CD pipelines, testing, and deployment directly in GitHub.
Introduction
GitHub Actions enables automation triggered by repository events. Define workflows in YAML to test, build, and deploy code.
- GitHub Actions — CI/CD Complete Guide
- Workflow Basics
- Simple Workflow
- Workflow Events
- Jobs and Steps
- Multiple Jobs
- Matrix Builds
- Environment and Secrets
- Using Secrets
- Environment Variables
- Docker Integration
- Build and Push
- Deployment
- Deploy to AWS
- Deploy to Kubernetes
- Testing
- Node.js Testing
- Artifacts and Caching
- Best Practices
- FAQ
Workflow Basics
Simple Workflow
Create .github/workflows/test.yml:
name: Run Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm install
- run: npm test
Workflow Events
on:
push:
branches:
- main
- develop
paths:
- 'src/**'
- 'package.json'
pull_request:
branches:
- main
schedule:
- cron: '0 0 * * *' # Daily at midnight
workflow_dispatch: # Manual trigger
release:
types: [published]
Jobs and Steps
Multiple Jobs
name: Build and Deploy
on: push
jobs:
build:
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.meta.outputs.tags }}
steps:
- uses: actions/checkout@v3
- name: Build Docker image
id: meta
run: echo "tags=myapp:${{ github.sha }}" >> $GITHUB_OUTPUT
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Deploy
run: echo "Deploying ${{ needs.build.outputs.image_tag }}"
Matrix Builds
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [16, 18, 20]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- run: npm test
Environment and Secrets
Using Secrets
steps:
- name: Deploy to server
env:
SSH_KEY: ${{ secrets.DEPLOY_KEY }}
API_KEY: ${{ secrets.API_KEY }}
run: |
mkdir -p ~/.ssh
echo "$SSH_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh user@server './deploy.sh'
Environment Variables
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Print environment
run: echo "Building $IMAGE_NAME:latest"
Docker Integration
Build and Push
name: Build and Push Docker Image
on:
push:
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: |
${{ secrets.DOCKER_USERNAME }}/myapp:latest
${{ secrets.DOCKER_USERNAME }}/myapp:${{ github.ref_name }}
Deployment
Deploy to AWS
name: Deploy to AWS
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Deploy to ECS
run: |
aws ecs update-service \
--cluster my-cluster \
--service my-service \
--force-new-deployment
Deploy to Kubernetes
name: Deploy to Kubernetes
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up kubectl
uses: azure/setup-kubectl@v3
with:
version: 'v1.26.0'
- name: Configure kubectl
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > $HOME/.kube/config
chmod 600 $HOME/.kube/config
- name: Deploy
run: kubectl apply -f k8s/
Testing
Node.js Testing
name: Test Node.js App
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm install
- run: npm test
- run: npm run lint
Artifacts and Caching
steps:
- uses: actions/checkout@v3
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
- name: Build
run: npm run build
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: dist
path: dist/
Best Practices
name: Production Workflow
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm test
- uses: codecov/codecov-action@v3
build:
needs: [lint, test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build
run: npm run build
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- uses: actions/checkout@v3
- name: Deploy to production
run: echo "Deploying to production"
FAQ
Q: How do I keep secrets safe in GitHub Actions? A: Use GitHub Secrets. Never log secrets or commit them to repository. Use masked values in logs.
Q: Can I reuse workflows across repositories? A: Yes, use uses: with owner/repo/.github/workflows/workflow.yml@ref to call reusable workflows.
Q: How do I debug a failing workflow? A: Enable debug logging: secrets.ACTIONS_STEP_DEBUG set to true, then check logs for detailed output.
Advertisement