Перейти к содержанию
Learning Platform
Глоссарий
Troubleshooting

Troubleshooting — Kubernetes (CKAD)

База знаний типичных ошибок курса Kubernetes (CKAD).

Категория

Показано 28 из 28 ошибок

Симптомы

  • Pod в статусе Pending или Running, но container в Waiting с reason ImagePullBackOff или ErrImagePull. kubectl describe pod показывает Events типа 'Failed to pull image ...: not found' / 'pull access denied' / 'manifest unknown'. Pod не стартует, restartCount растёт.

Причина

Опечатка в image name (registry/repo:tag) — типичные nginx:latests, niginx, registry typo Image не существует в registry — забыли push после build, или tag другой Private registry — нет imagePullSecret или token истёк / неверный Rate limit Docker Hub anonymous (100 pulls/6h), нужен авторизованный pull Network blocked: NetworkPolicy egress блокирует registry, корпоративный proxy, firewall Платформа image не совпадает с node (arm64 image на amd64 node — exec format error) imagePullPolicy: Always + private registry без working secret

Решение

  1. Исправить typo в image name (внимательно перечитать)
  2. Push image в registry, проверить тег: docker push registry/app:v1
  3. Создать imagePullSecret: kubectl create secret docker-registry regcred --docker-server=... --docker-username=... --docker-password=...; прикрепить к Pod или ServiceAccount
  4. На Docker Hub использовать аутентифицированный pull (paid plan или mirror)
  5. Открыть egress в NetworkPolicy для registry, или DNS resolution
  6. Build multi-arch images: docker buildx build --platform linux/amd64,linux/arm64 -t image --push
  7. Сменить imagePullPolicy: IfNotPresent если image уже на node

Связанные уроки:

Симптомы

  • Pod в Running, container с restartCount растущим и статусом Waiting reason: CrashLoopBackOff. kubelet применяет exponential backoff: 10s, 20s, 40s, 80s, 160s, 300s cap. kubectl describe — Last State: Terminated, Exit Code не 0, или приложение exit 0 сразу.

Причина

Application crash: exception в коде, missing dependency, неправильный entrypoint Missing/wrong config: переменная окружения не задана, ConfigMap mount не такой как ожидался Permission denied: контейнер хочет писать в readOnlyRootFilesystem, или files non-root Liveness probe валит контейнер слишком рано (initialDelay мал) Команда успешно exit'ает (exit 0) — typical если CMD = 'echo hello', и restartPolicy=Always Connection issue к dependency (DB, API) — fail-fast и crash OOM Killed (exit 137) — приложение пожирает память больше limit

Решение

  1. Исправить ошибку в приложении (см. logs --previous)
  2. Добавить недостающие env vars, ConfigMap, Secrets
  3. Увеличить liveness probe initialDelaySeconds, добавить startupProbe для медленных apps
  4. Если CMD заканчивается слишком рано — изменить на long-running процесс
  5. Увеличить memory limits если OOM, или fix memory leak
  6. Использовать kubectl debug или sleep команду для interactive отладки: command: ['sh', '-c', 'sleep 1d']

Связанные уроки:

Симптомы

  • Container terminated с reason: OOMKilled, exitCode: 137. kubectl describe — Last State: Terminated. В системных событиях на node: 'Memory cgroup out of memory: Killed process'. Pod может перезапускаться и снова падать (loop).

Причина

Container превысил memory limit (приложение жадно использует RAM) Memory leak в приложении Загрузка большого dataset в память (in-memory cache, ML model) JVM heap не настроен под container limit (старая Java < 10 без -XX:+UseContainerSupport) Sidecar тоже потребляет память, считаемую в Pod limit Node MemoryPressure — kubelet evict Pod (другой scenario — exit code 137 но reason 'Evicted')

Решение

  1. Увеличить resources.limits.memory у container
  2. Установить requests.memory ближе к limits — Guaranteed QoS защищает от eviction
  3. Profile приложение и устранить leak (heap dump для JVM, pprof для Go)
  4. JVM: -XX:MaxRAMPercentage=75.0 или -Xmx; Node.js: --max-old-space-size
  5. Если sidecar — посмотреть его memory отдельно, ограничить его
  6. Увеличить replicas Deployment чтобы распределить нагрузку

Связанные уроки:

