Skip to main content

GitOps best practices


Table of Contents

  1. Recommended patterns
  2. Anti-patterns to avoid
  3. Security
  4. Monitoring and alerting
  5. Documentation
  6. Hands-on exercises

Separation of Concerns

gitops-repo/
├── apps/ # Équipe dev
├── infrastructure/ # Équipe platform
└── clusters/ # Équipe SRE
# Permissions RBAC par dossier
# apps/* → développeurs
# infrastructure/* → platform team
# clusters/* → SRE uniquement

Small, Frequent Commits

# ✅ Bon : Un changement par commit
git commit -m "feat(frontend): update to v2.3.0"
git commit -m "fix(backend): increase memory to 1Gi"

# ❌ Mauvais : Tout dans un commit
git commit -m "Update frontend, backend, monitoring, ingress..."

Pull Request Workflow

# Branch protection rules
- Require PR reviews (2 approvers)
- Require status checks (lint, validate)
- No force push
- No direct commits to main

GitOps Validation Pipeline

# .github/workflows/validate.yml
name: Validate GitOps

on:
pull_request:
paths:
- 'apps/**'
- 'infrastructure/**'

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Validate YAML
run: |
find . -name '*.yaml' -exec yamllint {} \;

- name: Validate Kubernetes manifests
uses: instrumenta/kubeval-action@master

- name: Kustomize build
run: |
for dir in apps/*/overlays/*/; do
kustomize build $dir > /dev/null
done

Immutable Tags

# ✅ Bon : Tags immutables
image: myapp:v1.2.3
image: myapp:sha-abc123

# ❌ Mauvais : Tags mutables
image: myapp:latest
image: myapp:dev

🔝 Back to table of contents


2 - Anti-patterns to avoid

Direct kubectl Access

# ❌ JAMAIS en production
kubectl set image deployment/myapp myapp=myapp:v2
kubectl scale deployment/myapp --replicas=10
kubectl delete pod myapp-xxx

# ✅ Toujours via Git
git checkout -b hotfix/scale-myapp
# Modifier le fichier
git commit -m "fix: scale myapp to 10"
git push && créer PR

Plaintext secrets

# ❌ JAMAIS
apiVersion: v1
kind: Secret
data:
password: bXlwYXNzd29yZA== # base64 n'est PAS sécurisé

# ✅ Utiliser Sealed Secrets, SOPS, Vault
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
spec:
encryptedData:
password: AgBj7...chiffré...

Giant mono-repo

# ❌ Tout dans un seul repo
gitops-monorepo/
├── team-a/
├── team-b/
├── team-c/
├── ... 50 équipes ...
└── infrastructure/

# ✅ Séparer par domaine/équipe
org/gitops-platform
org/gitops-team-a
org/gitops-team-b

Lack of validation

# ❌ Pas de CI sur les manifests
# → Erreurs détectées en production

# ✅ Pipeline de validation
- yamllint
- kubeval / kubeconform
- kustomize build
- helm template
- Policy checks (OPA/Kyverno)

Constant manual sync

# ❌ Sync manuel = pas vraiment GitOps
syncPolicy: {} # Pas d'automated

# ✅ Auto-sync avec self-heal
syncPolicy:
automated:
prune: true
selfHeal: true

🔝 Back to table of contents


3 - Security

Principle of least privilege

# GitOps controller avec permissions limitées
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gitops-controller
rules:
# Seulement ce qui est nécessaire
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
# PAS de delete sur certaines ressources

Audit and traceability

# Tout est dans Git
git log --oneline --since="2024-01-01"
# a1b2c3d deploy v2.0 - [email protected]
# d4e5f6g scale to 5 - [email protected]

# Git blame
git blame apps/myapp/deployment.yaml

Signed Commits

# Configurer GPG signing
git config --global commit.gpgsign true
git config --global user.signingkey YOUR_KEY_ID

# Vérifier les signatures
git log --show-signature
# ArgoCD - Exiger des commits signés
apiVersion: argoproj.io/v1alpha1
kind: Application
spec:
source:
repoURL: ...
syncPolicy:
automated: {}
# + GPG verification dans ArgoCD settings

Network Policies

# Limiter les connexions du controller
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: gitops-controller
spec:
podSelector:
matchLabels:
app: argocd-repo-server
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
ports:
- port: 443
protocol: TCP

🔝 Back to table of contents


4 - Monitoring and alerting

GitOps metrics

MetricDescription
Sync StatusApplications in-sync vs out-of-sync
Sync DurationReconciliation time
Drift CountNumber of drifts detected
Failed SyncsSynchronization failures

