GitHub Actions Integration
GitHub Actions can automate GitOps workflows by building container images, updating manifests, running tests, and triggering deployments. This integration combines CI/CD automation with GitOps principles.
GitOps + CI/CD Flow
graph TB
A[Developer Push] --> B[GitHub Actions]
B --> C[Build Image]
C --> D[Push to Registry]
D --> E[Update Manifest]
E --> F[Git Commit]
F --> G[GitOps Controller]
G --> H[Deploy to Cluster]
style B fill:#e1f5ff
style C fill:#e8f5e9
style E fill:#fff4e1
style G fill:#f3e5f5
Basic Workflow
Image Build and Push
# .github/workflows/build.yml
name: Build and Push
on:
push:
branches: [main]
paths:
- 'apps/web-app/**'
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 Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and Push
uses: docker/build-push-action@v4
with:
context: ./apps/web-app
push: true
tags: |
ghcr.io/${{ github.repository }}/web-app:${{ github.sha }}
ghcr.io/${{ github.repository }}/web-app:latest
Update GitOps Manifest
# .github/workflows/update-manifest.yml
name: Update Manifest
on:
workflow_run:
workflows: ["Build and Push"]
types:
- completed
jobs:
update:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- uses: actions/checkout@v3
with:
token: ${{ secrets.GITOPS_TOKEN }}
- name: Update Image Tag
run: |
IMAGE_TAG="ghcr.io/${{ github.repository }}/web-app:${{ github.sha }}"
cd apps/web-app/overlays/production
sed -i "s|newImage:.*|newImage: ${IMAGE_TAG}|" kustomization.yaml
- name: Commit Changes
run: |
git config user.name "GitHub Actions"
git config user.email "[email protected]"
git add apps/web-app/overlays/production/kustomization.yaml
git commit -m "Update web-app image to ${{ github.sha }}"
git push
Image Update Automation
Automated Image Updates
# .github/workflows/image-update.yml
name: Update Image
on:
push:
branches: [main]
paths:
- 'apps/web-app/**'
workflow_dispatch:
jobs:
update-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
token: ${{ secrets.GITOPS_TOKEN }}
- name: Get Image SHA
id: image
run: |
SHA=$(git rev-parse --short HEAD)
echo "sha=$SHA" >> $GITHUB_OUTPUT
- name: Update Kustomize Image
run: |
cd apps/web-app/overlays/production
IMAGE="ghcr.io/${{ github.repository }}/web-app:${{ steps.image.outputs.sha }}"
kustomize edit set image web-app=$IMAGE
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.GITOPS_TOKEN }}
commit-message: "chore: update web-app image to ${{ steps.image.outputs.sha }}"
title: "Update web-app image"
body: |
Automated image update for web-app
- Image: ghcr.io/${{ github.repository }}/web-app:${{ steps.image.outputs.sha }}
branch: update-web-app-image
Manifest Validation
Validate Kubernetes Manifests
# .github/workflows/validate.yml
name: Validate Manifests
on:
pull_request:
paths:
- 'apps/**'
- 'infrastructure/**'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install kubeval
run: |
wget https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz
tar xf kubeval-linux-amd64.tar.gz
sudo mv kubeval /usr/local/bin
- name: Validate Manifests
run: |
for file in $(find apps -name "*.yaml" -o -name "*.yml"); do
kubeval $file
done
Validate with Kustomize
# .github/workflows/kustomize-validate.yml
name: Kustomize Validate
on:
pull_request:
paths:
- 'apps/**'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Kustomize
uses: imranismail/setup-kustomize@v1
with:
version: "4.5.7"
- name: Build and Validate
run: |
cd apps/web-app/overlays/production
kustomize build . | kubectl apply --dry-run=client -f -
Security Scanning
Container Image Scanning
# .github/workflows/scan.yml
name: Security Scan
on:
push:
branches: [main]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'ghcr.io/${{ github.repository }}/web-app:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
Manifest Security Scanning
# .github/workflows/manifest-scan.yml
name: Scan Manifests
on:
pull_request:
paths:
- 'apps/**'
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: apps/
framework: kubernetes
output_format: sarif
output_file_path: checkov.sarif
- name: Upload results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: checkov.sarif
Promotion Workflows
Environment Promotion
# .github/workflows/promote.yml
name: Promote to Production
on:
workflow_dispatch:
inputs:
version:
description: 'Version to promote'
required: true
type: string
jobs:
promote:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
token: ${{ secrets.GITOPS_TOKEN }}
- name: Update Production Image
run: |
cd apps/web-app/overlays/production
IMAGE="ghcr.io/${{ github.repository }}/web-app:${{ github.event.inputs.version }}"
kustomize edit set image web-app=$IMAGE
- name: Create Promotion PR
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.GITOPS_TOKEN }}
title: "Promote web-app ${{ github.event.inputs.version }} to production"
body: |
Promoting web-app version ${{ github.event.inputs.version }} to production.
- Version: ${{ github.event.inputs.version }}
- Image: ghcr.io/${{ github.repository }}/web-app:${{ github.event.inputs.version }}
branch: promote-prod-${{ github.event.inputs.version }}
labels: promotion,production
Automated Promotion with Tests
# .github/workflows/promote-with-tests.yml
name: Promote with Tests
on:
push:
branches: [staging]
jobs:
test-staging:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Integration Tests
run: |
# Run tests against staging environment
./scripts/test-staging.sh
- name: Promote to Production
if: success()
uses: actions/checkout@v3
with:
token: ${{ secrets.GITOPS_TOKEN }}
run: |
cd apps/web-app/overlays/production
STAGING_IMAGE=$(grep newImage overlays/staging/kustomization.yaml | cut -d: -f2)
kustomize edit set image web-app=$STAGING_IMAGE
git commit -am "Promote web-app to production"
git push
ArgoCD Integration
Trigger ArgoCD Sync
# .github/workflows/argocd-sync.yml
name: Sync ArgoCD
on:
push:
branches: [main]
paths:
- 'apps/**'
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Sync ArgoCD Application
uses: actions-hub/kubectl@master
env:
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
with:
args: >
patch application web-app
-n argocd
--type merge
-p '{"operation":{"initiatedBy":{"username":"github-actions"},"sync":{"revision":"${{ github.sha }}"}}}'
ArgoCD Webhook
# .github/workflows/argocd-webhook.yml
name: ArgoCD Webhook
on:
repository_dispatch:
types: [argocd-sync]
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Trigger ArgoCD Sync
run: |
curl -X POST ${{ secrets.ARGOCD_WEBHOOK_URL }} \
-H "Authorization: Bearer ${{ secrets.ARGOCD_TOKEN }}"
Flux Integration
Update Flux Image Policy
# .github/workflows/flux-update.yml
name: Update Flux Image
on:
push:
branches: [main]
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
token: ${{ secrets.GITOPS_TOKEN }}
- name: Update ImagePolicy
run: |
IMAGE_TAG="${{ github.sha }}"
kubectl patch imagepolicy web-app -n flux-system \
--type json \
-p="[{\"op\": \"replace\", \"path\": \"/spec/policy/semver/range\", \"value\": \">=$IMAGE_TAG\"}]"
Best Practices
1. Use Secrets for Credentials
# Store in GitHub Secrets
- name: Login to Registry
uses: docker/login-action@v2
with:
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
2. Limit Workflow Permissions
permissions:
contents: write # Only what's needed
pull-requests: write
3. Protect Main Branch
Require:
- Pull request reviews
- Status checks to pass
- Branch protection rules
4. Use Matrix Builds
strategy:
matrix:
app: [web-app, api, worker]
steps:
- name: Build ${{ matrix.app }}
run: docker build -t ${{ matrix.app }} ./apps/${{ matrix.app }}
5. Cache Dependencies
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
6. Run Tests Before Update
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Run Tests
run: npm test
update:
needs: test
runs-on: ubuntu-latest
steps:
- name: Update Manifest
run: ...
Common Workflows
Complete CI/CD Pipeline
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Image
run: docker build -t app:${{ github.sha }} .
- name: Push Image
run: docker push app:${{ github.sha }}
test:
runs-on: ubuntu-latest
needs: build
steps:
- name: Run Tests
run: ./test.sh
scan:
runs-on: ubuntu-latest
needs: build
steps:
- name: Security Scan
uses: aquasecurity/trivy-action@master
update-manifest:
runs-on: ubuntu-latest
needs: [test, scan]
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Update Manifest
run: |
sed -i "s|image:.*|image: app:${{ github.sha }}|" manifest.yaml
git commit -am "Update image"
git push
Troubleshooting
Workflow Not Triggering
# Check paths filter
on:
push:
paths:
- 'apps/**' # Must match file paths
Permission Denied
# Add permissions
permissions:
contents: write
pull-requests: write
Secrets Not Available
- Check secret name matches
- Verify secret is set in repository settings
- Use
${{ secrets.SECRET_NAME }}syntax
Summary
GitHub Actions + GitOps integration:
- Build Images - Automate container builds
- Update Manifests - Automatically update GitOps manifests
- Validate - Test manifests before deployment
- Scan - Security scanning for images and manifests
- Promote - Automated environment promotion
- Sync - Trigger GitOps controller syncs
Best practices:
- Use secrets for credentials
- Limit workflow permissions
- Protect main branch
- Run tests before updates
- Cache dependencies
- Validate before deploying
This combination provides automated CI/CD while maintaining GitOps principles of declarative, auditable deployments.