In this episode, we'll discuss GitOps for managing Kubernetes deployments using Git as the source of truth. We'll learn GitOps principles, tools like ArgoCD and Flux, and best practices for implementing GitOps workflows.

Note
If you want to read the previous episode, you can click the Episode 39 thumbnail below
In the previous episode, we explored Kustomize, which provides a declarative approach to customizing Kubernetes manifests. Now we'll dive into GitOps, which uses Git as the source of truth for Kubernetes deployments.
Note: Here I'll be using a Kubernetes Cluster installed through K3s.
GitOps is a set of practices that uses Git repositories as the single source of truth for declarative infrastructure and applications. Instead of manually applying kubectl commands, you commit your desired state to Git, and automated tools synchronize your cluster to match that state. Think of GitOps like Infrastructure as Code for Kubernetes - your entire cluster configuration lives in Git.
GitOps is based on four core principles:
1. Declarative
Your entire system is described declaratively in Git.
2. Versioned and Immutable
All changes are tracked in Git with full history.
3. Pulled Automatically
Automated tools pull changes from Git and apply them to the cluster.
4. Continuously Reconciled
The cluster state is continuously compared with Git and reconciled.
1. Single Source of Truth
Git is the authoritative source for all cluster state.
2. Audit Trail
Every change is tracked with commit history.
3. Easy Rollback
Revert to any previous state by reverting Git commits.
4. Collaboration
Teams collaborate through pull requests and code review.
5. Automation
Continuous deployment without manual intervention.
6. Disaster Recovery
Recreate entire cluster from Git.
Traditional vs GitOpsDeveloper → kubectl apply → ClusterManual, error-prone, no audit trail.
Developer → Git Commit → GitOps Tool → ClusterAutomated, auditable, reproducible.
ArgoCD is a declarative, GitOps continuous delivery tool for Kubernetes.
Installation
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yamlAccess ArgoCD UI
kubectl port-forward svc/argocd-server -n argocd 8080:443Get Initial Password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -dFlux is a tool for keeping Kubernetes clusters in sync with sources of configuration.
Installation
curl -s https://fluxcd.io/install.sh | sudo bash
flux installBootstrap from Git
flux bootstrap github \
--owner=your-username \
--repository=fleet-infra \
--branch=main \
--path=./clusters/my-cluster \
--personalgitops-repo/
├── clusters/
│ ├── dev/
│ │ ├── kustomization.yaml
│ │ └── apps/
│ ├── staging/
│ │ ├── kustomization.yaml
│ │ └── apps/
│ └── production/
│ ├── kustomization.yaml
│ └── apps/
├── apps/
│ ├── web-app/
│ │ ├── base/
│ │ └── overlays/
│ └── api-app/
│ ├── base/
│ └── overlays/
└── infrastructure/
├── networking/
├── storage/
└── monitoring/apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../apps/web-app/overlays/production
- ../../apps/api-app/overlays/production
- ../../infrastructure/monitoringapiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
namespace: production
replicas:
- name: web-app
count: 3
images:
- name: web-app
newTag: "v1.0.0"
commonLabels:
environment: productionapiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/gitops-repo
targetRevision: main
path: apps/web-app/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=trueapiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: full-stack
namespace: argocd
spec:
project: default
sources:
- repoURL: https://github.com/your-org/gitops-repo
targetRevision: main
path: apps/web-app/overlays/production
- repoURL: https://github.com/your-org/gitops-repo
targetRevision: main
path: apps/api-app/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: trueapiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: web-app
namespace: flux-system
spec:
interval: 10m
sourceRef:
kind: GitRepository
name: gitops-repo
path: ./apps/web-app/overlays/production
prune: true
wait: trueapiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: gitops-repo
namespace: flux-system
spec:
interval: 1m
url: https://github.com/your-org/gitops-repo
ref:
branch: main
secretRef:
name: git-credentials# Edit deployment
vim apps/web-app/overlays/production/kustomization.yaml
# Commit changes
git add apps/web-app/overlays/production/kustomization.yaml
git commit -m "Increase web-app replicas to 5"
git push origin mainArgoCD or Flux automatically detects the Git commit.
# ArgoCD syncs automatically
argocd app sync web-app
# Or Flux reconciles automatically
flux reconcile kustomization web-appThe cluster is updated to match the Git state.
git checkout -b feature/increase-replicas# Update configuration
vim apps/web-app/overlays/production/kustomization.yamlgit push origin feature/increase-replicas
# Create PR on GitHubTeam reviews changes in PR.
# After approval, merge PR
git merge feature/increase-replicas
git push origin mainGitOps tool automatically applies changes to cluster.
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../apps/web-app/overlays/dev
- ../../apps/api-app/overlays/dev
namespace: devapiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../apps/web-app/overlays/production
- ../../apps/api-app/overlays/production
namespace: productionapiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: dev-cluster
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/gitops-repo
targetRevision: main
path: clusters/dev
destination:
server: https://kubernetes.default.svc
syncPolicy:
automated:
prune: true
selfHeal: trueapiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: prod-cluster
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/gitops-repo
targetRevision: main
path: clusters/production
destination:
server: https://kubernetes.default.svc
syncPolicy:
automated:
prune: true
selfHeal: trueProblem: Some changes applied manually, others through GitOps.
# DON'T DO THIS - Manual changes bypass GitOps
kubectl apply -f deployment.yaml
kubectl set image deployment/web-app web-app=myapp:2.0Solution: All changes through Git:
# Update Git
vim apps/web-app/overlays/production/kustomization.yaml
git commit -m "Update image to 2.0"
git pushProblem: Anyone can push directly to main.
Solution: Require pull requests and reviews:
# Require pull request reviews
# Require status checks to pass
# Require branches to be up to dateProblem: Sensitive data exposed in Git.
# DON'T DO THIS - Secrets in Git
apiVersion: v1
kind: Secret
metadata:
name: db-secret
data:
password: c2VjcmV0MTIz # base64 encodedSolution: Use secret management tools:
# Use ArgoCD Sealed Secrets or External Secrets Operator
# Store secrets in external vaultProblem: Broken configurations deployed to production.
Solution: Test before merging:
# Validate YAML
kustomize build apps/web-app/overlays/production
# Run tests
kubectl apply -k apps/web-app/overlays/production --dry-run=clientProblem: Cluster drifts from Git state.
Solution: Monitor sync status:
# Check ArgoCD sync status
argocd app get web-app
# Check Flux reconciliation
flux get kustomization web-app# Never push directly to main
git checkout -b feature/my-change
# Make changes
git push origin feature/my-change
# Create PR, get review, mergegitops-repo/
├── clusters/
├── apps/
└── infrastructure/apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argocd
data:
policy.default: role:readonly
policy.csv: |
p, role:admin, applications, *, */*, allow
p, role:dev, applications, get, dev/*, allow
g, developers, role:dev# Monitor sync status
argocd app list
# Check for drift
argocd app diff web-app
# Set up alerts for sync failuresgitops-repo/
├── infrastructure/
│ ├── networking/
│ ├── storage/
│ └── monitoring/
├── apps/
└── clusters/# GitOps Repository
## Structure
- `clusters/` - Cluster configurations
- `apps/` - Application configurations
- `infrastructure/` - Infrastructure configurations
## Workflow
1. Create feature branch
2. Make changes
3. Create pull request
4. Get review
5. Merge to main
6. GitOps tool syncs automatically| Aspect | GitOps | Traditional |
|---|---|---|
| Source of Truth | Git | Manual commands |
| Audit Trail | Full Git history | Limited logs |
| Rollback | Git revert | Manual |
| Collaboration | Pull requests | Ad-hoc |
| Automation | Continuous | Manual |
| Disaster Recovery | Git clone | Manual restore |
| Compliance | Auditable | Difficult |
# Check application status
argocd app list
argocd app get web-app
# Check sync status
argocd app sync web-app
# View application details
argocd app info web-app# Check reconciliation status
flux get kustomization
flux get helmrelease
# Check source status
flux get source git
# View reconciliation logs
flux logs --all-namespaces --followIn episode 40, we've explored GitOps in Kubernetes in depth. We've learned GitOps principles, tools like ArgoCD and Flux, and best practices for implementing GitOps workflows.
Key takeaways:
GitOps transforms how you manage Kubernetes deployments by making Git the single source of truth and automating synchronization.
Note
If you want to continue to the next episode, you can click the Episode 41 thumbnail below