Full GitOps Pipeline — From Code Commit to Production
Why a Full GitOps Pipeline Matters
A complete GitOps pipeline automates the entire software delivery process — from code commit to production deployment — using Git as the single source of truth. This chapter combines GitHub Actions (CI) with ArgoCD (CD) to build a production-ready GitOps workflow with multi-environment promotion and disaster recovery.
Why this matters for your career:
- End-to-end GitOps pipelines are the industry standard for Kubernetes deployments
- Combining CI with GitOps CD is the modern DevOps pattern used by leading tech companies
- Multi-environment promotion with approval gates is essential for enterprise deployments
- Disaster recovery with GitOps is a key capability that sets GitOps apart from traditional CI/CD
Pipeline Architecture
The pipeline has two main stages:
CI (GitHub Actions): Build → Test → Push Docker image → Update config repo CD (ArgoCD): Detect config change → Sync cluster → Verify health → Promote
Developer → Code Commit → GitHub Actions (CI) → Push Image
↓
Update Config Repo (Git)
↓
ArgoCD detects change (CD)
↓
Sync Dev → Staging → Production
CI Pipeline (GitHub Actions)
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test
- run: npm run lint
build-and-push:
needs: [test]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v4
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
- name: Update image tag in config repo
run: |
git clone https://x-access-token:${{ secrets.CONFIG_PAT }}@github.com/myorg/myapp-config.git
cd myapp-config
cd k8s/overlays/production
kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
git config user.name "CI Bot"
git config user.email "ci-bot@example.com"
git add .
git commit -m "Update image tag to ${{ github.sha }}"
git push
CD Pipeline (ArgoCD ApplicationSet)
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: my-app
namespace: argocd
spec:
generators:
- list:
elements:
- env: dev
namespace: my-app-dev
path: k8s/overlays/dev
- env: staging
namespace: my-app-staging
path: k8s/overlays/staging
- env: production
namespace: my-app-prod
path: k8s/overlays/production
template:
metadata:
name: 'my-app-{{env}}'
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp-config.git
targetRevision: HEAD
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Multi-Environment Promotion
Strategy
| Environment | Trigger | Approval Required | Rollback Method | |-------------|---------|-----------------|-----------------| | Dev | Auto on merge | None | Revert commit | | Staging | After dev syncs + tests pass | Automated | Revert commit | | Production | Manual approval | Team lead + QA | Revert commit |
Promote via ArgoCD CLI
# Promote staging to production
argocd app sync my-app-production --revision main
# Check sync status
argocd app get my-app-production
# Rollback if needed
argocd app rollback my-app-production --prune
Image Updater Integration
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app-image-updater
namespace: argocd
annotations:
argocd-image-updater.argoproj.io/image-list: my-app=ghcr.io/myorg/my-app
argocd-image-updater.argoproj.io/my-app.update-strategy: semver
argocd-image-updater.argoproj.io/my-app.allow-tags: regexp:^v\\d+\\.\\d+\\.\\d+$
argocd-image-updater.argoproj.io/write-back-method: git:secret:argocd/image-updater-creds
argocd-image-updater.argoproj.io/git-branch: main
spec:
source:
repoURL: https://github.com/myorg/myapp-config.git
targetRevision: main
path: k8s/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: my-app-prod
Disaster Recovery
# New cluster provisioned → Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Apply the ApplicationSet
kubectl apply -f applicationset.yaml
# ArgoCD automatically syncs all apps from Git
# Entire cluster restored to desired state in minutes
This reduces recovery time from hours/days to 5-15 minutes.
Monitoring and Alerting
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: my-app
namespace: argocd
spec:
sourceRepos:
- 'https://github.com/myorg/*'
destinations:
- namespace: '*'
server: https://kubernetes.default.svc
syncWindows:
- kind: deny
schedule: '0 22 * * *'
duration: 6h
namespaces:
- my-app-prod
applications:
- '*-production'
Best Practices
| Practice | Reason | |----------|--------| | Separate app code from config repo | Security — config repo has narrower access permissions | | Use ApplicationSet for multi-env | DRY — one template generates all environments | | Enable self-heal and prune | Automatic drift correction and cleanup | | Use sync windows for production | Prevent deployments during off-hours | | Add cluster resource whitelist | Limit what ArgoCD can create/modify | | Always use PRs for config changes | Code review for infrastructure changes | | Monitor sync status and send alerts | Detect out-of-sync applications quickly | | Tag images with commit SHA (not latest) | Traceable, reproducible deployments |
Summary
A complete GitOps pipeline combines GitHub Actions for CI (build, test, push) with ArgoCD for CD (auto-sync from Git). Image updater automates version management. ApplicationSet handles multi-environment deployment with a single template. Disaster recovery becomes push-button.
Key takeaways:
- CI pipeline builds images and updates the config repo
- ArgoCD detects config changes and syncs the cluster
- Separate app code from config repo for security
- ApplicationSet: one template for all environments
- Image updater auto-detects new versions
- Promote: dev (auto) → staging (tests) → production (manual approval)
- Sync windows protect production during off-hours
- Disaster recovery: new cluster → install ArgoCD → sync from Git
- Monitor sync status and set up alerts
What's Next: DevOps — Monitoring
The next course covers DevOps monitoring — Prometheus, Grafana, Loki, and OpenTelemetry for comprehensive observability.