Modern QA2026Валидация манифестов Kubernetes
Join

Course08 Infrastructure as Code Testing

Cutting-edge · Chapter 08

Валидация манифестов Kubernetes

Updated Jul 2026

Проблема: Kubernetes принимает практически всё

Kubernetes поразительно терпим к тому, что принимает. Deployment без лимитов ресурсов, без проверок здоровья, запущенный от root, с тегом latest успешно развернётся. Kubernetes не предупредит вас, что он будет вести себя плохо — он просто сделает то, что вы попросили, а последствия вы обнаружите в продакшене.

Инструменты валидации манифестов выявляют эти ошибки конфигурации до того, как они попадут в кластер. Они обеспечивают соблюдение лучших практик, которые Kubernetes сам по себе не требует, но которые необходимы для промышленной эксплуатации.

Сравнение инструментов валидации

Инструмент Фокус Подход Поддержка CRD Скорость
kubeval Валидация схемы Проверка по API-схемам K8s Ограниченная Быстро
kubeconform Валидация схемы Быстрая замена kubeval Да (через плагины) Очень быстро
kube-score Лучшие практики Опинионированные проверки (безопасность, надёжность) Нет Быстро
Polaris Применение политик Движок политик Fairwinds Да Быстро
Datree Применение политик Встроенные + пользовательские правила Да Быстро
OPA/Gatekeeper Контроль допуска Пользовательские политики Rego в кластере Да Быстро

kubeval и kubeconform

# kubeval: validates manifests against K8s API schemas
kubeval deployment.yaml --kubernetes-version 1.29.0

# kubeconform: faster kubeval replacement with CRD support
kubeconform -strict -kubernetes-version 1.29.0 deployment.yaml

# Validate all manifests in a directory
kubeconform -strict -summary k8s/

# Validate Helm-rendered templates
helm template myapp ./charts/myapp/ | kubeconform -strict

# Use with custom resource definitions
kubeconform -strict \
  -schema-location default \
  -schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' \
  k8s/

kube-score

kube-score проверяет соблюдение лучших практик, а не валидность схемы:

# Score a deployment manifest
kube-score score deployment.yaml
# Output:
# apps/v1/Deployment myapp: (CRITICAL) Container has no readiness probe
# apps/v1/Deployment myapp: (CRITICAL) No network policy matching pod
# apps/v1/Deployment myapp: (WARNING) CPU limit is not set