Симптомы

  • Pod в статусе Pending долгое время, kubectl describe pod — Events: 'FailedScheduling' с сообщением '0/3 nodes are available: ...'. kubectl get pod -o wide показывает NODE: <none>. Scheduler не может найти подходящий node.

Причина

Недостаточно ресурсов: CPU/memory requests превышают allocatable на всех nodes nodeSelector / nodeAffinity не matches ни один node Taint на node без соответствующего toleration PVC не bound (зависит от PV/StorageClass) Anti-affinity конфликт: requiredDuringScheduling не может быть satisfied Все nodes имеют unschedulable=true (cordoned) PodTopologySpreadConstraints не могут быть satisfied

Решение

  1. Уменьшить resources.requests, или добавить node в кластер (autoscaler)
  2. Исправить nodeSelector label matching, проверить kubectl get nodes -l <label>
  3. Добавить toleration: spec.tolerations: [{ key: ..., operator: Equal, value: ..., effect: NoSchedule }]
  4. Создать PV вручную или fix StorageClass / provisioner
  5. Ослабить anti-affinity (preferredDuringScheduling вместо required) или добавить node
  6. kubectl uncordon <node>

Связанные уроки:

Симптомы

  • kubectl delete pod возвращает 'deleted', но Pod продолжает висеть в статусе Terminating минуты или часы. kubectl get pod показывает Terminating и deletionTimestamp в past. Новые Pods через ReplicaSet могут не создаваться (для StatefulSet — обязательно ждёт).

Причина

Finalizers на Pod (типа kubernetes.io/pv-protection или custom) не удалены контроллером Volume не unmount: NFS unresponsive, CSI driver hung, multi-attach issue preStop hook hung / sleep слишком долгий + большой terminationGracePeriodSeconds Node, на котором был Pod, NotReady (kubelet не отвечает) Контейнер игнорирует SIGTERM, ждёт SIGKILL после grace period API server / etcd проблемы — delete не applied

Решение

  1. Force delete: kubectl delete pod <pod> --grace-period=0 --force (только если уверен)
  2. Удалить finalizers вручную: kubectl patch pod <pod> -p '{"metadata":{"finalizers":null}}'
  3. Если node NotReady — устранить проблему kubelet/network на node, потом Pod удалится сам
  4. Уменьшить terminationGracePeriodSeconds или fix preStop hook
  5. Application должен обрабатывать SIGTERM и graceful shutdown
  6. Перезапустить kubelet на node если все остальные методы не помогли

Связанные уроки:

Симптомы

  • Pod в статусе Init:0/2, Init:CrashLoopBackOff, или Init:Error. Main containers не стартуют. kubectl get pod — STATUS: Init:CrashLoopBackOff, READY: 0/n.

Причина

Init container скрипт fail (exit code не 0) Init container ждёт dependency (DB, API) которая не доступна Permission issue — init нужен root для chown volume но pod runAsNonRoot Wrong image / wrong command в init Timeout: init требует больше времени чем activeDeadlineSeconds Pod ConfigMap / Secret для init не существует

Решение

  1. Fix init script (exit 0 при успехе)
  2. Проверить что dependency dostupna: nslookup, telnet из init container
  3. Init может бежать с разным securityContext чем main containers
  4. Использовать busybox / alpine для wait-for-it pattern
  5. Увеличить timeoutы у dependency check loops

Связанные уроки:

Симптомы

  • Pod в статусе Pending или Running, container в Waiting с reason: CreateContainerConfigError. kubectl describe — Events: 'Error: configmap "xxx" not found' / 'Error: secret "xxx" not found' / 'Error: couldn't find key xxx in ConfigMap'.

Причина

ConfigMap или Secret referenced в env/volumeMount не существует в namespace Опечатка в name ConfigMap/Secret Ключ в ConfigMap/Secret не существует (configMapKeyRef.key) Cross-namespace reference — ConfigMap не в том namespace что Pod Secret имеет неверный type для использования (например tls без tls.crt/tls.key)

Решение

  1. Создать недостающий ConfigMap / Secret: kubectl create configmap ...
  2. Исправить опечатку в spec
  3. Создать ConfigMap в namespace Pod (нельзя ссылаться на другой NS)
  4. Использовать optional: true в configMapKeyRef если ключ может отсутствовать
  5. Проверить совпадение type secret (Opaque, kubernetes.io/tls etc)

Связанные уроки:

