Events и kubectl describe
Event — это полноценный объект Kubernetes API (apiVersion: v1, kind: Event или новый events.k8s.io/v1), не просто запись в логе. У него есть namespace, lifecycle, RBAC. Компоненты Kubernetes — scheduler, kubelet, controllers, admission webhooks — пишут события в etcd как способ сказать клиенту: «вот что произошло с твоим ресурсом». TTL — 1 час. Если ты не успел посмотреть, событие уйдёт навсегда.
journalctl: единый журнал systemd для всех сервисов
Что такое Event
apiVersion: v1
kind: Event
metadata:
name: my-pod.16f7e2c5a3d9
namespace: default
type: Warning
reason: FailedScheduling
message: "0/3 nodes are available: 3 Insufficient memory."
source:
component: default-scheduler
involvedObject:
apiVersion: v1
kind: Pod
name: my-pod
namespace: default
uid: ...
firstTimestamp: "2026-05-13T10:00:00Z"
lastTimestamp: "2026-05-13T10:03:21Z"
count: 4
Ключевые поля:
type:Normal(информация) илиWarning(что-то пошло не так — обычно это и интересно).reason: машино-читаемый код. Типовые:Scheduled,FailedScheduling,Pulled,Failed,Created,Started,Killing,BackOff,Unhealthy,FailedMount.message: человеческое описание.source: кто создал событие.scheduler,kubeletна ноде X,deployment-controller, и т.д.involvedObject: на какой ресурс ссылается.firstTimestamp/lastTimestamp/count: повторяющиеся события схлопываются в один объект с инкрементом count, чтобы не плодить тысячи дубликатов.
TTL: 1 час и что с этим делать
В apiserver есть флаг --event-ttl=1h (default). Через час Event удаляется из etcd навсегда. Это сделано специально:
- Events часто и пишут много — у активного кластера тысячи событий в час.
- Хранить их вечно — раздувать etcd.
- Это transient signal, а не audit log. Для audit-а нужен apiserver
--audit-log-pathили внешний сборщик.
Для долгосрочной аналитики:
- kube-state-metrics + Prometheus — конвертирует event reasons в metrics (например, счётчик
kube_pod_status_reason{reason="ContainerCreating"}). - Logging stack (Loki / ELK) собирает events отдельным DaemonSet (например, через
eventrouter). - Audit log на apiserver — пишет всё, что прошло через API, включая создание событий.
Не полагайся на Events для post-mortem спустя сутки — они уже удалены. Сразу при инциденте делай kubectl get events -n <ns> -o yaml > events.yaml и копай оттуда.
kubectl get events vs kubectl events
Старый способ:
kubectl get events
kubectl get events -n production
kubectl get events --sort-by=.lastTimestamp # хронологически
kubectl get events --field-selector type=Warning # только warnings
kubectl get events --field-selector involvedObject.name=my-pod
Default-сортировка kubectl get events — по metadata.name (бесполезно). Всегда добавляй --sort-by=.lastTimestamp, иначе порядок случайный.
Новая команда — kubectl events (GA с v1.27, лучше UX):
kubectl events # уже отсортированы хронологически
kubectl events -n production
kubectl events --for pod/my-pod # удобный filter на involvedObject
kubectl events --watch # follow, как logs -f
kubectl events --types=Warning
kubectl events --watch — лучший способ смотреть, что происходит во время rolling update Deployment или при отладке scheduling issue.
kubectl describe: spec + status + Events в одном
describe — это не просто YAML-дамп. Это сформированный человеком вывод, где:
- В верхней части — основные поля spec (labels, annotations, containers, volumes).
- В середине — status (conditions, containerStatuses).
- В нижней —
Events:секция, отфильтрованная поinvolvedObject.uidресурса.
Именно эта Events-секция делает describe основным debug-tool:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m17s default-scheduler Successfully assigned default/my-pod to node-1
Normal Pulling 3m16s kubelet Pulling image "myapp:v2"
Normal Pulled 3m10s kubelet Successfully pulled image
Normal Created 3m10s kubelet Created container app
Normal Started 3m9s kubelet Started container app
Warning Unhealthy 2m45s kubelet Readiness probe failed: dial tcp 10.244.0.5:8080: connect: connection refused
Warning BackOff 1m30s kubelet Back-off restarting failed container
Этот хронологический trace отвечает на 80% вопросов отладки. Видно: image pull прошёл, container запущен, потом readiness FAIL, потом restart loop.
Типовая CKAD-задача: Pod в Pending
Дано: kubectl get pod my-pod показывает Pending. Диагностика:
# 1. Что говорит Pod о себе
kubectl describe pod my-pod
# 2. Events секция в конце вывода — главное
# Возможные сценарии:
# 2a. FailedScheduling: "0/3 nodes are available: 3 Insufficient cpu"
# → cpu requests > доступной ёмкости нод. Уменьшить requests или добавить ноды.
# 2b. FailedScheduling: "node(s) had untolerated taint {dedicated: gpu}"
# → Pod должен иметь tolerations для taint-а.
# 2c. FailedScheduling: "node(s) didn't match Pod's node affinity"
# → spec.affinity не находит matching ноды.
# 2d. Нет ни одного FailedScheduling, Pod просто Pending
# → PVC bound? kubectl describe pvc <name>. Если Pending — нет PV или StorageClass.
# 3. Если Pod привязан к ноде но container не стартует:
kubectl describe pod my-pod | tail -30
# Ищем: ImagePullBackOff, ErrImagePull, CreateContainerConfigError, etc.
# 4. Если уже Running но restart loop:
kubectl logs my-pod --previous
kubectl describe pod my-pod | grep -A 10 'Last State'
Pending без событий через 30+ секунд — обычно проблема с PVC: storage не выделился. kubectl describe pvc <name> покажет, ждёт ли он provisioner-а или StorageClass отсутствует.
Field selectors на events
Events не поддерживают label selectors (на них нет labels), но field selectors — да:
# Все events для конкретного Pod-а
kubectl get events --field-selector involvedObject.name=my-pod
# Все Warning-events в namespace
kubectl get events --field-selector type=Warning -n production
# Events от kubelet конкретной ноды
kubectl get events --field-selector source.component=kubelet,source.host=node-1
Killer-моменты
- Events живут 1 час. Никаких post-mortem спустя сутки.
--sort-by=.lastTimestampобязателен вkubectl get events, иначе порядок случайный. Уkubectl eventsсортировка по умолчанию.kubectl describeEvents section — первое место смотреть при любых проблемах с Pod. CKAD-задача «Pod не работает» в 80% случаев решается через describe.- Events схлопываются по
involvedObject + reason. Полеcountпоказывает, сколько раз произошло;firstTimestamp/lastTimestamp— окно. FailedSchedulingmessage содержит причины — читай внимательно, scheduler перечисляет все predicates, которые failed на каждом узле.