Wzorce orkiestracji Kubernetes
ENWzorce orkiestracji Kubernetes dla agentów AI to prompty i bramki, dzięki którym Claude Code, Codex lub Cursor piszą Deploymenty i charty Helm z realnymi ograniczeniami operacyjnymi: czas sond, zapas pamięci, budżety zakłóceń i ruch DNS. Manifest przechodzący kubectl apply wciąż może wywołać awarię, więc każda zmiana przechodzi przed merge’em walidację schematu, dry-run po stronie serwera i diff.
Twój rollout właśnie położył API. Sonda readiness zrobiła się zielona, zanim pula połączeń do Postgresa się rozgrzała, więc ruch trafił na pody zwracające 500, a manifest napisał agent, który nie wiedział, że pula potrzebuje ośmiu sekund. Ta strona jest dla developera lub tech leada, który odpowiada za taki manifest i chce, żeby następny udowodnił skrypt, a nie człowiek czytający 400 linii YAML-a.
Co zyskujesz dzięki tym wzorcom Kubernetes
Dział zatytułowany „Co zyskujesz dzięki tym wzorcom Kubernetes”- Blok reguł klastra do
CLAUDE.md,AGENTS.mdalbo reguły Cursora, żeby agent startował od twoich ograniczeń, a nie od swoich domyślnych ustawień. scripts/verify-k8s.sh— bramkę, która renderuje chart i sprawdza schemat, niezmienniki, admission po stronie serwera oraz diff względem klastra.- Prompty do skopiowania: Deployment bezpieczny dla sond, chart Helm bez zależności od Bitnami, diagnoza
CrashLoopBackOffi strojenie limitów zasobów na podstawie realnego zużycia. - Konfigurację serwera MCP dla Kubernetes w trybie tylko do odczytu dla wszystkich trzech narzędzi, żeby diagnoza opierała się na stanie żywego klastra.
- Sposoby wyjścia z sześciu typowych awarii, które powodują manifesty pisane przez agenta.
Najpierw daj agentowi reguły klastra
Dział zatytułowany „Najpierw daj agentowi reguły klastra”Agent wypełnia każdą lukę w prompcie domyślną wartością z danych treningowych: initialDelaySeconds zamiast startupProbe, tag obrazu latest, NetworkPolicy typu default-deny bez reguły dla DNS. Zapisz reguły raz, w pliku, który każde narzędzie czyta w każdej sesji: CLAUDE.md dla Claude Code, AGENTS.md dla Codeksa i reguła w .cursor/rules/ dla Cursora.
## Kubernetes rules (k8s/ and charts/)- Every container: requests and limits for CPU and memory; memory limit >= 1.25x observed P99.- Slow-starting apps get a startupProbe; never gate readiness with initialDelaySeconds.- Probes use named ports. Liveness never checks downstream dependencies.- Pods run as non-root, readOnlyRootFilesystem: true, drop ALL capabilities, seccomp RuntimeDefault.- Images are pinned by version tag or digest. Never `latest`.- A PodDisruptionBudget sets exactly one of minAvailable / maxUnavailable.- A default-deny NetworkPolicy always allows egress to kube-dns on UDP and TCP 53.- No Bitnami dependencies (charts.bitnami.com or oci://registry-1.docker.io/bitnamicharts). Postgres comes from the CloudNativePG operator.- If an HPA manages a Deployment, do not set spec.replicas in the Deployment.- Done means: scripts/verify-k8s.sh exits 0. Paste its summary into the PR.To właśnie ostatnia reguła zmienia code review. Zamienia „wygląda OK” w kod wyjścia, który agent musi uzyskać, zanim odda pracę.
Jak udowodnić manifest bez czytania każdej linii
Dział zatytułowany „Jak udowodnić manifest bez czytania każdej linii”Czytanie wygenerowanego YAML-a linia po linii się nie skaluje i przepuszcza awarie, które mają znaczenie, bo brakująca reguła DNS po prostu nie istnieje na ekranie. Zamiast tego wyrenderuj to, co faktycznie trafi do klastra, i pozwól sprawdzić to czterem warstwom. Uruchamiaj skrypt w terminalu i w CI.
#!/usr/bin/env bash# scripts/verify-k8s.sh (terminal or CI; needs helm, kubeconform, kubectl)set -euo pipefailCHART=charts/orders-apiVALUES=$CHART/values-production.yamlOUT=.rendered; rm -rf "$OUT"; mkdir -p "$OUT"
# 1. Render exactly what will be appliedhelm lint "$CHART" -f "$VALUES"helm template orders-api "$CHART" -n production -f "$VALUES" > "$OUT/all.yaml"
# 2. Schema: built-in kinds plus CRDs (such as the CNPG Cluster)kubeconform -strict -summary \ -schema-location default \ -schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' \ "$OUT/all.yaml"
# 3. Invariants a schema cannot expressfail() { echo "FAIL: $1"; exit 1; }grep -Eq 'image: .*:latest' "$OUT/all.yaml" && fail "image pinned to latest"# Assumes no registry port: registry.internal:5000/orders-api (no tag) passes.grep -Eq '^\s*image: "?[^:@"]+"?\s*$' "$OUT/all.yaml" && fail "image with no tag or digest"# orders-api warms a Postgres pool, so its Deployment must have a startupProbe.# Drop this check for charts whose apps start fast.if grep -q 'kind: Deployment' "$OUT/all.yaml"; then grep -q 'startupProbe:' "$OUT/all.yaml" || fail "Deployment without startupProbe"fiif grep -q 'kind: NetworkPolicy' "$OUT/all.yaml"; then grep -q 'k8s-app: kube-dns' "$OUT/all.yaml" || fail "NetworkPolicy without DNS egress"figrep -Eq 'charts\.bitnami\.com|bitnamicharts' "$CHART/Chart.yaml" && fail "Bitnami dependency"grep -Eq 'image: .*bitnami' "$OUT/all.yaml" && fail "Bitnami image"
# 4. Admission and drift against a real API server (staging or kind)kubectl apply --dry-run=server -f "$OUT/all.yaml"set +e; kubectl diff -f "$OUT/all.yaml" > "$OUT/cluster.diff"; rc=$?; set -e[ "$rc" -le 1 ] || fail "kubectl diff errored (rc=$rc)"echo "OK: $(grep -c '^kind:' "$OUT/all.yaml") objects; diff in $OUT/cluster.diff"Każda warstwa łapie inną klasę błędów:
| Warstwa | Łapie | Nie łapie |
|---|---|---|
helm lint i helm template | Błędy szablonów, własne kontrole fail chartu | Niczego, co jest poprawne, ale złe |
kubeconform -strict | Zły apiVersion, nieznane pola lub pola z literówkami | Zachowania: czasu sond, DNS |
Linie grep z niezmiennikami | Reguły zespołu, np. przypięty tag obrazu i obecność ruchu do DNS | Reguł, których nie zapisałeś |
kubectl apply --dry-run=server | Admission: Pod Security Standards, webhooki polityk, walidację PDB, brakujące CRD | Zachowania w czasie działania |
kubectl diff | To, co faktycznie zmieni się w klastrze | Niczego; ten wynik czyta człowiek |
kubectl diff zwraca 1, gdy są różnice, a więcej niż 1 przy błędzie, dlatego skrypt toleruje dokładnie 1. cluster.diff to jedyny artefakt, który czyta człowiek: jest krótki i pokazuje zmianę stanu klastra, a nie szablon, który ją wygenerował. Dołącz go do PR-a razem z podsumowaniem skryptu, tak jak opisuje pakiet dowodów. Właściciel serwisu zatwierdza diff, a nie YAML.
Po merge’u bramka przenosi się na rollout. kubectl rollout status deployment/orders-api -n production --timeout=5m zatrzymuje pipeline, jeśli nowe pody nigdy nie osiągną stanu Ready. Analizę canary i automatyczny rollback opisuje strona o progressive delivery.
Jak uruchomić agenta na katalogu manifestów
Dział zatytułowany „Jak uruchomić agenta na katalogu manifestów”Poniższe prompty działają we wszystkich trzech narzędziach. Różni się sposób uruchomienia ich na katalogu manifestów i to, jak trzymasz agenta z dala od klastra, gdy pisze.
Uruchom claude w katalogu głównym repozytorium i wklej prompt. Claude Code czyta CLAUDE.md oraz istniejący kustomization.yaml albo chart, więc nowe obiekty dostają te same etykiety i nakładki (overlays).
Do audytu tylko do odczytu w CI albo w skrypcie użyj trybu print z uprawnieniami planu — agent czyta pliki, ale ich nie edytuje:
claude -p --permission-mode plan --output-format json \ "Audit charts/orders-api against the Kubernetes rules in CLAUDE.md. List violations by severity with file and line."Sama forma claude "query" otwiera sesję interaktywną z tym promptem. To nie jest polecenie wsadowe. Od v2.1.283 (oba kanały wydań, stan na 2026-10-12) sesje interaktywne startują w trybie auto, w którym klasyfikator zatwierdza większość akcji. Żeby agent nie zmienił działającego klastra, dodaj reguły deny do .claude/settings.json, np. "deny": ["Bash(kubectl apply *)", "Bash(kubectl delete *)"], i uruchamiaj sesję z kontekstem kubeconfig powiązanym z rolą RBAC tylko do odczytu. Reguła prefiksowa łapie tylko zwykłą pisownię polecenia, więc realną ochroną jest rola RBAC.
Uruchom Codeksa z profilem uprawnień :workspace i zatwierdzaniem na żądanie — zapisuje wtedy tylko w workspace i pyta przed czymkolwiek szerszym, np. wywołaniem kubectl:
codex -c default_permissions=":workspace" -a on-request \ "Generate a probe-safe Deployment for orders-api under k8s/base following AGENTS.md"Do audytu bez nadzoru codex exec z profilem :read-only zapisuje końcową odpowiedź do pliku:
codex exec -c default_permissions=":read-only" -o k8s-audit.md \ "Audit charts/orders-api against the Kubernetes rules in AGENTS.md. List violations by severity."Profile uprawnień są w wersji beta (Codex CLI 0.138.0 lub nowszy) i nie mają osobnej flagi, więc wybierasz je przez -c default_permissions=… albo w config.toml. Starsza alternatywa to --sandbox workspace-write lub --sandbox read-only; według OpenAI oba systemy się nie łączą, więc używaj jednego albo drugiego, nigdy obu naraz. W Codex CLI 0.157.1 -a przyjmuje tylko on-request i never, codex exec nie ma flagi -a, a flagi --full-auto nie ma wcale.
Umieść reguły w regule projektu w .cursor/rules/, żeby agent ładował je dla k8s/ i charts/. Zmianę obejmującą wiele plików, np. manifesty → chart, zacznij w Plan Mode, przejrzyj plan, a potem pozwól agentowi pisać. Przejrzyj każdy manifest w widoku diff, zanim go zaakceptujesz; PodDisruptionBudget z minAvailable: 1 przy Deploymencie z jedną repliką widać tam, zanim zablokuje każde drenowanie węzła.
Do audytów skryptowych CLI Cursora ma tryb print (-p, --print), który działa bez interfejsu w CI.
Jak wygenerować Deployment, który nie ściga się z własnymi sondami
Dział zatytułowany „Jak wygenerować Deployment, który nie ściga się z własnymi sondami”Częsty błąd w Deploymencie napisanym przez agenta to sonda readiness, która przechodzi, zanim aplikacja jest gotowa. Wpisz czas rozgrzewania do promptu, a startupProbe poprawnie wstrzyma pozostałe sondy.
W wyniku szukaj bloku sond:
# k8s/base/deployment.yaml (container excerpt)startupProbe: # gates liveness and readiness while the pool warms httpGet: { path: /health/startup, port: http } periodSeconds: 2 failureThreshold: 30 # up to 60 sreadinessProbe: httpGet: { path: /health/ready, port: http } periodSeconds: 5 failureThreshold: 3livenessProbe: httpGet: { path: /health/live, port: http } periodSeconds: 10 failureThreshold: 3Jeśli agent zamiast tego zwróci initialDelaySeconds w sondzie readiness, odrzuć to. initialDelaySeconds to stałe zgadywanie — za krótkie na zimnym węźle albo stracony czas na rozgrzanym. startupProbe czeka na prawdziwy sygnał i nie pozwala sondzie liveness zabić poda w trakcie rozgrzewania.
Jak zablokować ruch sieciowy, nie psując DNS
Dział zatytułowany „Jak zablokować ruch sieciowy, nie psując DNS”Poproś o Service, Ingress i NetworkPolicy w jednym prompcie, żeby workload był jednocześnie wystawiony i ograniczony. Reguła, którą agenci często pomijają, to DNS:
# k8s/base/networkpolicy.yaml (egress excerpt)egress:- to: - namespaceSelector: {} podSelector: matchLabels: k8s-app: kube-dns ports: - { protocol: UDP, port: 53 } - { protocol: TCP, port: 53 }Bez niej pody startują, nie rozwiązują żadnej nazwy hosta i logują błędy no such host, które wyglądają jak błąd aplikacji. Linia z niezmiennikiem w verify-k8s.sh zamiast tego przerywa build. Sprawdź etykietę k8s-app: kube-dns w swoim klastrze poleceniem kubectl get pods -n kube-system --show-labels, bo niektóre dystrybucje etykietują CoreDNS inaczej.
Jak sparametryzować manifesty w chart Helm
Dział zatytułowany „Jak sparametryzować manifesty w chart Helm”Gdy te same manifesty trafiają na dev, staging i produkcję, każ agentowi wyodrębnić chart z walidacją wartości. Najpierw popraw jedną domyślną wartość z danych treningowych: agenci wciąż sięgają po zależności Bitnami. Od 28 sierpnia 2025 r. Bitnami przeniosło wersjonowane obrazy kontenerów z docker.io/bitnami do nieutrzymywanego repozytorium bitnamilegacy, a spakowane charty przestały dostawać aktualizacje (ogłoszenie Bitnami). Pin skopiowany ze starego przykładu może wskazywać obraz, którego już nie ma.
Dla Postgresa zainstaluj operator CloudNativePG raz na klaster, a chart aplikacji niech renderuje tylko zasób Cluster. Nie dołączaj operatora jako subchartu aplikacji, bo wtedy jego CRD i klastrowy RBAC dzielą cykl życia z wydaniem aplikacji.
# Platform team, once per cluster (terminal)helm repo add cnpg https://cloudnative-pg.github.io/chartshelm upgrade --install cnpg --namespace cnpg-system --create-namespace cnpg/cloudnative-pgHelper walidacyjny sprawia, że zły plik wartości kończy się błędem już na helm template, czyli na pierwszej warstwie bramki:
# charts/orders-api/templates/_helpers.tpl (excerpt){{- define "orders-api.validateValues" -}}{{- if not .Values.image.repository }} {{- fail "image.repository is required" }}{{- end }}{{- if and .Values.ingress.enabled (not .Values.ingress.hosts) }} {{- fail "ingress.hosts must be set when ingress.enabled is true" }}{{- end }}{{- end }}Jak bezpiecznie skalować i drenować węzły z HPA i PDB
Dział zatytułowany „Jak bezpiecznie skalować i drenować węzły z HPA i PDB”Generuj HorizontalPodAutoscaler i PodDisruptionBudget razem. PDB ma jedną pułapkę: przyjmuje minAvailable albo maxUnavailable, nigdy oba, a serwer API odrzuca PDB, który ustawia oba pola. maxUnavailable: 1 jest zwykle lepszym wyborem przy co najmniej dwóch replikach, bo działa dalej, gdy HPA zmienia liczbę replik. Przy jednej replice każdy PDB albo blokuje drenowanie, albo dopuszcza przestój.
# pdb.yaml — exactly one of minAvailable / maxUnavailableapiVersion: policy/v1kind: PodDisruptionBudgetmetadata: { name: orders-api, namespace: production }spec: maxUnavailable: 1 selector: matchLabels: { app: orders-api }W GitOps HPA i Argo CD walczą o spec.replicas, dopóki nie każesz Argo CD tego pola ignorować. Dodaj do Application:
spec: ignoreDifferences: - group: apps kind: Deployment jsonPointers: [/spec/replicas] syncPolicy: syncOptions: [RespectIgnoreDifferences=true]Samo ignoreDifferences tylko ukrywa różnicę: jeśli spec.replicas nadal jest w Gicie, każda synchronizacja (i każdy self-heal) zapisuje je z powrotem ponad HPA. Dlatego usuń spec.replicas z Deploymentu w Gicie, jak mówi plik z regułami, albo zostaw pokazaną wyżej opcję RespectIgnoreDifferences=true, żeby synchronizacja nie ruszała liczby replik.
Podział ruchu i wdrożenia canary, wraz z analizą decydującą o promocji, opisuje strona o progressive delivery. Gdy generujesz routing Istio, sprawdź, które wersje API obsługuje twój mesh (kubectl api-resources --api-group=networking.istio.io), zanim zaakceptujesz apiVersion wybrany przez agenta.
Jak zdiagnozować padający pod na podstawie stanu klastra
Dział zatytułowany „Jak zdiagnozować padający pod na podstawie stanu klastra”Bez dostępu do klastra agent odpowiada na „dlaczego ten pod się restartuje?” ogólną checklistą. Ze społecznościowym serwerem MCP dla Kubernetes (npm kubernetes-mcp-server, wersja 0.0.67 na 2026-09-26) sam listuje pody, czyta logi i pobiera zdarzenia. Ustawienia tego serwera leżą w pliku TOML; CLI zachowało tylko --config, --config-dir i --version. Uruchom go w trybie tylko do odczytu:
read_only = truetoolsets = ["core", "config", "helm"]Wskaż serwerowi także kontekst kubeconfig powiązany z rolą RBAC tylko do odczytu. read_only = true ogranicza narzędzia serwera; RBAC ogranicza, co da się zrobić wyciekłym poświadczeniem. W toolsets zostaw tylko to, czego potrzebuje diagnoza, bo definicja każdego włączonego narzędzia zajmuje kontekst w każdej sesji. claude mcp add domyślnie zapisuje w zakresie local (Claude Code 2.1.283); dodaj --scope project, żeby zapisać .mcp.json, który commitujesz, a cały zespół dostaje ten sam serwer.
claude mcp add kubernetes -- npx -y kubernetes-mcp-server@0.0.67 --config "$HOME/.config/k8s-mcp.toml"codex mcp add kubernetes -- npx -y kubernetes-mcp-server@0.0.67 --config "$HOME/.config/k8s-mcp.toml"Dodaj serwer do .cursor/mcp.json w projekcie. Użyj ścieżki bezwzględnej do pliku TOML; argumenty trafiają do npx bez zmian, a nie przez powłokę.
{ "mcpServers": { "kubernetes": { "command": "npx", "args": ["-y", "kubernetes-mcp-server@0.0.67", "--config", "/home/you/.config/k8s-mcp.toml"] } }}Agent nie ma dostępu do klastra? Uruchom sam kubectl describe pod POD -n production i kubectl logs POD -n production --previous, a oba wyniki wklej nad tym samym promptem. Więcej serwerów infrastrukturalnych oraz to, kiedy skill pasuje lepiej niż serwer, znajdziesz w serwerach MCP dla infrastruktury.
Jak dostroić limity zasobów na podstawie realnego zużycia
Dział zatytułowany „Jak dostroić limity zasobów na podstawie realnego zużycia”Limity wybrane przez agenta to zgadywanie. Zastąp je liczbami z własnych metryk.
Skąd brać te metryki i jakie alerty mówią, że limit jest za ciasny, opisują wzorce monitoringu i logowania.
Co się psuje, gdy agent pisze konfigurację Kubernetes?
Dział zatytułowany „Co się psuje, gdy agent pisze konfigurację Kubernetes?”-
CrashLoopBackOfftuż po rolloucie. Sonda liveness zabija poda, zanim ten skończy start. Potwierdź przezkubectl describe pod POD -n production: zdarzenia pokazująLiveness probe failed, a po nim restart.kubectl logs POD -n production --previouspokazuje przerwaną sekwencję startu. Wyjście: przenieś ochronę startu dostartupProbei dodaj kontrolęstartupProbedoverify-k8s.sh, jeśli jej jeszcze nie ma. -
OOMKilledpod obciążeniem.kubectl describe podpokazujeLast State: Terminated, Reason: OOMKilled. Wyjście: podnieś limit pamięci powyżej zaobserwowanego P99 promptem do zasobów powyżej i na realnych danych. Nie podwajaj liczby tylko po to, żeby alert ucichł. -
Drenowanie węzła wisi. PDB nie zostawia budżetu zakłóceń, np.
minAvailable: 3przy trzech replikach. Wyjście: przejdź namaxUnavailable: 1. PDB z oboma polami nigdy nie trafi do klastra, bo odrzuca go dry-run po stronie serwera w bramce. -
ImagePullBackOff. Tag nie istnieje, rejestr wymagaimagePullSecretsalbo chart nadal wskazuje usunięty obraz Bitnami. Wyjście: potwierdź tag w rejestrze, dołącz sekret do pobierania obrazów i zastąp zależność Bitnami tak, jak pokazano wyżej. -
Argo CD utknęło w
OutOfSynclubProgressing.OutOfSync, które wraca po każdej synchronizacji, to zwykle HPA i Git walczące ospec.replicas: dodaj wpisignoreDifferencesi albo usuńspec.replicasz Deploymentu w Gicie, albo ustawRespectIgnoreDifferences=true, żeby synchronizacja nie resetowała liczby replik.Progressingbez końca oznacza, że Deployment nigdy nie osiąga stanu Ready: wróć do punktów 1 i 2. -
Awaryjne
kubectl rollout undosamo się cofa. PrzyselfHeal: trueArgo CD w ciągu kilku minut przywraca to, co jest w Gicie. Wyjście: zrób revert commita w repozytorium konfiguracji. To jest właściwy rollback — niekubectl. Przećwicz tę ścieżkę według strony o przećwiczonym rollbacku z decyzją człowieka.
Zielona bramka przy zepsutej produkcji to jedyna cicha awaria w tym procesie. Zdarza się, gdy klaster stagingowy używany do dry-runu po stronie serwera nie ma CRD, polityki albo etykiety Pod Security, które ma produkcja. Utrzymuj oba w zgodzie, a każde nowe odrzucenie przez admission na produkcji traktuj jako lukę w stagingu.
Dokąd dalej z Kubernetes i agentami
Dział zatytułowany „Dokąd dalej z Kubernetes i agentami”Czy ten artykuł Ci pomógł?
Jedno kliknięcie, bez logowania.
Co z tym zrobisz?
Jak się czytało?
Co przeszkadzało? Możesz zaznaczyć kilka
Twoja rola?
Dzięki. Czytam każdą odpowiedź. Michał Jaskólski
Pomógł Ci ten artykuł?
Każde to jedno kliknięcie. Zamknij, kiedy chcesz.
bez logowania