Containerization & Orchestration
«У нас всё в Kubernetes» — в 2026 это звучит как «у нас всё на Linux» десять лет назад: уже не отличительная черта, а фон. И я регулярно вижу команды, где владение k8s сводится к kubectl get pods и копированию манифестов с прошлого проекта. Когда случается нетривиальный инцидент — отстаёт компакция etcd, под завис в Terminating, после обновления посыпался CrashLoopBackOff, политика сети не пускает трафик между пространствами имён, — выясняется, что control plane для команды чёрный ящик с веб-мордой. Этот лист — про то, что нужно знать, чтобы Kubernetes был не «магией платформенной команды», а наблюдаемой системой: контейнер как процесс (см. Operating Systems), под как единица планирования, control plane как набор перекликающихся контроллеров.
У меня есть свой проект orb-k8s-gitops — шаблон выкатки приложений в несколько контуров k8s через Helmfile, с явным разделением «приложение», «контур», «значения». Он вырос из боли «как выкатить одно приложение в пять окружений без копипасты», и этот лист во многом про навыки, которые набирались на таких задачах. Граница с соседями: Infrastructure as Code — про то, что разворачивается (включая сам кластер); здесь — про то, как кластер работает после разворачивания. GitOps — про модель доставки; здесь — про сам кластер, в который эта доставка идёт.
Что должен уметь
Заголовок раздела «Что должен уметь»Главный навык на уровне L4 — отлаживать под, не открывая шпаргалку по kubectl. Когда под в CrashLoopBackOff, последовательность примерно одна и та же: kubectl describe pod → события, число рестартов, код выхода → kubectl logs --previous → если контейнер падает раньше логов, kubectl get events --sort-by=.lastTimestamp → если планировщик не размещает, kubectl describe node → taints, нехватка ресурсов, affinity. Это не про память, а про понимание, что контроллер k8s делает на каждом шаге и где он оставляет следы. Я регулярно вижу команды, где эта последовательность есть у двух старших инженеров, а остальные открывают Grafana и ждут, что «оно само починится». День на Kubernetes the Hard Way и kubectl explain по базовым ресурсам заметно меняет качество всех будущих дежурств.
L3
- Понимает, что контейнер — это процесс в пространствах имён и cgroups (см. Operating Systems), а под — группа контейнеров с общей сетью. Различает
Deployment,StatefulSet,DaemonSet,JobиCronJobи знает, для чего каждый. - Работает с базовым
kubectl:get,describe,logs,exec,apply,delete; читает манифест как YAML сapiVersion,kind,metadata,specиstatus.
L4
- Отлаживает под самостоятельно:
describe→ события → логи (включая--previous) →kubectl get events --sort-by=.lastTimestamp. РазличаетImagePullBackOff,CrashLoopBackOff,Pending,EvictedиOOMKilledпо симптому и знает, где искать причину. - Понимает разницу между requests и limits: запросы влияют на планирование, лимиты — на cgroup. Знает, что придушивание по CPU без OOM — типичная причина «под жив, но медленный».
- Настраивает пробы:
liveness(когда перезапускать),readiness(когда убрать под из endpoints сервиса),startup(для медленно стартующих). Понимает, почему liveness без readiness — частая причина «обновление положило сервис». - Отлаживает сеть внутри кластера:
kubectl get svcиendpoints, проверка DNS из отладочного пода,NetworkPolicy, логи контроллера ingress.
L5
- Управляет нагрузками через GitOps (см. GitOps): шаблоны Helm и Kustomize, разделение значений по окружениям, обнаружение расхождений в ArgoCD и Flux. В
orb-k8s-gitopsу меня как раз пример схемы «приложение — окружение — значения». - Понимает control plane: kube-apiserver, etcd, controller-manager, scheduler, kubelet; знает, где лежат токены (
/var/run/secrets/kubernetes.io/serviceaccount/), как работает RBAC (Role,ClusterRole, привязки), что означает отказ вебхука admission. - Проектирует политики на весь кластер: PodSecurity (в современных версиях — PSA), квоты и лимиты на пространства имён,
NetworkPolicyс запретом по умолчанию и явными разрешениями. - Различает виды состояния: временное хранилище (
emptyDir), постоянное (PersistentVolume,PersistentVolumeClaim,StorageClass) и внешнее (управляемая база черезServiceилиExternalName). Знает, чтоStatefulSetдаёт стабильную идентичность, а не надёжность.
L6+
- Оценивает размен между своим кластером и управляемым (EKS, GKE, AKS, managed-k8s у облаков — см. Cloud Providers). Понимает, что уходит провайдеру (доступность control plane, etcd, обновления) и что остаётся команде (узлы, дополнения, сеть, наблюдаемость).
- Планирует обновления: с каким ритмом брать минорные версии, чем ловить устаревшие API (
pluto,kube-no-trouble), как крутить пулы узлов, когда снимать копию etcd. Готов к неприятным случаям: заклинивший PDB, бессмертные поды, циклы вебхуков. - Учит команду: разбирает инциденты в k8s как демонстрацию, ведёт планы обновлений, записывает инварианты кластера — то, что ломать нельзя, — в runbook’ах.
Материалы
Заголовок раздела «Материалы»- Kelsey Hightower, Brendan Burns, Joe Beda — Kubernetes: Up & Running (O’Reilly, 3-е изд., 2022). Если выбирать одну книгу для входа — эту. Авторы — те же люди, что строили Kubernetes в Google; идиоматика правильная.
- Marko Lukša — Kubernetes in Action (Manning, 2-е изд., 2023). Более инженерная альтернатива: больше про как устроено, меньше про как пользоваться. Глава про внутренности control plane — лучшая, что я видел в открытом доступе.
- Liz Rice — Container Security (O’Reilly, 2020). Уже упомянута в Operating Systems; здесь особенно интересны главы про среду исполнения контейнеров и модель безопасности k8s.
- Bilgin Ibryam, Roland Huß — Kubernetes Patterns (O’Reilly, 2-е изд., 2023). Каталог паттернов проектирования нагрузок: sidecar, инициализирующие контейнеры, ambassador, выбор лидера. По моим наблюдениям, эти паттерны спасают команды от изобретения «своего оператора» там, где задача типовая.
Статьи и доклады
Заголовок раздела «Статьи и доклады»- Kelsey Hightower — Kubernetes the Hard Way. Пошаговый подъём кластера без
kubeadm. Не для прода — для расколдовывания. Один день этого упражнения, и control plane перестаёт быть магией. - Julia Evans — How Containers Work (wizardzines). Отдельного зина по Kubernetes у неё нет, но этот объясняет слой под ним — пространства имён, cgroups, образы. Жанр — один концепт на страницу, и для тех, кто отскакивает от пятисотстраничных книг, это лучший вход.
- Kubernetes the Documentary (CNCF, 2022). Полтора часа про то, как Kubernetes появился. Не учебник, зато становится понятно, откуда растут его архитектурные решения.
- CNCF — отчёты и материалы фонда. Там же публиковались чек-листы готовности кластера к продакшену по доменам: наблюдаемость, безопасность, сеть, хранилище. Отдельные PDF периодически переезжают, поэтому ищите по названию, а не по прямой ссылке.
- Reddit Pi Day Outage 2023-03-14 postmortem — публичный разбор инцидента при обновлении кластера, см. ниже.
Инструменты
Заголовок раздела «Инструменты»kubectl— основной CLI. По моим наблюдениям, разница между инженером, который свободно живёт в k8s, и тем, кто нет, — этоkubectl get events --sort-by=.lastTimestamp,kubectl explain,kubectl debug(с версии 1.25) и привычка к--dry-run=server.- k9s — текстовый интерфейс поверх kubectl. По моим наблюдениям, чаще всего берут именно его; lens и headlamp — на любителя.
- Helm / Kustomize — упаковка и шаблонизация манифестов. Helm — индустриальный стандарт для сторонних чартов; Kustomize встроен в
kubectlи проще для своих приложений без сложных шаблонов. - Helmfile — декларативная обёртка над Helm для нескольких релизов и окружений. Использую в
orb-k8s-gitops: даёт структуру «приложение × окружение» без копипасты значений. - ArgoCD / Flux — операторы GitOps (см. GitOps). ArgoCD использую в
evo-tf-argocd— демо для Cloud.ru Evolution Managed Kubernetes. - kind / k3s / minikube — локальный k8s для разработки. По моим наблюдениям, в 2026 чаще берут
kindдля CI иk3sдля периферии и IoT. - kube-no-trouble / pluto — поиск устаревших API перед обновлением. В конвейере обновления обязательны.
- stern / kail — логи сразу из многих подов. Когда у сервиса десять реплик, читать
kubectl logsпо одному — пытка.
Best practices
Заголовок раздела «Best practices»Хороший публичный пример того, насколько непросты операции в k8s, — отказ Reddit 14 марта 2023 года. Команда выполняла рутинное обновление с 1.23 на 1.24; кластер деградировал больше чем на пять часов, потому что новый релиз изменил поведение Calico при определённой конфигурации сетевых политик. Постмортем опубликован и разобран подробно: команда сделала всё по учебнику — обновила стейдж, раскатывала последовательно, — но баг проявился только под продовой нагрузкой. Я регулярно ссылаюсь на этот разбор как на лучший пример того, что обновление k8s — это не проставить тег в git: между минорными версиями меняются поведение API, умолчания у контроллеров admission, семантика плагинов CNI и CSI. Здравый порядок — отдельное окно обслуживания, план отката до старта и никаких других изменений в том же окне. Одно окно — одно изменение.
Три вещи ломаются чаще прочих.
Liveness без readiness — прямой путь к аварии на обновлении. Liveness перезапускает контейнер, и если приложение медленно прогревается (кеш, JIT, пул соединений), его убьют раньше, чем оно обслужит первый запрос. Readiness же просто держит под вне endpoints сервиса, пока тот не готов. Без неё обновление пускает трафик на непрогретый под. Отдельный антипаттерн — скопировать адрес readiness в liveness и считать дело сделанным.
Лимит по CPU — это придушивание в cgroup, а не магия изоляции. Поставили лимит в одно ядро, и под начинает тормозить даже при свободных ядрах на узле, потому что выбрана квота периода. По моим наблюдениям, на реальных нагрузках лимиты по CPU приносят больше проблем, чем пользы; запросы без лимитов — вполне уважаемое умолчание (см. обсуждение в k8s SIG-node). С памятью наоборот. Без лимита по памяти OOM-killer срабатывает уже на уровне узла и выбирает жертву совсем не так, как хотелось бы вам.
Третье — сеть. Кластер без политик плоский, как стол: любой под говорит с любым. В инциденте уровня «в одно пространство имён приехал скомпрометированный образ» это разница между «пострадал один сервис» и «дальше открыта дорога ко всем остальным». Запрет по умолчанию плюс явные разрешения — это один PR на пространство имён. Не проект.
Под — единица планирования, а не единица приложения. Я регулярно вижу сервисы, упакованные в под из двух контейнеров: основной и вспомогательный. У вспомогательного нет своего жизненного цикла, отдельно он не масштабируется, перезапускается вместе с основным. А ресурсы ест полноценно. Здоровая модель: под — набор контейнеров, которые живут и умирают вместе (sidecar под логи, инициализирующий контейнер под миграции, временный контейнер под отладку). Всё остальное — отдельные Deployment с Service между ними. Паттерн разобран в «Kubernetes Patterns» как разница между sidecar, adapter и ambassador.
Манифест без запросов ресурсов — сирота для планировщика. Планировщик выбирает узел по spec.containers[*].resources.requests. Без них под попадает в класс BestEffort: при нехватке памяти ядро выселяет его первым, а планировщик не учитывает его потребление, когда считает свободное место. По моим наблюдениям, кластеры без явных запросов на всех нагрузках живут до первого всплеска потребления памяти, после которого выселяется случайный набор подов и команда не понимает, почему легло именно это. Минимум — requests по CPU и памяти на каждый контейнер, обоснованные замерами из Performance & Profiling.
Обновление — это больше, чем «раз в три месяца». Каждый минорный релиз уносит с собой часть API: policy/v1beta1 для PDB исчез в 1.25, flowcontrol.apiserver.k8s.io/v1beta2 — в 1.29. Без проверки перед обновлением (pluto, kube-no-trouble) команда узнаёт о ломающем изменении в момент упавшей выкатки. Здоровый порядок такой: найти устаревшие API → починить манифесты → обновить стейдж → выдержать не меньше недели → обновить один узел в проде → раскатать остальное. Автомасштабирование кластера и дополнения (cert-manager, контроллер ingress, CNI) — отдельная ось совместимости; обновление k8s без обновления дополнений и порождает большую часть «странных багов».
Копия etcd перед каждым серьёзным изменением — не паранойя. Всё состояние кластера живёт в etcd. Снять снимок — одна команда, etcdctl snapshot save, а восстановление кластера без него после повреждения — это от пары часов до «поднимаем заново». В управляемых кластерах снимок делает провайдер; в своих — забота команды. Я регулярно вижу команды, которые бэкапят приложения и базы, но про etcd не думают: «оно же управляется операторами». До первого случая, когда сбойный вебхук admission оставил кластер в несогласованном состоянии.
Связанные листья
Заголовок раздела «Связанные листья»- Operating Systems — контейнер — это процесс в пространствах имён и cgroups; отладка пода часто заканчивается на уровне ядра (
/proc,nsenter,dmesg). - Networking — оверлейные сети (Calico, Cilium, Flannel), внутренности плагинов CNI, сетевые политики, kube-proxy и IPVS, контроллеры ingress — стык с сетевым доменом.
- Service Mesh — следующий слой поверх трафика между подами: mTLS, перевод трафика, наблюдаемость на уровне L7 через sidecar.
- Cloud Providers — управляемый k8s (EKS, GKE, AKS, Yandex Managed Kubernetes) сдвигает границу ответственности: control plane живёт у провайдера.
- Infrastructure as Code — кластер разворачивается через Terraform или Pulumi; манифесты — следующий слой того же декларативного подхода.
- GitOps — Argo CD и Flux синхронизируют git с состоянием кластера; естественный механизм доставки для всего, что живёт в k8s.
- Resilience Patterns —
PodDisruptionBudget,HorizontalPodAutoscaler, ограничения на распределение по зонам — родные для k8s реализации тех же паттернов устойчивости. - Capacity Planning — запросы и лимиты плюс автомасштабирование кластера переводят планирование мощностей в декларативный формат.
Открытые вопросы
Заголовок раздела «Открытые вопросы»Операторы и CRD — отдельная подобласть: как писать оператор, когда оправдан свой ресурс, а когда хватит обычного Deployment. Возможно, отдельный лист в будущем; пока тема живёт здесь через паттерны.
Сеть на eBPF (Cilium) против iptables (Calico, Flannel). Cilium становится стандартом, но решений на iptables в проде по-прежнему большинство. Где проходит граница «пора мигрировать», я не знаю.
Несколько кластеров сразу — федерация, virtual kubelet, Cluster API. Большинству команд хватает одного кластера на окружение, а несколько добавляют отдельный класс сложности, который я в проде не разворачивал. Есть опыт — расскажите через PR.
Service Mesh как обязательный слой обсуждается в листе Service Mesh. Короткий ответ там такой. Чаще нет, чем да.