GitOps Automation Pipeline

Automate infrastructure and application delivery using GitOps principles. Covers repository structure, reconciliation loops, drift detection, ArgoCD patterns, and the automation patterns that make Git the single source of truth for your operational state.

A GitOps Automation Pipeline synchronizes a system’s desired state with its actual state through a continuous, automated, and declarative process, where Git is the single source of truth for infrastructure and application configurations. It matters when teams manage complex, distributed systems across multiple environments, and need to reduce drift, accelerate deployments, and ensure auditability and reproducibility of every change. This pipeline is the backbone of modern cloud-native operations, where every configuration update—whether for Kubernetes manifests, CI/CD jobs, or service policies—is tracked, versioned, and automatically applied.

Core Workflow: From Commit to Live

The GitOps pipeline begins when a developer pushes a change to a Git repository, and ends when the system reflects that change in production. The process is fully automated: each commit triggers a sequence of events that verify, build, test, and deploy the change.

  1. Commit and Push:

A developer modifies a Kubernetes Deployment manifest in manifests/app.yaml.

   # manifests/app.yaml
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: frontend
   spec:
     replicas: 3
     selector:
       matchLabels:
         app: frontend
     template:
       metadata:
         labels:
           app: frontend
       spec:
         containers:
         - name: app
           image: registry.example.com/frontend:v1.2.3
           ports:
           - containerPort: 80

The change is committed and pushed to the main branch.

  1. Pull Request and CI Validation:

A CI system (e.g., GitHub Actions, GitLab CI, or Argo Workflows) runs on every push:

   # .github/workflows/ci.yml
   name: CI
   on: [push]
   jobs:
     build:
       runs-on: ubuntu-latest
       steps:
         - uses: actions/checkout@v4
         - run: |
             docker build -t registry.example.com/frontend:latest .
             docker push registry.example.com/frontend:latest
         - run: |
             kubectl apply -f manifests/
             kubectl get deployment frontend -o yaml
         - run: |
             # Run Helm chart linting
             helm lint charts/frontend

The CI job fails if helm lint reports issues or kubectl get deployment returns an unexpected state.

  1. Automated Review and Approval:

The pipeline automatically creates a pull request with a status check: ci/ci with a link to logs. A reviewer approves the PR, and the CI job passes.

  1. Merge to Main and Deployment Trigger:

Upon merge, the pipeline triggers a deployment job. The main branch is the source of truth.

   # .github/workflows/deploy.yml
   name: Deploy
   on:
     push:
       branches: [ main ]
   jobs:
     deploy:
       runs-on: ubuntu-latest
       steps:
         - uses: actions/checkout@v4
         - run: |
             kubectl apply -f manifests/
             kubectl rollout status deployment/frontend --timeout=60s
         - run: |
             kubectl get deployment/frontend -o wide
         - run: |
             echo "Deployed to production" | tee -a /tmp/deploy.log

The rollout status command fails with a timeout if the deployment takes more than 60 seconds.

  1. Post-Deployment Verification:

After the rollout, the pipeline runs integration tests via a test job:

   # .github/workflows/test.yml
   name: Test
   on: [push]
   jobs:
     test:
       runs-on: ubuntu-latest
       steps:
         - uses: actions/checkout@v4
         - run: |
             kubectl wait --for=condition=Available --timeout=60s deployment/frontend
             curl -f http://frontend.example.com/health
         - run: |
             kubectl get pods -l app=frontend -o wide

If curl -f fails with HTTP 404 or 500, the job fails, and a notification is sent via Slack.

Configuration Management: Declarative State in Git

The pipeline relies on a single, shared configuration repository. This repository contains all declarative artifacts, including Kubernetes manifests, Helm charts, and CI/CD workflows.

Manifests and Configuration Files

All infrastructure and application configurations are stored as YAML files in manifests/, charts/, and config/. These files are versioned and reviewed through pull requests.


replicaCount: 4
image:
  repository: registry.example.com/frontend
  tag: "v1.2.3"
service:
  type: LoadBalancer
  port: 80

Changes to values.yaml are applied via Helm, and the resulting manifest is committed to Git.

Git Branching Strategy

A main branch holds the production-ready configuration. Feature branches are used for experimentation.

The pipeline automatically deploys staging branch to a staging cluster, and main to production.

Configuration Validation

Before applying configuration to a cluster, the pipeline validates it.

# .github/workflows/lint.yml
name: Lint
on: [pull_request]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: |
          yq eval '.image.tag' charts/frontend/values.yaml
          # Validate all manifests
          kubectl apply -f manifests/ --dry-run=client -o yaml
      - run: |
          # Run kubeval
          curl -sSfL https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64 -o kubeval
          chmod +x kubeval
          ./kubeval --strict manifests/

The --strict flag in kubeval requires all required fields to be present. A missing spec.replicas field fails validation.

Automation Triggers and Event Sources

