Kubernetes Survival Guide
15 вещей, которые ты должен знать про K8s до того, как окажешься в продакшене. Это спасёт тебя от типичных «почему всё лежит» в 3 утра.
1. Requests и limits — без них ты слепой
- requests — гарантированные ресурсы (для scheduler)
- limits — потолок (CPU throttling или OOM kill)
resources:
requests: {cpu: 100m, memory: 128Mi}
limits: {memory: 256Mi} # CPU limits часто не ставят — см. ниже
CPU limits часто вредят latency (CFS throttling). Netflix, Uber, многие компании рекомендуют ставить requests без CPU limits. Memory limits — обязательны.
2. Probes — три типа, не путай
- startupProbe — «приложение запустилось?» (для медленно стартующих). Пока не успешен — другие probes не вызываются.
- livenessProbe — «живо? нужен ли restart?». Провал → kubelet перезапускает.
- readinessProbe — «готов принимать трафик?». Провал → исключается из Service endpoints.
startupProbe:
httpGet: {path: /healthz, port: 8000}
failureThreshold: 30
periodSeconds: 10 # даём 5 минут на старт
readinessProbe:
httpGet: {path: /ready, port: 8000}
periodSeconds: 5
livenessProbe:
httpGet: {path: /healthz, port: 8000}
periodSeconds: 10
failureThreshold: 3
Liveness probe не должен проверять зависимости (БД, кэш). Иначе при падении БД все pod-ы пойдут в restart loop, не давая БД восстановиться.
3. PodDisruptionBudget — защита от eviction
При drain ноды (обновление) Kubernetes уважает PDB.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
spec:
minAvailable: 2 # или maxUnavailable: 1
selector:
matchLabels: {app: api}
4. Anti-affinity для HA
Без anti-affinity все 3 replica могут оказаться на одной ноде. Нода упала — всё лежит.
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels: {app: api}
topologyKey: kubernetes.io/hostname
5. Imagepullpolicy и тег latest
С тегом :latest Kubernetes по умолчанию использует Always. С конкретным тегом — IfNotPresent. Используй конкретные теги или digest.
6. Namespace — изоляция
- Один namespace на env (prod, staging, dev) — нет
- Один на сервис / команду — да
- ResourceQuota на namespace — обязательно
- NetworkPolicy default deny на namespace — обязательно
7. Secrets — это base64, не шифрование
K8s Secret — просто base64. Любой с RBAC доступом к Secret видит его.
Production: External Secrets Operator + Vault или SOPS + Sealed Secrets.
8. Service types — для чего что
- ClusterIP (default) — внутри кластера
- NodePort — для разработки или low-level (30000-32767)
- LoadBalancer — облачный LB (платно). Используй Ingress вместо нескольких LB
- ExternalName — CNAME alias
9. Ingress → Gateway API
Старое API Ingress — лимиты по фичам. Gateway API — новый стандарт K8s. Учи Gateway API, Ingress на pension.
10. NetworkPolicy default deny
По умолчанию все pod-ы общаются со всеми. Это плохо. Запрети входящее по умолчанию, разрешай явно.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes: [Ingress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-from-ingress
spec:
podSelector: {matchLabels: {app: api}}
ingress:
- from:
- namespaceSelector: {matchLabels: {name: ingress-nginx}}
ports:
- port: 8000
11. RBAC: least privilege
- Не давай cluster-admin никому, кроме платформенной команды
- ServiceAccount per workload (не default)
- Role в namespace, ClusterRole только когда нужен
- Регулярный audit:
kubectl auth can-i --list
12. Karpenter лучше Cluster Autoscaler
На AWS EKS — стандарт сейчас Karpenter. Быстрее, гибче, дешевле (через Spot).
13. Probes-friendly graceful shutdown
При rolling update K8s посылает SIGTERM. Дай приложению время:
- Pod уходит из Service endpoints (readiness fail)
- SIGTERM → приложение
- Подожди terminationGracePeriodSeconds (по умолчанию 30s)
- SIGKILL если не завершился
spec:
terminationGracePeriodSeconds: 60
containers:
- name: api
lifecycle:
preStop:
exec:
command: ["sleep", "10"] # дать времени LB обновиться
14. kubectl полезности
# Алиасы (сэкономят часы за карьеру)
alias k=kubectl
alias kgp='kubectl get pods'
alias kgs='kubectl get svc'
alias kctx='kubectl config use-context'
alias kns='kubectl config set-context --current --namespace'
# Дебаг
kubectl describe pod <name>
kubectl logs <name> --previous # лог упавшего контейнера
kubectl get events --sort-by='.lastTimestamp'
kubectl debug pod/<name> -it --image=busybox
# Поиск
kubectl get pods --all-namespaces -o wide
kubectl get pods --field-selector=status.phase!=Running
# Тестирование DNS из кластера
kubectl run -it --rm test --image=nicolaka/netshoot --restart=Never -- /bin/bash
Установи k9s — TUI для K8s. Изменит жизнь.
15. Алгоритм дебага упавшего pod
kubectl get pod <name>— STATUSkubectl describe pod <name>— Events внизу всегдаkubectl logs <name>— текущий логkubectl logs <name> --previous— лог упавшего контейнераkubectl exec -it <name> -- sh— войти внутрьkubectl get events --sort-by='.lastTimestamp' -n <ns>kubectl top pod / node(нужен metrics-server)
Частые ошибки
| STATUS | Что делать |
|---|---|
| CrashLoopBackOff | App падает. logs --previous |
| ImagePullBackOff | Образ недоступен. Проверь tag, imagePullSecrets |
| Pending | Нет ресурсов. describe → Events |
| OOMKilled | Превышен memory limit. Увеличь |
| Evicted | Нода под давлением. Проверь node conditions |
| Error | Generic. Смотри describe + logs |
Если знаешь все 15 — ты production-ready. Дальше — CKA + CKS.