Симптомы

  • Pod в Pending. Events: '0/3 nodes are available: 3 Insufficient cpu' или 'Insufficient memory'. Scheduler видит nodes, но allocatable < requests Pod.

Причина

Pod requests слишком большие — нет node с таким свободным запасом Кластер близок к full — старые Pods не освободили ресурсы Allocatable меньше capacity из-за system-reserved / kube-reserved / eviction-hard reserve ResourceQuota namespace ограничивает summa requests

Решение

  1. Уменьшить resources.requests Pod (если over-provisioned)
  2. Добавить nodes в кластер (cluster autoscaler scales up при Pending Pods)
  3. Evict / drain noisy neighbors, scale-down неважные workloads
  4. Увеличить ResourceQuota если ограничение namespace-level
  5. Использовать priorityClassName + preemption для critical workloads

Связанные уроки:

Симптомы

  • Pod в Pending. Events: '0/3 nodes are available: 3 node(s) didn't match Pod's node affinity/selector'. Pod указал nodeSelector или affinity, но ни один node не имеет matching labels.

Причина

Label на node не задан или другой ключ/значение Опечатка в значении (disktype=sssd вместо ssd) Все nodes с нужным label cordoned / drained requiredDuringSchedulingIgnoredDuringExecution affinity, который не satisfied

Решение

  1. Добавить label на node: kubectl label node worker-1 disktype=ssd
  2. Исправить опечатку в Pod spec
  3. Использовать preferredDuringScheduling вместо required для мягкого предпочтения
  4. Расширить selector (matchExpressions с In вместо single value)

Связанные уроки:

Симптомы

  • Pod в Pending. Events: '0/3 nodes are available: 1 node(s) had taint {key: value}, that the pod didn't tolerate'. Control plane nodes часто имеют node-role.kubernetes.io/control-plane:NoSchedule.

Причина

Control-plane taint — Pod пытается schedule на master без toleration GPU/специализированные nodes имеют taint типа dedicated=gpu:NoSchedule kubectl taint вручную добавил taint NotReady taint (node.kubernetes.io/not-ready:NoSchedule) automatically added kubelet'ом Memory/disk pressure taints автоматически applied

Решение

  1. Добавить toleration в Pod spec: tolerations: [{ key: dedicated, operator: Equal, value: gpu, effect: NoSchedule }]
  2. Использовать operator: Exists без value — match любое значение ключа
  3. Удалить taint если он не нужен: kubectl taint node worker-1 dedicated-
  4. Для system workloads tolerate все: tolerations: [{ operator: Exists }]

Связанные уроки:

Симптомы

  • Из одного Pod curl http://service-name отдаёт connection refused, timeout, или DNS resolution fails. kubectl get svc показывает ClusterIP, но запросы не доходят до backend Pods.

Причина

Service selector не совпадает с labels Pods — EndpointSlices пустые Backend Pods не Ready (readiness probe fail) — не в EndpointSlices Pods слушают на другом порту чем targetPort NetworkPolicy блокирует ingress на backend Pods Service в другом namespace — нужно FQDN <svc>.<ns>.svc.cluster.local kube-proxy crashed на node клиента или сервера Pods используют hostNetwork и Service selector не совпадает

Решение

  1. Исправить selector Service — должен совпадать с labels Pods
  2. Дождаться Ready Pods, fix readiness probe если она fail unjustly
  3. Согласовать targetPort с containerPort приложения
  4. Добавить NetworkPolicy ingress rule разрешающий трафик от клиента
  5. Использовать FQDN для cross-namespace: backend.api.svc.cluster.local
  6. Перезапустить kube-proxy: kubectl rollout restart ds/kube-proxy -n kube-system

Симптомы

  • nslookup из Pod возвращает 'server can't find ...: NXDOMAIN' или timeout. Запросы по DNS-имени Service fail, но по ClusterIP работают. Application logs показывают 'no such host', 'getaddrinfo ENOTFOUND'.

Причина

CoreDNS pods crashed или не Ready Service kube-dns не доступен с node Pod (NetworkPolicy блокирует egress на 10.96.0.10:53) /etc/resolv.conf в Pod неверный (dnsPolicy: None без dnsConfig) Search domain не включает нужный namespace — short name только в same NS ndots: 5 default — много extra queries (foo.com.<ns>.svc.cluster.local etc), внешние имена тормозят Upstream DNS broken — внешние имена не резолвятся CoreDNS не имеет permissions watch endpoints (RBAC issue)