ArgoCD Metrics

# ServiceMonitor pour Prometheus
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: argocd-metrics
spec:
selector:
matchLabels:
app.kubernetes.io/name: argocd-server
endpoints:
- port: metrics

Alerting

# PrometheusRule
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: gitops-alerts
spec:
groups:
- name: gitops
rules:
- alert: AppOutOfSync
expr: argocd_app_info{sync_status="OutOfSync"} == 1
for: 5m
labels:
severity: warning
annotations:
summary: "Application {{ $labels.name }} is out of sync"

- alert: AppDegraded
expr: argocd_app_info{health_status="Degraded"} == 1
for: 5m
labels:
severity: critical

Notifications

# ArgoCD Notifications
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
data:
service.slack: |
token: $slack-token
template.app-sync-failed: |
message: |
Application {{.app.metadata.name}} sync failed.
Error: {{.app.status.operationState.message}}
trigger.on-sync-failed: |
- send: [app-sync-failed]
when: app.status.operationState.phase in ['Error', 'Failed']

🔝 Back to table of contents


5 - Documentation

README in each folder

# apps/myapp/README.md

## MyApp

Description de l'application.

### Environnements

| Env | Namespace | Replicas |
|-----|-----------|----------|
| Dev | dev | 1 |
| Prod | production | 5 |

### Déploiement

Pour déployer une nouvelle version :
1. Modifier `overlays/<env>/kustomization.yaml`
2. Créer une PR
3. Attendre la review
4. Merge = déploiement automatique

### Rollback

```bash
git revert HEAD
git push

### Architecture Decision Records (ADR)

```markdown
# docs/adr/001-gitops-tool-selection.md

# ADR 001: Choix de l'outil GitOps

## Status
Accepted

## Context
Nous devons choisir un outil GitOps pour gérer nos déploiements K8s.

## Decision
Nous utilisons ArgoCD car :
- UI native importante pour nos développeurs
- CNCF Graduated
- Grande communauté

## Consequences
- Formation nécessaire pour l'équipe
- Installation et maintenance du controller

Runbooks

# docs/runbooks/sync-failed.md

# Runbook: Application Sync Failed

## Symptôme
Alerte `AppSyncFailed` déclenchée

## Diagnostic
1. Vérifier l'état ArgoCD
```bash
argocd app get <app-name>
  1. Voir les logs
    argocd app logs <app-name>

Résolution

  • Si erreur de manifest : corriger dans Git
  • Si erreur réseau : vérifier la connectivité
  • Si ressource bloquée : voir les events K8s

#### [🔝 Back to table of contents](#table-des-matieres)


---

<a name="exercices"></a>

## 6 - Hands-on exercises

### Quiz

**Q1.** Why should you never use `kubectl` directly in production?

<details>
<summary>Answer</summary>

- No traceability (who did what?)
- Causes **drift** (cluster state ≠ Git)
- No review process
- Self-healing will revert the change
- Not reproducible

</details>

**Q2.** Why avoid `latest` tags?

<details>
<summary>Answer</summary>

- **Not reproducible**: `latest` changes over time
- **No rollback**: impossible to go back
- **Difficult audit**: which version is really running?
- Use **immutable** tags: `v1.2.3`, `sha-abc123`

</details>

### Exercise: GitOps checklist

Create a checklist to validate your GitOps setup:

<details>
<summary>Complete checklist</summary>

**Repository**
- README in each folder
- .gitignore configured
- Branch protection enabled
- Mandatory PR reviews

**CI/CD**
- YAML validation (yamllint)
- K8s validation (kubeval)
- Kustomize/Helm build test
- Policy checks

**Security**
- Encrypted secrets (Sealed Secrets/SOPS)
- No plaintext credentials
- RBAC configured
- Signed commits (optional)

**Monitoring**
- GitOps metrics exposed
- Alerts configured
- Slack/Teams notifications

**Documentation**
- ADR for decisions
- Runbooks for incidents
- Architecture diagrams

</details>

#### [🔝 Back to table of contents](#table-des-matieres)


---

## Key takeaways

- **Patterns**: Small commits, PR workflow, immutable tags
- **Anti-patterns**: direct kubectl, plaintext secrets, no validation
- **Security**: Least privilege, signed commits, audit trail
- **Monitoring**: Sync metrics, drift alerts
- **Documentation**: README, ADR, runbooks

#### [🔝 Back to table of contents](#table-des-matieres)

---

[← Previous chapter](./08-multi-environnements.md) | [Next chapter: Exercises →](./10-exercices-projets.md)