Porovnání YAML souborů - Kubernetes a CI/CD
Minulý měsíc mi spadla produkce. Důvod? Kolega upravil YAML deployment a posunul jednu sekci o dvě mezery. Syntakticky validní, sémanticky katastrofa. Od té doby před každým mergem YAML configů používám diff.
Proč to vůbec řeším
YAML je všude - Kubernetes, GitHub Actions, Docker Compose, Helm. A ta jedna špatná mezera? Ta vám položí celý cluster.
Typické situace kdy sáhnu po diffu:
- Kolega poslal PR - co vlastně změnil v tom deploymentu?
- Staging vs produkce - před deployem chci vidět co je jinak
- "Včera to fungovalo" - klasika, porovnám co běželo předtím
- Helm upgrade - co se změnilo ve values?
Ta záludnost s mezerami
Tady je to nejdůležitější co jsem se naučil: v YAML záleží na každé mezeře. Tohle vypadá skoro stejně:
# Soubor A - korektní
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
key: value
# Soubor B - broken (špatné odsazení)
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
key: value
Diff ti okamžitě ukáže posun data: pod metadata: - a ušetří ti hodinu debugování.
Pipe vs šipka (a proč na tom záleží)
Tohle mě jednou taky dostalo:
# Pipe - zachová newlines
script: |
echo "Hello"
echo "World"
# Šipka - spojí řádky
description: >
Toto je dlouhý
popis na více řádků.
Změna | na > v CI scriptu = nefungující pipeline. Diff to ale hned ukáže.
Anchory - skrytá past
Tohle je záludné. YAML umí "znovupoužít" hodnoty:
defaults: &defaults
timeout: 30
retries: 3
production:
<<: *defaults
timeout: 60
Změníš &defaults a změní se to všude kde se používá *defaults. Někdy to chceš, někdy ne.
Co sleduju v Kubernetes manifestech
Tady je můj checklist - na tohle se při review zaměřuju nejvíc:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3 # Počet replik
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Strategie update
maxUnavailable: 0
template:
spec:
containers:
- name: app
image: myapp:v2.1.0 # Verze image - KRITICKÉ
resources:
requests:
memory: "256Mi" # Resource requests
cpu: "100m"
limits:
memory: "512Mi" # Resource limits
cpu: "500m"
env:
- name: DATABASE_URL # Environment variables
valueFrom:
secretKeyRef:
name: db-secret
key: url
Na co si dávám pozor
Červená vlajka (vždycky se ptám proč):
- Změna
image:tagu - nová verze? Testovaná? - Úprava
resources.limits- přestane to stačit? securityContextzměny - neotevíráme díru?- Volumes - přístup k novým datům?
Pozornost:
- Změna
replicas- kapacita? - Nové env proměnné - existují na produkci?
V pohodě:
- Labels, annotations, metadata - většinou OK
Service a Ingress - pozor na to
Service a Ingress změny jsou záludné - hned ovlivní produkci. Když v diffu vidím změnu portu nebo selectoru, dvakrát zkontroluju jestli to odpovídá deploymentu.
CI/CD - co v diffu hledám
GitHub Actions (používám denně)
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to production
run: ./deploy.sh
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
Při review GitHub Actions koukám hlavně na:
Security (tady jsem paranoidní):
- Nové
secrets- proč? Máme je nastavené? permissionszměny - neotevíráme si díru?- Nové external actions - důvěryhodné?
Funkčnost:
if:podmínky - kdy to běží?needs:- správné pořadí?on:triggery - nespustí se náhodou na každém pushu?
GitLab CI
stages:
- test
- build
- deploy
variables:
DOCKER_IMAGE: registry.example.com/myapp
test:
stage: test
image: node:20
script:
- npm ci
- npm test
coverage: '/Coverage: \d+\.\d+%/'
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHA .
- docker push $DOCKER_IMAGE:$CI_COMMIT_SHA
deploy:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl set image deployment/myapp app=$DOCKER_IMAGE:$CI_COMMIT_SHA
only:
- main
environment:
name: production
url: https://app.example.com
Jenkins Pipeline (Jenkinsfile)
I když Jenkinsfile používá Groovy, mnoho týmů definuje konfiguraci v YAML:
# jenkins-config.yaml
pipeline:
agent: any
stages:
- name: Build
steps:
- sh: npm install
- sh: npm run build
- name: Test
steps:
- sh: npm test
- name: Deploy
when:
branch: main
steps:
- sh: ./deploy.sh
Helm Charts
Helm charts kombinují YAML šablony s hodnotami – porovnávání zde má svá specifika.
values.yaml
# values.yaml
replicaCount: 3
image:
repository: myapp
tag: "v2.1.0"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
ingress:
enabled: true
className: nginx
hosts:
- host: app.example.com
paths:
- path: /
pathType: Prefix
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 80
Porovnání prod vs staging values
Typický workflow je porovnání values-staging.yaml vs values-production.yaml:
# values-staging.yaml
replicaCount: 1
resources:
limits:
memory: 256Mi
# values-production.yaml
replicaCount: 3
resources:
limits:
memory: 1Gi
Diff vám ukáže všechny rozdíly, které musíte zohlednit při promotion do produkce.
Docker Compose
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://db:5432/app
depends_on:
- db
- redis
deploy:
replicas: 2
resources:
limits:
memory: 512M
db:
image: postgres:15
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: app
POSTGRES_USER: user
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
secrets:
db_password:
file: ./secrets/db_password.txt
Terraform YAML konfigurace
Ačkoli Terraform primárně používá HCL, mnoho týmů definuje variables v YAML:
# terraform.tfvars.yaml
environment: production
vpc:
cidr: "10.0.0.0/16"
availability_zones:
- eu-central-1a
- eu-central-1b
- eu-central-1c
eks:
cluster_name: prod-cluster
cluster_version: "1.28"
node_groups:
- name: workers
instance_types:
- t3.large
desired_size: 3
min_size: 2
max_size: 10
rds:
instance_class: db.r6g.large
engine_version: "15.4"
allocated_storage: 100
multi_az: true
Praktické tipy pro YAML diff
1. Normalizace před porovnáním
Před porovnáním YAML souborů je užitečné je normalizovat:
# Pomocí yq (YAML processor)
yq eval '.' file.yaml > normalized.yaml
# Seřazení klíčů abecedně
yq eval 'sort_keys(..)' file.yaml
2. Ignorování nepodstatných změn
Některé změny jsou kosmetické:
- Přeuspořádání klíčů na stejné úrovni
- Změna uvozovek (
"value"vsvalue) - Trailing whitespace
3. Sémantické vs syntaktické porovnání
Syntakticky různé, sémanticky stejné:
# Varianta A
ports:
- port: 80
targetPort: 8080
# Varianta B
ports:
- port: 80
targetPort: 8080
Oba zápisy jsou ekvivalentní, ale diff je zobrazí jako různé.
4. Komentáře v YAML
YAML komentáře (#) nejsou součástí dat, ale pro code review jsou důležité:
resources:
limits:
memory: 512Mi # Zvýšeno z 256Mi kvůli OOM
Workflow pro code review YAML změn
1. Rychlá vizuální kontrola
Použijte diff nástroj pro přehled změn. Zaměřte se na:
- Počet změněných řádků
- Které sekce jsou ovlivněny
- Zda změny odpovídají popisu PR
2. Validace syntaxe
# Kubernetes
kubectl apply --dry-run=client -f manifest.yaml
# Generic YAML
yamllint manifest.yaml
# Helm
helm lint ./chart
3. Sémantická kontrola
- Odpovídají změny záměru?
- Jsou dodrženy best practices?
- Nejsou přítomny security issues?
4. Impact analýza
- Které služby budou ovlivněny?
- Je potřeba koordinace s jinými týmy?
- Jaký je rollback plán?
Časté chyby a jak je odhalit
1. Špatné odsazení
# Špatně - env je součástí image
containers:
- name: app
image: myapp:v1
env: # <- Mělo by být odsazeno
- name: DEBUG
value: "true"
2. Chybějící pomlčka v seznamu
# Špatně
containers:
name: app # <- Chybí pomlčka
# Správně
containers:
- name: app
3. Typ hodnoty
# Může způsobit problémy
replicas: "3" # String místo integeru
enabled: "true" # String místo booleanu
# Správně
replicas: 3
enabled: true
4. Secrets v YAML
# NIKDY necommitujte!
database:
password: super_secret_password123
# Správně - reference na secret
database:
passwordSecretRef:
name: db-credentials
key: password
Best practices
1. Verzování a historie
- Vždy commitujte YAML změny s popisným commit message
- Používejte feature branches pro větší změny
- Tagujte release verze
2. Struktura repozitáře
k8s/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── development/
│ └── kustomization.yaml
├── staging/
│ └── kustomization.yaml
└── production/
└── kustomization.yaml
3. GitOps workflow
- Změny v YAML = změny v infrastruktuře
- Automatické deployment po merge
- Audit trail prostřednictvím Git historie
4. Pre-commit hooks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/adrienverge/yamllint
rev: v1.32.0
hooks:
- id: yamllint
args: [-c=.yamllint.yaml]
- repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt
rev: 0.2.3
hooks:
- id: yamlfmt
Co jsem se naučil
Po letech práce s YAML configy mám tři pravidla:
- Diff před každým mergem - i "kosmetická změna" může rozbít produkci
- Validuj, nejen diffuj - syntaxi ověř přes
yamllintnebokubectl --dry-run - Komentuj proč, ne co - v commit message piš důvod změny
Ten incident z úvodu? Kdybych se podíval na diff pořádně, uviděl bych ten posun. Teď už vím líp.
Potřebuješ rychle porovnat dva YAML soubory? Hoď je do PorovnejText - běží to v prohlížeči a data nikam neposílám.
Vyzkoušejte PorovnejText.cz zdarma
Nejrychlejší český nástroj pro porovnání textů. Vše probíhá ve vašem prohlížeči, žádná registrace není potřeba.
Porovnat texty nyní →Související články
Jak automatizuju changelog z Git commitů
Ruční psaní release notes mě nebavilo. Tady je jak jsem to automatizoval pomocí Conventional Commits.
Jak kontroluju config soubory před deployem
Jedna špatná změna v YAML a máte outage. Tady je jak porovnávám konfigurace mezi prostředími.
XML konfiguráky - jak je porovnat bez bolesti hlavy
Praktické tipy na porovnávání XML souborů. Od Spring configu přes Maven POM po .NET app.config - co funguje a na co si dát pozor.