Решение

  1. Перезапустить CoreDNS: kubectl rollout restart deployment/coredns -n kube-system
  2. Добавить NetworkPolicy egress для UDP 53 на kube-system
  3. Использовать FQDN для cross-namespace (api.prod.svc.cluster.local)
  4. Снизить ndots в Pod: dnsConfig: { options: [{ name: ndots, value: '2' }] }
  5. Проверить upstream в CoreDNS Corefile (forward . /etc/resolv.conf)
  6. NodeLocal DNSCache для уменьшения load и улучшения latency

Связанные уроки:

Симптомы

  • Запрос на Ingress endpoint возвращает 404 'default backend - 404' (NGINX), 502 Bad Gateway, или 503 Service Unavailable. Service напрямую работает корректно (curl ClusterIP — OK).

Причина

404: rule не matches Host или path — typo, неверный pathType 404: ingressClassName не указан, или нет default IngressClass 404: Service name в backend не существует или в другом namespace 502: backend Pod не отвечает или crash'ит 502: targetPort неверный, controller не может connect 503: backend Service не имеет endpoints (Pods not Ready) TLS issue: certificate невалидный, hostname mismatch

Решение

  1. Проверить host + path в правилах Ingress, pathType: Prefix vs Exact
  2. Указать ingressClassName в Ingress, или назначить default IngressClass
  3. Исправить service.name и service.port в backend
  4. Fix backend app — посмотри logs Pod и probes
  5. Согласовать backend service port и Pod targetPort
  6. Проверить readiness probe — Pods должны быть Ready
  7. Обновить TLS Secret (cert-manager или вручную)

Связанные уроки:

Симптомы

  • После применения NetworkPolicy одни Pods перестали общаться с другими, DNS перестал работать, или внешние API недоступны. Раньше всё работало.

Причина

Default deny включён (policyTypes: Ingress, Egress) но не все нужные правила добавлены Forgot to allow DNS egress (UDP 53 to kube-system) — все DNS-имена ломаются namespaceSelector не matches kube-system (по default нет label kubernetes.io/metadata.name) podSelector pyramid: Policy выбирает не те Pods (пустой selector = ВСЕ Pods в NS) CNI не поддерживает NetworkPolicy (Flannel default — нет; нужен Calico, Cilium, Weave) Egress policy блокирует API server endpoint (для in-cluster API calls) Pod selector в from/to пустой = ANY Pod, но затронутый namespaceSelector ограничивает

Решение

  1. Добавить explicit allow для DNS: egress to namespaceSelector matching kube-system, ports UDP/TCP 53
  2. Залейбить namespaces: kubectl label ns kube-system kubernetes.io/metadata.name=kube-system (с v1.22 это automatic)
  3. Указать узкий podSelector — НЕ пустой если не хотим affect everyone
  4. Сменить CNI на поддерживающий NetworkPolicy
  5. Добавить allow egress на API server: ports tcp 443 to ipBlock с cluster CIDR
  6. Использовать observability (Cilium Hubble) для tracing drops

Связанные уроки:

Симптомы

  • Ingress в namespace ingress-nginx указывает на Service в другом namespace и возвращает 503 / Service not found. Или LoadBalancer Service ссылается на Pods, которые в другом namespace.

Причина

Ingress backend.service.name — Service должен быть в ТОМ ЖЕ namespace что Ingress LoadBalancer Service selector matches только Pods в его namespace Gateway API HTTPRoute в другом namespace без ReferenceGrant ExternalName Service не настроен правильно

Решение

  1. Создать Ingress в namespace где backend Service
  2. Использовать ExternalName Service-proxy: в Ingress namespace create Service type=ExternalName pointing to real-svc.other-ns.svc.cluster.local
  3. Gateway API: создать ReferenceGrant в backend namespace разрешающий cross-NS reference
  4. Перенести Service в namespace Ingress (если возможно)

Связанные уроки:

Симптомы

  • kubectl get pvc показывает STATUS: Pending. Описание показывает 'no persistent volumes available for this claim and no storage class is set' или 'waiting for first consumer to be created before binding'.

Причина

