5 min readDe Kicked Team
GitOps: Infrastructure as Code făcut corect
GitOps înseamnă mai mult decât a ține configurările în Git. Este un model operațional complet, în care Git este singura sursă de adevăr și reconcilierea este continuă. Iată cum îl implementăm noi.
- DevOps
- GitOps
- Kubernetes
- Infrastructure
„Ținem Terraform-ul în Git” nu este GitOps. Este version control. GitOps este un model operațional în care:
- Întregul sistem este descris declarativ
- Starea dorită trăiește în Git
- Modificările se fac prin pull request-uri
- Un controller reconciliază continuu starea reală cu starea dorită
Ultimul punct este cel care separă GitOps de „configurări într-un repo”.
De ce GitOps?
Administrăm infrastructură pentru zeci de clienți. Înainte de GitOps, deploy-urile arătau așa:
Developer → SSH into server → Run commands → Hope it works → Forget what they changed
Cu GitOps:
Developer → Open PR → Review → Merge → Automated reconciliation → Drift detection
Beneficiile se adună:
- Audit trail — Fiecare modificare este un commit Git cu autor, timestamp și review
- Rollback —
git reverteste butonul tău de „undo” - Reproductibilitate — Ridici un mediu identic din același repo
- Detectarea drift-ului — Controller-ul alertează când realitatea se abate de la Git
- Self-service — Developerii pot face modificări de infrastructură prin PR-uri, fără acces SSH
Cele două pattern-uri: Push vs. Pull
Bazat pe push (CI/CD tradițional)
Git Push → CI Pipeline → kubectl apply / terraform apply → Cluster
Pipeline-ul are credențiale pentru a modifica infrastructura. Funcționează, dar are dezavantaje:
- Sistemul de CI are nevoie de acces larg la producție
- Fără reconciliere continuă — drift-ul rămâne nedetectat
- Eșecurile din pipeline pot lăsa starea aplicată parțial
Bazat pe pull (GitOps)
Git Push → Controller (in-cluster) → Detects diff → Reconciles → Cluster matches Git
Controller-ul rulează în interiorul cluster-ului și trage starea dorită din Git. Acesta este modelul GitOps.
Stack-ul nostru GitOps
ArgoCD pentru Kubernetes
ArgoCD este controller-ul nostru GitOps principal pentru workload-urile Kubernetes. Urmărește repo-urile Git și se asigură că cluster-ul le corespunde.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: production-api
namespace: argocd
spec:
project: production
source:
repoURL: https://github.com/kicked-ro/infrastructure
targetRevision: main
path: apps/production/api
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # Delete resources removed from Git
selfHeal: true # Revert manual changes
syncOptions:
- CreateNamespace=true
Alegeri-cheie de configurare:
selfHeal: true— Dacă cineva editează manual o resursă, ArgoCD o readuce la loc. Git este sursa de adevăr, întotdeauna.prune: true— Resursele șterse din Git sunt șterse din cluster. Fără resurse zombie.- Sincronizare automată — Merge-ul în
maindeclanșează deploy-ul. Fără butoane apăsate manual.
Terraform + Atlantis pentru resurse cloud
Pentru infrastructura cloud (VM-uri, DNS, networking) folosim Terraform cu Atlantis, într-un flux bazat pe PR-uri:
Developer opens PR with Terraform change
→ Atlantis runs `terraform plan`
→ Plan output posted as PR comment
→ Reviewer approves
→ Atlantis runs `terraform apply`
→ State updated, PR merged
Nimeni nu rulează terraform apply local. Niciodată.
Renovate pentru actualizarea dependențelor
Menținerea la zi a imaginilor de bază, a versiunilor de Helm chart-uri și a provider-ilor Terraform este un job cu normă întreagă. Renovate îl automatizează:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"kubernetes": {
"fileMatch": ["apps/.+\\.yaml$"]
},
"regexManagers": [
{
"fileMatch": ["apps/.+\\.yaml$"],
"matchStrings": ["image: (?<depName>.*?):(?<currentValue>.*?)\\s"],
"datasourceTemplate": "docker"
}
]
}
Renovate deschide PR-uri pentru fiecare actualizare. ArgoCD le face deploy când sunt merge-uite. Supply chain complet automatizat.
Structura repository-ului
Am ajuns la această structură după multe iterații:
infrastructure/
├── apps/
│ ├── production/
│ │ ├── api/
│ │ │ ├── deployment.yaml
│ │ │ ├── service.yaml
│ │ │ └── kustomization.yaml
│ │ ├── web/
│ │ └── workers/
│ └── staging/
│ └── ... (mirrors production)
├── platform/
│ ├── cert-manager/
│ ├── ingress-nginx/
│ ├── monitoring/
│ └── external-secrets/
├── terraform/
│ ├── networking/
│ ├── dns/
│ └── compute/
└── renovate.json
Apps sunt workload-urile. Platform este infrastructura partajată. Terraform sunt resursele de la nivelul cloud. Fiecare director este o ArgoCD Application.
Secretele în GitOps
Singurul lucru pe care nu îl poți pune în Git: secretele. Abordarea noastră:
- Sealed Secrets — Criptezi secretele cu o cheie specifică cluster-ului. Versiunea criptată trăiește în Git. Doar cluster-ul le poate decripta.
- External Secrets Operator — Referențiezi secrete din Vault/AWS SSM. Git stochează referința, nu valoarea.
Preferăm External Secrets Operator pentru producție, pentru că rotația secretelor este automată.
Lecții învățate
- Începe cu o singură aplicație — Nu încerca să treci toată infrastructura pe GitOps în prima săptămână
- Impune selfHeal — Dacă oamenii pot ocoli Git, o vor face, iar sursa ta de adevăr devine o minciună
- Review-urile de PR sunt obligatorii — Chiar și pentru inginerul senior. Mai ales pentru inginerul senior
- Testează întâi în staging — ArgoCD ApplicationSets fac promovarea între medii trivială
- Monitorizează starea de sync — O aplicație blocată în „OutOfSync” este o bombă cu ceas
Rezultatul
De când am adoptat GitOps în toată infrastructura noastră:
- Zero modificări neautorizate în producție
- 4 minute timp mediu de deploy (de la merge la rulare)
- 100% audit trail pentru fiecare modificare de infrastructură
- Disaster recovery într-un singur click (îndrepți ArgoCD către repo, gata)
GitOps nu este doar o strategie de deploy — este o filosofie operațională. Dacă încă intri prin SSH pe servere ca să faci modificări, hai să vorbim.