2.7 GitOps: Git как единый источник истины #
🎯 Что такое GitOps простыми словами #
GitOps — это методология, где Git репозиторий содержит полное описание желаемого состояния вашей инфраструктуры и приложений. Специальные агенты автоматически синхронизируют реальное состояние с тем, что описано в Git.
🚗 Аналогия с автопилотом #
Традиционный CI/CD = водитель:
👨💼 CI/CD system → kubectl apply → Kubernetes
↓ ↓ ↓
"Толкает" "Надеется" "Может сломаться"
GitOps = автопилот:
📋 Git → ArgoCD постоянно проверяет → Kubernetes
↓ ↓ ↓
"Описание" "Умный агент" "Всегда синхронно"
🔄 Принципы GitOps #
1. Declarative - Декларативное описание #
# Описываем ЖЕЛАЕМОЕ состояние, не шаги
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 3 # Хотим 3 пода
template:
spec:
containers:
- name: app
image: myapp:v1.2.0 # Хотим эту версию
2. Versioned - Все под версионным контролем #
# Вся инфраструктура в Git
infrastructure-repo/
├── apps/
│ ├── frontend/
│ │ └── deployment.yaml
│ └── backend/
│ └── deployment.yaml
├── infrastructure/
│ ├── monitoring/
│ └── ingress/
└── environments/
├── dev/
├── staging/
└── prod/
3. Immutable - Неизменяемость #
❌ kubectl edit deployment webapp # Изменение напрямую
✅ Изменение через Git:
1. Изменить YAML в репозитории
2. Создать Pull Request
3. После merge - ArgoCD применит изменения автоматически
4. Pulled - Агент сам забирает изменения #
Traditional Push Model:
CI/CD → проталкивает изменения → Kubernetes
GitOps Pull Model:
Git ← ArgoCD постоянно проверяет ← Kubernetes
🛠️ ArgoCD: Популярный GitOps инструмент #
🟢 Установка ArgoCD в Kubernetes #
# Создать namespace
kubectl create namespace argocd
# Установить ArgoCD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Проверить статус подов
kubectl get pods -n argocd
# Получить пароль админа
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# Port forwarding для доступа к UI
kubectl port-forward svc/argocd-server -n argocd 8080:443
Доступ к ArgoCD UI #
# Открыть браузер: https://localhost:8080
# Логин: admin
# Пароль: (из команды выше)
🎯 Практический пример: Деплой приложения через GitOps #
Структура Git репозитория #
my-app-gitops/
├── applications/
│ └── webapp/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── ingress.yaml
├── argocd-apps/
│ └── webapp-app.yaml
└── environments/
├── dev/
│ └── kustomization.yaml
├── staging/
│ └── kustomization.yaml
└── prod/
└── kustomization.yaml
🟢 Базовое приложение #
# applications/webapp/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
labels:
app: webapp
spec:
replicas: 2
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: nginx:1.21
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: webapp-service
spec:
selector:
app: webapp
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
ArgoCD Application манифест #
# argocd-apps/webapp-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: webapp
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
# Источник - Git репозиторий
source:
repoURL: https://github.com/username/my-app-gitops
targetRevision: HEAD
path: applications/webapp
# Назначение - Kubernetes кластер
destination:
server: https://kubernetes.default.svc
namespace: default
# Политики синхронизации
syncPolicy:
automated:
prune: true # Удалять ресурсы, которых нет в Git
selfHeal: true # Восстанавливать изменения вне Git
syncOptions:
- CreateNamespace=true
Применение ArgoCD приложения #
# Применить ArgoCD app
kubectl apply -f argocd-apps/webapp-app.yaml
# Посмотреть статус
kubectl get applications -n argocd
# Посмотреть детали
kubectl describe application webapp -n argocd
🟡 Продвинутый пример: Multi-environment с Kustomize #
Базовая конфигурация #
# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 1 # Базовое значение
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: myapp:latest # Будет переопределена
ports:
- containerPort: 8080
env:
- name: ENVIRONMENT
value: "base"
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
commonLabels:
version: v1.0.0
Development окружение #
# environments/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: dev
resources:
- ../../base
patchesStrategicMerge:
- deployment-patch.yaml
images:
- name: myapp
newTag: dev-latest
commonLabels:
environment: development
# environments/dev/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 1
template:
spec:
containers:
- name: webapp
env:
- name: ENVIRONMENT
value: "development"
- name: DEBUG
value: "true"
resources:
requests:
memory: "64Mi"
cpu: "100m"
Production окружение #
# environments/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
resources:
- ../../base
patchesStrategicMerge:
- deployment-patch.yaml
images:
- name: myapp
newTag: v1.2.3 # Стабильная версия
commonLabels:
environment: production
# environments/prod/deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 3 # Больше реплик в prod
template:
spec:
containers:
- name: webapp
env:
- name: ENVIRONMENT
value: "production"
- name: DEBUG
value: "false"
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
ArgoCD Apps для разных окружений #
# argocd-apps/dev-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: webapp-dev
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/username/my-app-gitops
targetRevision: HEAD
path: environments/dev
destination:
server: https://kubernetes.default.svc
namespace: dev
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
🟠 App of Apps Pattern #
Управление множественными приложениями #
# app-of-apps/root-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: app-of-apps
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/username/platform-gitops
targetRevision: HEAD
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
# apps/monitoring.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: monitoring
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/username/platform-gitops
targetRevision: HEAD
path: monitoring
destination:
server: https://kubernetes.default.svc
namespace: monitoring
syncPolicy:
automated:
prune: true
selfHeal: true
🔴 Продвинутые возможности ArgoCD #
Custom Health Checks #
# argocd-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
resource.customizations.health.argoproj.io_Rollout: |
hs = {}
if obj.status ~= nil then
if obj.status.replicas ~= nil and obj.status.updatedReplicas ~= nil and obj.status.availableReplicas ~= nil then
if obj.status.replicas == obj.status.updatedReplicas and obj.status.replicas == obj.status.availableReplicas then
hs.status = "Healthy"
hs.message = "Rollout is healthy"
return hs
end
end
end
hs.status = "Progressing"
hs.message = "Waiting for rollout to finish"
return hs
Pre/Post Sync Hooks #
apiVersion: batch/v1
kind: Job
metadata:
name: database-migration
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
template:
spec:
containers:
- name: migration
image: migrate/migrate
command: ["migrate", "-path", "/migrations", "-database", "postgres://...", "up"]
restartPolicy: Never
Sync Waves для упорядочивания #
# Сначала применить ConfigMaps
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
annotations:
argocd.argoproj.io/sync-wave: "1"
data:
config.yaml: |
database:
host: postgres
---
# Потом Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
annotations:
argocd.argoproj.io/sync-wave: "2"
spec:
# ... спецификация
🔄 Flux: Альтернатива ArgoCD #
Flux v2 архитектура #
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Source │ │ Kustomize │ │ Helm │
│ Controller │ │ Controller │ │ Controller │
│ │ │ │ │ │
│ Git, Helm Repo, │ │ Kustomizations │ │ Helm Releases │
│ Bucket Sources │ │ │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│ │ │
└────────────────────────┼────────────────────────┘
│
┌─────────────────────────┐
│ Notification │
│ Controller │
│ │
│ Slack, Discord, │
│ Webhook notifications │
└─────────────────────────┘
Установка Flux #
# Установить Flux CLI
curl -s https://fluxcd.io/install.sh | sudo bash
# Проверить prerequisite
flux check --pre
# Bootstrap в Git репозиторий
flux bootstrap github \
--owner=username \
--repository=fleet-infra \
--branch=main \
--path=./clusters/my-cluster \
--personal
Flux GitRepository и Kustomization #
# GitRepository resource
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
name: webapp-source
namespace: flux-system
spec:
interval: 1m
ref:
branch: main
url: https://github.com/username/webapp-config
---
# Kustomization resource
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: webapp
namespace: flux-system
spec:
interval: 10m
path: "./kustomize"
prune: true
sourceRef:
kind: GitRepository
name: webapp-source
targetNamespace: default
🔐 Безопасность в GitOps #
Sealed Secrets для безопасного хранения секретов #
# Установка Sealed Secrets controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.18.0/controller.yaml
# Установка kubeseal CLI
wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.18.0/kubeseal-0.18.0-linux-amd64.tar.gz
tar -xzf kubeseal-0.18.0-linux-amd64.tar.gz
sudo install -m 755 kubeseal /usr/local/bin/kubeseal
Создание SealedSecret #
# Создать обычный Secret
echo -n mypassword | kubectl create secret generic mysecret --dry-run=client --from-file=password=/dev/stdin -o yaml > mysecret.yaml
# Зашифровать Secret
kubeseal -f mysecret.yaml -w mysealedsecret.yaml
# Теперь можно безопасно коммитить mysealedsecret.yaml в Git
# mysealedsecret.yaml (пример результата)
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: mysecret
namespace: default
spec:
encryptedData:
password: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEQAx...
template:
metadata:
name: mysecret
namespace: default
RBAC для GitOps операторов #
# ArgoCD RBAC
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argocd
data:
policy.default: role:readonly
policy.csv: |
# DevOps team - full access
g, devops-team, role:admin
# Developers - read only
g, developers, role:readonly
# Only senior developers can sync
g, senior-developers, role:sync
# Custom role for app-specific access
p, role:app-admin, applications, *, */*, allow
p, role:app-admin, repositories, *, *, allow
g, app-team, role:app-admin
📊 Мониторинг GitOps #
Prometheus метрики ArgoCD #
# ServiceMonitor для ArgoCD
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: argocd-metrics
namespace: argocd
spec:
selector:
matchLabels:
app.kubernetes.io/name: argocd-metrics
endpoints:
- port: metrics
Grafana дашборд для ArgoCD #
{
"dashboard": {
"title": "ArgoCD Overview",
"panels": [
{
"title": "Application Health",
"type": "stat",
"targets": [
{
"expr": "argocd_app_health_status",
"legendFormat": "{{name}} - {{health_status}}"
}
]
},
{
"title": "Sync Status",
"type": "piechart",
"targets": [
{
"expr": "count by (sync_status) (argocd_app_info)",
"legendFormat": "{{sync_status}}"
}
]
}
]
}
}
Alerting правила #
# PrometheusRule для ArgoCD
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: argocd-alerts
spec:
groups:
- name: argocd
rules:
- alert: ArgoCDAppNotSynced
expr: argocd_app_info{sync_status!="Synced"} == 1
for: 15m
annotations:
summary: "ArgoCD Application не синхронизировано"
description: "Application {{ $labels.name }} в статусе {{ $labels.sync_status }} более 15 минут"
- alert: ArgoCDAppUnhealthy
expr: argocd_app_info{health_status!="Healthy"} == 1
for: 5m
annotations:
summary: "ArgoCD Application нездоровое"
description: "Application {{ $labels.name }} в статусе {{ $labels.health_status }}"
🚀 CI/CD Integration с GitOps #
GitHub Actions для обновления манифестов #
# .github/workflows/update-manifests.yml
name: Update K8s manifests
on:
push:
branches: [main]
jobs:
update-manifests:
runs-on: ubuntu-latest
steps:
- name: Checkout app repo
uses: actions/checkout@v3
- name: Build and push Docker image
run: |
docker build -t myapp:${{ github.sha }} .
docker push myapp:${{ github.sha }}
- name: Checkout config repo
uses: actions/checkout@v3
with:
repository: username/k8s-config
token: ${{ secrets.CONFIG_REPO_TOKEN }}
path: k8s-config
- name: Update image tag
run: |
cd k8s-config
sed -i "s|image: myapp:.*|image: myapp:${{ github.sha }}|" environments/staging/deployment.yaml
- name: Commit and push
run: |
cd k8s-config
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add .
git commit -m "Update image to ${{ github.sha }}"
git push
ArgoCD Image Updater #
# Автоматическое обновление образов
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: webapp
annotations:
argocd-image-updater.argoproj.io/image-list: myapp=registry.com/myapp
argocd-image-updater.argoproj.io/write-back-method: git
argocd-image-updater.argoproj.io/git-branch: main
spec:
# ... остальная конфигурация
🎯 Типичные проблемы и решения #
Проблема: Drift Detection #
# Кто-то изменил что-то напрямую в кластере
kubectl edit deployment webapp
# replicas: 2 → 3
# ArgoCD обнаружит расхождение и покажет "Out of Sync"
# Решение: включить selfHeal для автоматического восстановления
Проблема: Секреты в Git #
❌ Проблема: Где хранить database пароли?
✅ Решения:
1. Sealed Secrets - шифрование в Git
2. External Secrets Operator - интеграция с Vault/AWS Secrets
3. SOPS - шифрование файлов в Git
4. ArgoCD Vault Plugin
Проблема: Environment Promotion #
# Автоматический promotion между средами
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: webapp-prod
annotations:
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
spec:
source:
repoURL: https://github.com/username/k8s-config
targetRevision: HEAD
path: environments/prod
syncPolicy:
automated:
prune: false # Осторожнее в prod!
selfHeal: false # Ручной контроль
🏆 Лучшие практики GitOps #
1. Repository Structure #
✅ DO:
- Отдельные репозитории для кода и конфигурации
- Логическая структура директорий
- Consistent naming conventions
- Environment-specific branches/directories
❌ DON'T:
- Смешивать application code и k8s manifests
- Один монолитный репозиторий для всего
- Hardcoded values в манифестах
2. Security #
✅ DO:
- Encrypted secrets (Sealed Secrets, SOPS)
- RBAC для GitOps операторов
- Branch protection rules
- Signed commits для critical changes
❌ DON'T:
- Plain text secrets в Git
- Over-permissive RBAC
- Direct cluster access
- Unreviewed changes в prod
3. Monitoring #
✅ DO:
- Monitor sync status и health
- Alert на drift и failures
- Dashboard для операционной видимости
- Audit logs для compliance
❌ DON'T:
- Игнорировать Out of Sync статусы
- Отсутствие мониторинга GitOps операторов
- Manual interventions без логирования
🎯 Практические задания #
🟢 Задание 1: Базовый GitOps #
- Установить ArgoCD в minikube
- Создать Git репозиторий с простым приложением
- Настроить ArgoCD Application
- Сделать изменение через Git и проверить автосинхронизацию
🟡 Задание 2: Multi-environment #
- Создать структуру с base и overlays
- Настроить dev, staging, prod окружения
- Использовать разные image tags для сред
- Настроить promotion pipeline
🟠 Задание 3: Secrets Management #
- Установить Sealed Secrets controller
- Создать encrypted секреты
- Использовать их в приложениях
- Настроить rotation секретов
🔴 Задание 4: Production Setup #
- Настроить RBAC и security policies
- Создать мониторинг и алертинг
- Implement blue-green deployment
- Настроить disaster recovery
🔗 Полезные ресурсы #
Документация #
- ArgoCD Documentation - официальная документация ArgoCD
- Flux Documentation - документация Flux v2
- GitOps Principles - принципы GitOps
Инструменты #
- Kustomize - шаблонизация Kubernetes манифестов
- Sealed Secrets - безопасное хранение секретов
- SOPS - шифрование файлов
Обучение #
- GitOps Guide - гид по GitOps
- CNCF GitOps Working Group - рабочая группа
- Argo Workflows - для сложных CI/CD
🎯 Заключение #
GitOps — это эволюция DevOps практик для cloud-native мира. Основные преимущества:
✅ Single Source of Truth — Git как единственный источник истины
✅ Declarative — описываем желаемое состояние
✅ Auditable — полная история изменений
✅ Secure — контролируемый доступ через Git
✅ Recoverable — простое восстановление из Git
Помните: GitOps не заменяет CI/CD, а дополняет его. CI занимается сборкой и тестированием, GitOps — деплоем и управлением состоянием.
Следующий раздел: 2.10 Service Mesh