Нет default StorageClass и в PVC не указан storageClassName StorageClass указан, но provisioner не установлен (CSI driver не работает) Static PV не существует с подходящими параметрами (size, accessModes, storageClassName) volumeBindingMode: WaitForFirstConsumer — нормальное состояние пока Pod не создан PVC размер больше чем любой available PV AccessMode PVC не поддерживается provisioner (RWX на EBS — невозможно)

Решение

  1. Указать storageClassName в PVC, или назначить default SC
  2. Установить / fix CSI driver (logs csi-controller, csi-node)
  3. Создать static PV с подходящими полями
  4. Если WaitForFirstConsumer — создать Pod, использующий PVC
  5. Уменьшить request.storage в PVC
  6. Сменить accessMode на supported (RWO для EBS, RWX для EFS/NFS)

Связанные уроки:

Симптомы

  • Pod в Pending. Events: 'Multi-Attach error for volume "pvc-xxx" Volume is already used by pod(s) other-pod' или 'FailedAttachVolume'. Возникает при rolling update RWO PVC, или Pod move между nodes.

Причина

PVC с accessMode RWO монтируется в Pod на node A, новый Pod schedule на node B Старый Pod не удалился полностью (stuck Terminating) Block storage (EBS, GCE PD) attached к одному VM exclusively Несколько replicas Deployment пытаются маунтить one RWO PVC Node failure: kubelet on old node не отвечает, controller не может detach

Решение

  1. Удалить старый Pod (force delete если stuck): kubectl delete pod <old> --grace-period=0 --force
  2. Перенести PVC на StatefulSet — у каждого Pod свой PVC через volumeClaimTemplates
  3. Использовать RWX storage (NFS, EFS, CephFS) если действительно нужен shared
  4. Recreate strategy в Deployment вместо RollingUpdate для RWO PVC
  5. Удалить stale VolumeAttachment вручную: kubectl delete volumeattachment <name>
  6. Drain старый node если он не Ready

Связанные уроки:

Симптомы

  • PVC stuck Pending. Events: 'storageclass.storage.k8s.io "standard" not found'. Кластер не имеет default StorageClass или указанный SC удалён.

Причина

Default StorageClass отсутствует и PVC не задаёт storageClassName StorageClass был удалён (а PVC ссылается) Опечатка в storageClassName в PVC Bare-metal кластер без storage provisioner

Решение

  1. Создать StorageClass: kubectl apply -f sc.yaml с provisioner вашего CSI
  2. Назначить default: kubectl annotate sc <name> storageclass.kubernetes.io/is-default-class=true
  3. Установить CSI driver для облака (ebs-csi, gce-pd-csi) или local-path-provisioner для bare-metal
  4. Исправить опечатку в PVC

Связанные уроки:

Симптомы

  • Pod evicted, kubectl describe — 'Evicted' / 'The node was low on resource: ephemeral-storage'. Container уходил в OOM-like при больших файлах в /tmp.

Причина

emptyDir растёт до bigger size, заполняя node disk Node ephemeral-storage approached eviction threshold (nodefs.available < 10% by default) Нет sizeLimit на emptyDir — нет ограничения Log files в контейнере накапливаются (writable layer) medium: Memory emptyDir не подсчитан в memory limit правильно

Решение

  1. Добавить sizeLimit к emptyDir: emptyDir: { sizeLimit: 1Gi }
  2. Установить ephemeral-storage requests/limits на container
  3. Перевести на PVC если данные persistent
  4. Очистить старые logs / temp files в приложении
  5. Increase node disk size, или add nodes
  6. Использовать medium: Memory только для маленьких volumes (учитывать memory limit)

Связанные уроки:

Симптомы

  • После kubectl apply / edit ConfigMap, новое значение не появилось в контейнере. Приложение использует старую конфигурацию. Файл в volume — тоже старый.

Причина

ConfigMap mounted через subPath — обновления НЕ подхватываются автоматически ConfigMap используется через env vars — обновления НЕ применяются (нужен restart Pod) kubelet syncFrequency задержка (~1 минута для volume updates) Приложение читает файл один раз при старте и кэширует ConfigMap имеет immutable: true — обновления невозможны Pod использовал старую revision RS, deploy не triggered

