Modern DevOps Engineering
Chapitre 13
13 - GitOps
13 - GitOps
Chapitre 13 : GitOps
13.1 Introduction a GitOps
13.1.1 Definition et principes
Le GitOps est une methodologie de gestion d'infrastructure et d'applications qui utilise Git comme source de verite unique. Les trois principes fondamentaux sont :
- Declaratif : L'etat desire du systeme est decrit de maniere declarative
- Versionne : L'etat desire est stocke dans Git (historique, audit, rollback)
- Synchronisation automatique : Un operateur maintient en permanence l'etat du cluster conforme a Git
13.1.2 GitOps vs CI/CD traditionnel
| Aspect | CI/CD Traditionnel | GitOps |
|---|---|---|
| Source de verite | Pipeline CI | Repository Git |
| Mode de deploiement | Push (CI push vers cluster) | Pull (operateur pull depuis Git) |
| Rollback | Commande manuelle | Git revert |
| Audit | Logs de pipeline | Git history |
| Acces cluster | CI a besoin d'acces | Operateur a acces, pas CI |
| Derive de configuration | Possible | Detectee et corrigee |
13.1.3 Architecture GitOps
Git Repository
│
Git Push / Pull Request
│
v
GitOps Operator
(ArgoCD / Flux)
│ │
v v
┌────────┴────────┐
│ Kubernetes │
│ Cluster │
└─────────────────┘
13.2 ArgoCD
13.2.1 Architecture ArgoCD
ArgoCD est un GitOps operator CNCF graduate :
User ──> ArgoCD API / UI ──> Git Repository
│ │
│ Poll / Webhook
│ │
v v
Kubernetes ────────── Sync Status
│
v
Applications (Deployments, Services, etc.)
Composants :
- API Server : Interface gRPC/REST
- Repository Server : Clone et cache les repos Git
- Application Controller : Maintient la synchronisation
- Redis : Cache
13.2.2 Installation
# Installation avec Helm
helm repo add argo https://argoproj.github.io/argo-helm
helm upgrade --install argocd argo/argo-cd \
--namespace argocd --create-namespace \
--set server.ingress.enabled=true \
--set server.ingress.hosts=["argocd.example.com"]
# Obtenir le mot de passe admin
kubectl get secret argocd-initial-admin-secret \
-n argocd -o jsonpath="{.data.password}" | base64 -d
13.2.3 Application et ApplicationSet
Application simple :
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/company/myapp-config.git
targetRevision: main
path: kubernetes/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- PruneLast=true
ApplicationSet (multi-cluster/multi-env) :
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: myapp-multi-env
spec:
generators:
- list:
elements:
- cluster: production
url: https://kubernetes.default.svc
namespace: prod
- cluster: staging
url: https://staging-cluster.example.com
namespace: stg
template:
metadata:
name: 'myapp-{{cluster}}'
spec:
project: default
source:
repoURL: https://github.com/company/myapp-config.git
targetRevision: main
path: 'kubernetes/overlays/{{cluster}}'
destination:
server: '{{url}}'
namespace: '{{namespace}}'
13.2.4 Sync Waves et Hooks
Les Sync Waves permettent d'ordonner le deploiement :
# ConfigMap (wave 0)
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
annotations:
argocd.argoproj.io/sync-wave: "0"
data:
config.yaml: |
key: value
---
# Deployment (wave 1)
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
annotations:
argocd.argoproj.io/sync-wave: "1"
spec:
template:
spec:
containers:
- name: app
image: myapp:latest
---
# Service (wave 2)
apiVersion: v1
kind: Service
metadata:
name: myapp
annotations:
argocd.argoproj.io/sync-wave: "2"
spec:
ports:
- port: 80
PreSync / PostSync Hooks :
apiVersion: batch/v1
kind: Job
metadata:
name: db-migration
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
template:
spec:
containers:
- name: migration
image: myapp-migration:latest
command: ["alembic", "upgrade", "head"]
restartPolicy: Never
13.2.5 Rollback
# Rollback via CLI
argocd app rollback myapp 3
# Rollback via UI
# Applications > myapp > HISTORY AND ROLLBACK > Select revision > ROLLBACK
# Rollback via Git (recommandé)
git revert HEAD
git push origin main
# ArgoCD va automatiquement synchroniser
13.3 Flux
13.3.1 Architecture Flux
Flux est un GitOps operator developpe par Weaveworks :
Git Repository ──> Source Controller
│
Notification Controller
│
┌─────────┴─────────┐
│ │
KustomizeController HelmController
│ │
v v
Kubernetes Helm Releases
Composants :
- Source Controller : Gere les sources (Git, Helm, S3)
- KustomizeController : Applique les manifests Kustomize
- HelmController : Gere les releases Helm
- NotificationController : Notifications Slack, Teams, etc.
13.3.2 Installation
# Installation avec CLI
curl -s https://fluxcd.io/install.sh | bash
flux bootstrap github \
--owner=company \
--repository=flux-config \
--path=clusters/production \
--personal
# Verification
flux check
13.3.3 KustomizeController
# kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: myapp
namespace: flux-system
spec:
interval: 5m
path: ./kubernetes/overlays/production
prune: true
sourceRef:
kind: GitRepository
name: myapp-source
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: myapp
namespace: production
postBuild:
substitute:
environment: production
region: eu-west-1
13.3.4 HelmController
# helm-release.yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: myapp
namespace: production
spec:
interval: 5m
chart:
spec:
chart: myapp
sourceRef:
kind: HelmRepository
name: myapp-charts
interval: 1h
values:
replicaCount: 3
image:
tag: 1.2.3
ingress:
enabled: true
hosts:
- myapp.example.com
13.3.5 NotificationController
# notification.yaml
apiVersion: notification.toolkit.fluxcd.io/v1beta2
kind: Alert
metadata:
name: slack-alerts
namespace: flux-system
spec:
providerRef:
name: slack
eventSeverity: info
eventSources:
- kind: Kustomization
name: '*'
---
apiVersion: notification.toolkit.fluxcd.io/v1beta2
kind: Provider
metadata:
name: slack
namespace: flux-system
spec:
type: slack
address: https://hooks.slack.com/services/T00/B00/xxxxx
13.4 Kustomize
13.4.1 Structure de projet
Kustomize permet de personnaliser des manifests sans templates :
kubernetes/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ └── service.yaml
└── overlays/
├── development/
│ ├── kustomization.yaml
│ └── patch-replicas.yaml
└── production/
├── kustomization.yaml
├── patch-replicas.yaml
└── ingress.yaml
13.4.2 Base
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
commonLabels:
app: myapp
managed-by: kustomize
commonAnnotations:
version: 1.0.0
environment: base
# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: myapp:latest
ports:
- containerPort: 8080
13.4.3 Overlays
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
- ingress.yaml
patches:
- path: patch-replicas.yaml
target:
kind: Deployment
name: myapp
configMapGenerator:
- name: app-config
literals:
- ENVIRONMENT=production
- LOG_LEVEL=info
images:
- name: myapp
newTag: 1.2.3
namespace: production
# overlays/production/patch-replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
# overlays/production/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
number: 80
13.5 Helm
13.5.1 Structure d'un Chart
myapp-chart/
├── Chart.yaml
├── values.yaml
├── values.production.yaml
├── templates/
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── hpa.yaml
│ └── tests/
│ └── test-connection.yaml
└── charts/
└── redis-*.tgz
13.5.2 Chart.yaml et valeurs
# Chart.yaml
apiVersion: v2
name: myapp
description: A Helm chart for Kubernetes
type: application
version: 0.1.0
appVersion: "1.16.0"
dependencies:
- name: redis
version: "17.x"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled
# values.yaml
replicaCount: 1
image:
repository: myregistry.io/myapp
tag: latest
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
targetPort: 8080
ingress:
enabled: false
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 200m
memory: 256Mi
13.5.3 Templates
# templates/_helpers.tpl
{{- define "myapp.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "myapp.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "myapp.fullname" . }}
labels:
{{- include "myapp.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "myapp.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "myapp.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- containerPort: {{ .Values.service.targetPort }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
- name: ENVIRONMENT
value: {{ .Values.environment | quote }}
13.6 Resume
- GitOps utilise Git comme source de verite unique pour l'infrastructure
- ArgoCD est le GitOps operator le plus populaire
- Flux offre une alternative avec des controllers specialises
- Kustomize permet de personnaliser les manifests sans templates
- Helm est le gestionnaire de paquets standard pour Kubernetes
- Les Sync Waves et Hooks permettent d'ordonner les deploiements
- L'ApplicationSet permet de deployer sur multiples clusters/environnements
- GitOps + CI/CD = Pipeline CI pour build + GitOps pour deploy