# Score all manifests in a directory
kube-score score k8s/*.yaml

# Output as JSON for CI parsing
kube-score score deployment.yaml --output-format json

# Ignore specific checks
kube-score score deployment.yaml \
  --ignore-test container-cpu-limit \
  --ignore-test pod-networkpolicy

Polaris

Polaris предоставляет как CLI-сканирование, так и контроль допуска в кластере:

# Audit local manifests
polaris audit --audit-path ./k8s/ --format=pretty
# Checks: resource limits, health probes, security context,
# image pull policy, host network access, privilege escalation

# Audit with a minimum score threshold
polaris audit --audit-path ./k8s/ --set-exit-code-below-score 80

# Run Polaris as a Kubernetes admission controller
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm install polaris fairwinds-stable/polaris --namespace polaris

Что валидировать в манифестах Kubernetes

Deployment, готовый к продакшену, должен включать ВСЕ перечисленные ниже элементы. Каждая аннотация объясняет, почему поле важно:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  labels:
    app: myapp
    version: "1.2.3"        # Pinned version, not "latest"
spec:
  replicas: 3               # Multiple replicas for availability
  selector:
    matchLabels:
      app: myapp
  template:
    spec:
      securityContext:
        runAsNonRoot: true   # Never run as root
        runAsUser: 1000
        fsGroup: 2000
        seccompProfile:
          type: RuntimeDefault  # Use default seccomp profile
      containers:
        - name: myapp
          image: myapp:1.2.3  # Pinned tag, never :latest
          resources:
            requests:          # Scheduler needs these
              cpu: 100m
              memory: 128Mi
            limits:            # Prevent noisy-neighbor issues
              cpu: 500m
              memory: 512Mi
          readinessProbe:      # When to send traffic
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
            failureThreshold: 3
          livenessProbe:       # When to restart
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 15
            periodSeconds: 20
            failureThreshold: 3
          startupProbe:        # Grace period for slow starts
            httpGet:
              path: /healthz
              port: 8080
            failureThreshold: 30
            periodSeconds: 10
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop: ["ALL"]
          ports:
            - containerPort: 8080
              protocol: TCP
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:    # Never hardcode secrets
                  name: myapp-secrets
                  key: db-password
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: kubernetes.io/hostname
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: myapp

Чек-лист для ревью манифестов

Проверка Зачем Критичность
Тег образа не :latest Предотвращает непредсказуемые деплои Критическая
Заданы requests и limits ресурсов Предотвращает исчерпание ресурсов Критическая
Настроен readiness probe Предотвращает трафик на неготовые поды Критическая
Настроен liveness probe Обеспечивает автоматическое восстановление Высокая
runAsNonRoot: true Предотвращает выход из контейнера Критическая
readOnlyRootFilesystem: true Ограничивает запись файлов атакующим Высокая
allowPrivilegeEscalation: false Предотвращает повышение привилегий Критическая
Все capabilities сброшены Минимизирует доступ к ядру Высокая
Нет hostNetwork: true Предотвращает доступ к сети хоста Критическая
Нет hostPID: true Предотвращает видимость процессов Критическая
Секреты через secretKeyRef Никаких захардкоженных учётных данных Критическая
Несколько реплик Доступность при отказе узла Высокая
PodDisruptionBudget существует Предотвращает одновременное обновление всех подов Средняя
NetworkPolicy существует Сетевая сегментация по принципу нулевого доверия Высокая

Пользовательская валидация с OPA Gatekeeper

Для организационных правил, выходящих за рамки стандартных инструментов, разверните OPA Gatekeeper как контроллер допуска Kubernetes:

# constraint-template.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8snolatestimage
spec:
  crd:
    spec:
      names:
        kind: K8sNoLatestImage
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8snolatestimage

        violation[{"msg": msg}] {
          container := input.review.object.spec.template.spec.containers[_]
          endswith(container.image, ":latest")
          msg := sprintf("Container '%s' uses :latest tag. Pin a specific version.", [container.name])
        }

        violation[{"msg": msg}] {
          container := input.review.object.spec.template.spec.containers[_]
          not contains(container.image, ":")
          msg := sprintf("Container '%s' has no image tag. Pin a specific version.", [container.name])
        }

---
# constraint.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sNoLatestImage
metadata:
  name: no-latest-image
spec:
  match:
    kinds:
      - apiGroups: ["apps"]
        kinds: ["Deployment", "StatefulSet", "DaemonSet"]
    namespaces:
      - production
      - staging

Интеграция валидации в CI

# .github/workflows/k8s-validation.yml
name: Kubernetes Manifest Validation
on:
  pull_request:
    paths:
      - 'k8s/**'
      - 'charts/**'

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

      - name: Schema validation
        run: kubeconform -strict -summary k8s/

      - name: Best practices check
        run: |
          kube-score score k8s/*.yaml
          EXIT_CODE=$?
          if [ $EXIT_CODE -ne 0 ]; then
            echo "kube-score found issues. Review above output."
            exit 1
          fi

      - name: Policy audit
        run: |
          polaris audit --audit-path k8s/ \
            --set-exit-code-below-score 80 \
            --format=pretty

Валидация манифестов — одна из наиболее ценных и наименее затратных практик в безопасности Kubernetes. Она выполняется за секунды, выявляет реальные проблемы и предотвращает ошибки конфигурации, на отладку которых в продакшене уходят часы.