Решение

  1. Убрать subPath, mount directory целиком — обновления автоматические
  2. Триггерить rollout deployment при ConfigMap update: kubectl rollout restart deployment/<name>
  3. Использовать tool типа Reloader / ConfigMap-Reload для auto-restart Pods
  4. Подождать ~1 минуту kubelet sync (для non-subPath mounts)
  5. Приложение должно перечитывать конфиг (SIGHUP, file watch)
  6. Для immutable — создать новый ConfigMap с другим именем и обновить Deployment

Симптомы

  • Pod стартует, но приложение fail с 'credentials not found'. Файл с secret отсутствует или пустой. env var из Secret не передан.

Причина

Опечатка в name Secret или key Secret в другом namespace чем Pod — cross-namespace не работает напрямую Secret type не соответствует (tls без tls.crt/tls.key полей) ServiceAccount не существует или нет permissions read Secret defaultMode на projected secret слишком restrictive (file unreadable) imagePullSecret не type kubernetes.io/dockerconfigjson

Решение

  1. Создать Secret в namespace Pod
  2. Исправить name / key spec
  3. Использовать правильный type: kubernetes.io/tls для TLS, Opaque для general
  4. Установить defaultMode: 0400 для секретов (читаемо owner)
  5. Использовать external-secrets для синхронизации из Vault/AWS Secrets Manager
  6. Проверить RBAC permissions ServiceAccount

Связанные уроки:

Симптомы

  • Pod не может pull image из private registry. Events: 'Failed to pull image ... unauthorized' / '403 Forbidden' даже несмотря на наличие imagePullSecret. ImagePullBackOff несмотря на secret.

Причина