The pipeline responds to multiple event sources, each triggering a different workflow.

Push to Git

A push to main triggers the full deploy pipeline: CI, deployment, and post-deployment testing.

Pull Request

A pull request triggers CI and linting, and updates a status check.

{
  "state": "success",
  "description": "All tests passed",
  "target_url": "https://github.com/org/repo/actions/runs/123456",
  "context": "ci/ci"
}

GitHub uses this JSON in its API to update the PR status.

Manual Trigger

A team member can manually trigger a deployment via a CLI command:

curl -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"branch": "main", "message": "Manual deployment"}' \
  https://pipeline.example.com/api/v1/deploy

The server responds with a job ID:

{
  "job_id": "deploy-2024-05-10-12345",
  "status": "queued",
  "started_at": "2024-05-10T10:30:00Z"
}

Scheduled Triggers

The pipeline runs a weekly maintenance job:

# .github/workflows/maintenance.yml
name: Maintenance
on:
  schedule:
    - cron: '0 2 * * 0' # Every Sunday at 2 AM UTC
jobs:
  cleanup:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: |
          kubectl get pods --all-namespaces -o wide | grep -v Running
          kubectl delete pod -n monitoring -l app=grafana

The cron schedule uses standard cron syntax, and the job runs independently of Git events.

State Synchronization and Drift Detection

The pipeline ensures that the actual state of the system matches the desired state declared in Git.

Continuous Reconciliation

A reconciliation loop runs every 5 minutes, comparing the current state of the cluster with the desired state in Git.

# reconcile.sh
#!/bin/bash
set -euo pipefail

BRANCH=${BRANCH:-main}
CLUSTER=${CLUSTER:-production}

# Get current state from cluster
kubectl get all -A -o yaml > /tmp/actual.yaml

# Get desired state from Git
git checkout $BRANCH
git pull origin $BRANCH
git checkout $BRANCH

# Compare with desired state
git diff --name-only HEAD~1 HEAD -- manifests/

# If differences exist, log and apply
if [ -n "$(git diff --name-only HEAD~1 HEAD -- manifests/)" ]; then
  echo "Drift detected: applying changes"
  kubectl apply -f manifests/
  kubectl rollout status deployment/frontend --timeout=60s
fi

The script uses git diff --name-only to detect which manifest files have changed. If any file differs, it applies the changes and rolls out the deployment.

Drift Detection and Alerting

When drift is detected, the pipeline logs the differences and sends an alert.

{
  "event": "drift_detected",
  "branch": "main",
  "timestamp": "2024-05-10T10:30:00Z",
  "changes": [
    {
      "file": "manifests/app.yaml",
      "diff": "  replicas: 3\n+  replicas: 4\n",
      "type": "deployment"
    }
  ],
  "details": {
    "applied": true,
    "rollout_status": "Successful",
    "new_revision": "frontend-7584d6c98f"
  }
}

The alert is sent via a webhook to a monitoring system.

Failure Modes and Common Pitfalls

Silent Failures

The CI job runs kubectl apply, but the actual rollout is not verified. If kubectl rollout status fails silently, the deployment appears successful but the app is down.

A new image tag is pushed to the registry, but values.yaml is not updated. The Helm release uses an old image.

Common Mistakes

A 30-second timeout is too short for a large cluster, causing false positives.

The deploy job uses main, but the pipeline is configured for staging. The wrong branch is deployed.

Without --dry-run=client, kubectl apply applies the manifest but does not validate it against the cluster’s API version.

Configuration Errors

The deployment is not ready, but the pipeline assumes it is. The rollout status command must include --timeout=60s.

The health endpoint is not available. The pipeline must ensure the service is exposed and the pod is running.

Monitoring and Debugging

A debug job allows teams to inspect the state of the pipeline:

# .github/workflows/debug.yml
name: Debug
on:
  workflow_dispatch:
    inputs:
      branch:
        description: 'Branch to debug'
        required: true
        default: 'main'
jobs:
  debug:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: |
          git checkout ${{ inputs.branch }}
          kubectl get all -A
          kubectl get deployment/frontend -o yaml
          kubectl logs deployment/frontend -n default

The workflow_dispatch allows manual triggering from the GitHub UI, with a form to specify the branch.

Summary: The GitOps Automation Pipeline

The GitOps Automation Pipeline is a fully automated, declarative, and event-driven system where Git is the source of truth. Every change to infrastructure and application configuration is versioned, validated, tested, and deployed. The pipeline runs continuously, reconciling the actual state of the system with the desired state in Git. It is driven by events: commits, pull requests, manual triggers, and schedules. It detects and corrects drift, and provides clear, actionable feedback when failures occur. The pipeline is built from standard tools—Git, kubectl, curl, docker, and shell scripts—and is not tied to any specific platform. Its success depends on careful configuration, consistent validation, and a clear understanding of how each component interacts.

This page was rewritten on 18 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.