GitOps 101: How to Manage Infrastructure and Deployments with Git
What if your entire infrastructure could be managed the same way you manage code—through Git commits, pull requests, and version control? What if deployments were as simple as merging a PR, with automatic rollbacks if something goes wrong?
This is GitOps: a paradigm shift in how we think about infrastructure and deployments. Instead of manual kubectl commands, SSH sessions, or clicking through cloud consoles, GitOps treats Git as the single source of truth for your entire system state.
If you're managing cloud infrastructure, Kubernetes clusters, or complex deployment pipelines, GitOps can dramatically improve reliability, auditability, and developer velocity. Let's explore how.
What is GitOps?
GitOps is an operational framework that applies DevOps best practices—version control, collaboration, compliance, and CI/CD—to infrastructure automation.
Core principle: Your Git repository describes the desired state of your system. Automated agents continuously ensure the actual state matches the desired state declared in Git.
The Four Pillars of GitOps
| Pillar | Description |
|---|---|
| 1. Declarative | Your system is described declaratively (YAML, HCL, etc.) |
| 2. Versioned and Immutable | All changes are tracked in Git with full audit history |
| 3. Pulled Automatically | Agents pull changes from Git (not pushed from CI) |
| 4. Continuously Reconciled | Agents continuously sync actual state to match desired state |
GitOps vs. Traditional DevOps
Let's compare the traditional push-based approach to GitOps:
Traditional Approach (Push-Based)
graph LR
A[Developer] --> B[Git Commit];
B --> C[CI Pipeline];
C --> D[Build/Test];
D --> E[Push to Cluster];
E --> F[Production];
style E fill:#ff9999
Problems:
- CI system needs cluster credentials (security risk)
- Manual intervention often required
- Difficult to audit who changed what
- Drift between Git and actual state
GitOps Approach (Pull-Based)
graph LR
A[Developer] --> B[Git Commit];
B --> C[Git Repository];
D[GitOps Agent in Cluster] -.->|Polls| C;
D --> E[Auto-sync to Match Desired State];
E --> F[Production];
style D fill:#99ff99
Benefits:
- No cluster credentials in CI (agent pulls from Git)
- Automatic, continuous reconciliation
- Complete audit trail in Git
- Self-healing infrastructure
The GitOps Workflow
Here's a typical GitOps workflow for deploying a web application:
-
Developer makes a change:
# Update image tag in Kubernetes manifest git checkout -b update-api-v2 # Edit deployment.yaml: image: myapp:v2 git commit -m "Update API to v2.0.0" git push origin update-api-v2 -
Code review: Team reviews the PR, checking:
- Correct image tag
- Resource limits appropriate
- Environment variables correct
-
Merge to main:
git merge update-api-v2 -
GitOps agent detects change:
- Argo CD or Flux polls the repository
- Notices the new commit
- Applies changes to the cluster
- Reports success/failure
-
Observability:
- Git provides full audit trail
- Slack/email notifications on deployment
- Prometheus monitors application health
Tools: Argo CD vs. Flux
The two leading GitOps tools for Kubernetes are Argo CD and Flux. Both are CNCF projects with strong communities.
| Feature | Argo CD | Flux |
|---|---|---|
| UI | Rich web UI with visual app topology | CLI-focused (UI via extensions) |
| Multi-tenancy | Built-in with Projects | Via RBAC and repository structure |
| Git Source | Git, Helm repos | Git, Helm, OCI registries |
| Sync Strategy | Manual or auto | Always automatic |
| Notifications | Built-in (Slack, email, webhooks) | Via Notification Controller |
| Architecture | Centralized controller | Distributed, per-cluster agents |
| Learning Curve | Moderate (UI helps) | Steeper (CLI-first) |
| Best For | Teams wanting visibility via UI | Large-scale, multi-cluster setups |
Both are excellent. Choose based on your team's preferences and infrastructure complexity.
Getting Started with Argo CD
Installation
# Create namespace
kubectl create namespace argocd
# Install Argo CD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Expose the UI (for local testing)
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Get admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
Creating Your First Application
Create a Git repository with Kubernetes manifests:
# git-repo/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: nginx:1.21
ports:
- containerPort: 80
Define an Argo CD Application:
# argocd-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/my-app-config
targetRevision: HEAD
path: k8s
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
Apply it:
kubectl apply -f argocd-app.yaml
Argo CD will:
- Clone your Git repository
- Apply the manifests to the
productionnamespace - Continuously sync on every Git commit
- Self-heal if someone manually changes resources
Getting Started with Flux
Installation
# Install Flux CLI
curl -s https://fluxcd.io/install.sh | sudo bash
# Bootstrap Flux on your cluster
flux bootstrap github \
--owner=myorg \
--repository=fleet-infra \
--branch=main \
--path=clusters/production \
--personal
This command:
- Creates a
fleet-infrarepository in your GitHub account - Installs Flux controllers in your cluster
- Configures Flux to sync from the repository
Defining a GitRepository and Kustomization
# clusters/production/my-app-source.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: my-app
namespace: flux-system
spec:
interval: 1m
url: https://github.com/myorg/my-app-config
ref:
branch: main
# clusters/production/my-app-kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
interval: 5m
path: ./k8s
prune: true
sourceRef:
kind: GitRepository
name: my-app
Commit these files to your fleet-infra repository. Flux will automatically apply your application manifests.
GitOps for Multi-Environment Deployments
A common pattern is using branches or directories for different environments:
Directory-Based (Recommended)
my-app-config/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
├── overlays/
│ ├── dev/
│ │ └── kustomization.yaml
│ ├── staging/
│ │ └── kustomization.yaml
│ └── production/
│ └── kustomization.yaml
Each environment has its own Argo CD Application or Flux Kustomization pointing to the appropriate overlay.
Staging Argo CD App:
spec:
source:
repoURL: https://github.com/myorg/my-app-config
path: overlays/staging
Production Argo CD App:
spec:
source:
repoURL: https://github.com/myorg/my-app-config
path: overlays/production
Branch-Based (Alternative)
devbranch → dev environmentstagingbranch → staging environmentmainbranch → production environment
This approach is simpler but can lead to drift between environments.
Benefits of GitOps
1. Complete Audit Trail
Every change is a Git commit. You can answer:
- Who deployed version X?
- When did this configuration change?
- Why was this change made? (commit message)
2. Easy Rollbacks
Made a mistake? Revert the Git commit:
git revert HEAD
git push
GitOps agent automatically rolls back the deployment.
3. Disaster Recovery
If your cluster is destroyed, you can recreate it entirely from Git:
# Provision new cluster
# Install Argo CD or Flux
# Point it at your Git repo
# All applications and configs are restored
4. Enhanced Security
- No need to distribute cluster credentials to CI systems
- Git access controls dictate who can deploy
- All changes go through code review
5. Developer Self-Service
Developers can deploy by merging PRs without needing cluster access or DevOps intervention.
Challenges and Best Practices
Challenge 1: Secret Management
Problem: You can't store secrets in Git in plain text.
Solutions:
- Sealed Secrets: Encrypt secrets that only the cluster can decrypt
- External Secrets Operator: Sync secrets from AWS Secrets Manager, HashiCorp Vault, etc.
- SOPS: Encrypt YAML files with keys managed externally
Example with Sealed Secrets:
# Create a sealed secret
kubectl create secret generic my-secret --from-literal=password=supersecret --dry-run=client -o yaml | \
kubeseal -o yaml > sealed-secret.yaml
# Commit sealed-secret.yaml to Git (safe)
git add sealed-secret.yaml
git commit -m "Add database password"
Challenge 2: Image Tag Updates
Problem: How do you update image tags in a GitOps workflow?
Solution: Use image automation controllers (Flux Image Automation, Argo CD Image Updater):
# Flux ImageUpdateAutomation
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
name: my-app
spec:
interval: 1m
sourceRef:
kind: GitRepository
name: my-app-config
git:
commit:
author:
email: fluxbot@example.com
name: Flux Bot
update:
path: ./overlays/production
strategy: Setters
When a new image is pushed, Flux automatically updates the Git repository.
Challenge 3: Drift Detection
Problem: Someone manually edits resources in the cluster (they shouldn't, but it happens).
Solution: Both Argo CD and Flux detect and report drift. Enable self-healing:
# Argo CD
syncPolicy:
automated:
selfHeal: true
# Flux
spec:
prune: true
force: true
The agent will automatically revert manual changes to match Git.
GitOps Beyond Kubernetes
While GitOps is most commonly associated with Kubernetes, the principles apply to any infrastructure:
- Terraform GitOps: Atlantis, Terraform Cloud, env0
- AWS/Azure GitOps: CloudFormation, ARM templates in Git with automated deployment
- Configuration Management: Ansible, Chef, Puppet playbooks in Git
Conclusion
GitOps isn't just a tool—it's a mindset. By treating Git as the single source of truth, you gain auditability, reliability, and velocity. Deployments become routine, rollbacks become trivial, and your infrastructure becomes code that your entire team can collaborate on.
Start small: pick one application, set up Argo CD or Flux, and experience the GitOps workflow firsthand. Once you see how powerful it is to deploy with a git push, there's no going back.
Ready to streamline your deployment workflows? Sign up for ScanlyApp and integrate GitOps best practices into your QA and delivery pipeline.
Related articles: Also see the CI/CD pipeline that makes GitOps workflows testable, testing the infrastructure code that your GitOps pipeline deploys, and deployment strategies that pair naturally with GitOps workflows.