Secret в другом namespace чем Pod Secret type не kubernetes.io/dockerconfigjson Wrong registry URL в secret (https://, http://, без protocol — important) Token истёк (для cloud registries auth tokens живут часы) Учётка не имеет permissions на конкретный repo imagePullSecret не указан в Pod spec / ServiceAccount Server мнения отличаются: registry.example.com vs registry.example.com:443

Решение

  1. Recreate secret: kubectl create secret docker-registry regcred --docker-server=<url> --docker-username=<u> --docker-password=<p>
  2. Создать в правильном namespace или duplicate в нужный
  3. Прикрепить к ServiceAccount чтобы auto-apply всем Pods: kubectl patch sa default -p '{"imagePullSecrets":[{"name":"regcred"}]}'
  4. Для AWS ECR — использовать IAM роль через IRSA вместо static secret
  5. Refresh token периодически (CronJob с aws ecr get-login-password)
  6. Сверить registry URL точно (включая порт, scheme)

Связанные уроки:

Симптомы

  • kubectl или приложение получает 'Error from server (Forbidden)': User/ServiceAccount 'xxx' cannot 'verb' resource 'yyy' in API group 'zzz'. API call не проходит authorization.

Причина

Нет Role/ClusterRole с нужным verb на resource Нет RoleBinding/ClusterRoleBinding к subject Subject типа ServiceAccount но binding к User (не matches) RoleBinding в неверном namespace ClusterRole используется через RoleBinding но resource cluster-scoped (нужен ClusterRoleBinding) resourceNames ограничивает только конкретные объекты API group неверный: '' (core) vs 'apps' vs 'batch'

Решение

  1. Создать Role: rules с правильным apiGroups, resources, verbs
  2. Bind через RoleBinding (namespaced) или ClusterRoleBinding (cluster-wide)
  3. Использовать встроенные ClusterRoles: view, edit, admin, cluster-admin
  4. Aggregate permissions через aggregationRule
  5. Использовать impersonation для testing: kubectl --as=...
  6. Для cluster-scoped resources — ClusterRoleBinding обязателен

Связанные уроки:

Симптомы

  • kubectl apply возвращает 'violates PodSecurity "restricted:latest": ...' или warning. Pod не создаётся / с warning. Описывает конкретное нарушение: runAsNonRoot, allowPrivilegeEscalation, capabilities, seccompProfile.

Причина

Namespace помечен PSS labels (pod-security.kubernetes.io/enforce: restricted) Pod нарушает: runAsRoot, hostPath volume, privileged container, добавляет capabilities Образ запускается как root (USER 0 в Dockerfile) Нет seccompProfile.type: RuntimeDefault при PSS Restricted allowPrivilegeEscalation: true (default — нужно явно false)

Решение

  1. Привести Pod к PSS Restricted: runAsNonRoot, runAsUser, capabilities drop ALL, seccompProfile RuntimeDefault, allowPrivilegeEscalation false, readOnlyRootFilesystem if possible
  2. Перебилдить image с non-root USER (USER 10001)
  3. Сменить level namespace на более слабый (baseline вместо restricted) — НЕ для prod
  4. Использовать exemption (только для special workloads, kube-system)
  5. Перенести privileged workload в отдельный namespace c baseline

Связанные уроки:

Симптомы

  • Приложение, использующее SA token для in-cluster API calls, получает 'Unauthorized' или 401. Старые client libraries не handle token rotation. CronJob, запускающийся раз в неделю, может видеть expired token.

Причина

TokenRequest bound tokens (v1.22+) auto-rotated каждый час, library должна re-read /var/run/secrets/kubernetes.io/serviceaccount/token Legacy long-lived token Secret deprecated в v1.24+, не создаётся automatically Изменилась audience у token (если used kubectl create token --audience) automountServiceAccountToken: false — token не mounted вообще SA удалён — token invalid

Решение

  1. Обновить client library до использующей file watch или re-reading token (client-go это делает auto)
  2. Использовать TokenRequestProjection в Pod spec с expirationSeconds
  3. Для legacy approach — manually create Secret типа kubernetes.io/service-account-token (но deprecated)
  4. Restart Pod чтобы получить свежий token
  5. Установить automountServiceAccountToken: true

Связанные уроки:

Симптомы

  • Pod рестартится каждые ~30-60 секунд. kubectl describe — Events: 'Liveness probe failed: HTTP probe failed with statuscode: ...' или connection refused. restartCount растёт.

Причина

Probe настроен на неверный path / port initialDelaySeconds слишком мал — приложение ещё не запустилось App slow startup без startupProbe — liveness валит до того как app ready App overload — health endpoint медленный, timeoutSeconds слишком мал DNS/dependency check в health endpoint — fail при transient issues Liveness слишком aggressive (failureThreshold: 1) — flapping GC pause / IO stalls делают app temporarily unresponsive

Решение

  1. Согласовать probe path/port с приложением
  2. Добавить startupProbe с failureThreshold * periodSeconds покрывающим startup time
  3. Увеличить initialDelaySeconds или периодичность
  4. Увеличить timeoutSeconds (default 1s часто мало)
  5. Liveness endpoint должен быть LIGHTWEIGHT — никаких DB checks (это readiness)
  6. Failure threshold: 3 (default) или больше для tolerance
  7. Если в коде long GC — fix или увеличить probe timeouts

Связанные уроки:

Симптомы

  • Pod в CreateContainerConfigError, или Pod стартует но fail: env var пустой, файл отсутствует. Events: 'couldn't find key XYZ in ConfigMap'.

Причина

Опечатка в configMapKeyRef.key ConfigMap создан без этого ключа (data: пустой или другой) ConfigMap обновили — старый ключ удалён envFrom без prefix — переменные ENV с дефисом в ключе ConfigMap игнорируются Case-sensitivity в имени ключа

Решение

  1. Добавить недостающий key в ConfigMap: kubectl edit cm <name>
  2. Использовать optional: true в configMapKeyRef если key опционален
  3. Для invalid ENV-name keys использовать volume mount вместо env
  4. Зафиксировать соглашение naming (только [A-Z][A-Z0-9_]*)

Связанные уроки:

Симптомы

  • kubectl rollout status deployment висит, потом 'error: deployment exceeded its progress deadline'. kubectl get deploy показывает READY: 2/5, не движется. Старый ReplicaSet остался scaled, новый — частично готов.

Причина

Новые Pods не становятся Ready: readiness probe fails, или crash ImagePullBackOff на новых Pods Quota / limit достигнут — новые Pods не schedule maxSurge=0 + maxUnavailable=0 — невозможно сделать ни одного шага progressDeadlineSeconds слишком короткий для медленного rollout PDB запрещает evict старых Pods (minAvailable > replicas - 1)

Решение

  1. Fix root cause в новых Pods: image, probes, config
  2. kubectl rollout undo deployment/<name> — откат на предыдущий RS
  3. Увеличить progressDeadlineSeconds в Deployment
  4. Скорректировать maxSurge/maxUnavailable хотя бы одно ненулевое
  5. Скорректировать PDB чтобы можно было evict
  6. kubectl rollout pause, fix manually, kubectl rollout resume

Связанные уроки: