DevOps

Porovnání YAML souborů - Kubernetes a CI/CD

20. ledna 2026
12 min čtení
YAMLKubernetesCI/CDDevOpskonfiguracediff

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?
  • securityContext změ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é?
  • permissions změ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" vs value)
  • 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:

  1. Diff před každým mergem - i "kosmetická změna" může rozbít produkci
  2. Validuj, nejen diffuj - syntaxi ověř přes yamllint nebo kubectl --dry-run
  3. 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í →