Поздравляю — если вы дошли до этой главы, у вас на ноутбуке крутится настоящий Kubernetes, в нём живёт ваш myapp, рядом стоит PostgreSQL, а правка кода прилетает в кластер за секунды. Давайте подведём итог и поговорим о том, куда двигаться дальше, когда базовая локалка перестанет вас удивлять.

Что мы построили: итог

Вспомним весь путь. Мы собрали локальное окружение, которое ведёт себя примерно так же, как продакшен, — то, что в начале статьи мы назвали production-like окружением (см. главу 2). По кусочкам это выглядит так:

  • Локальный кластер. Лёгкий Kubernetes через k3d (k3s внутри Docker) с именем dev, namespace myapp и встроенным реестром образов k3d-registry.localhost:5000 (см. главу 5). Это не «эмуляция» Kubernetes, а настоящий кластер — просто маленький.
  • Образ сервиса. Dockerfile для Python 3.12 + FastAPI, который собирается в тот же образ, что поедет в прод (см. главу 6).
  • Реальные манифесты Kubernetes. Deployment, Service, Ingress — настоящие YAML-объекты, а не docker-compose.yml. Это ключевая мысль всей статьи: локально вы гоняете ровно те же манифесты, что и в проде, поэтому ошибки в них (опечатка в selector, забытый порт, кривой Ingress) ловятся на ноутбуке, а не после выкатки (см. главу 7).
  • Быстрый inner loop. Tilt пересобирает образ и обновляет под при каждом сохранении файла, так что цикл «поменял код → увидел результат» (тот самый inner dev loop из главы 1) занимает секунды, а не минуты (см. главу 8).
  • Зависимости рядом. PostgreSQL поднят прямо в кластере, а не «где-то на стейджинге» (см. главу 9).
  • Конфигурация и секреты через ConfigMap и Secret, а не хардкодом (см. главу 10).
  • Здоровье и ресурсы. liveness- и readiness-пробы, requests/limits на CPU и память — то, что обычно забывают новички и за что больно расплачиваются в проде (см. главу 13).
  • Наблюдение за кластером глазами через kubectl и k9s (см. главу 12).

Главная ценность всего этого — паритет окружений. Проблемы манифестов, RBAC, сетевых политик и service discovery вы видите локально, а не узнаёте о них из алертов в три часа ночи.

Чек-лист хорошего локального окружения

Держите под рукой короткий список. Если все пункты отмечены — ваша локалка действительно похожа на прод, а не притворяется.

  • Та же версия Kubernetes и те же аддоны, что в проде. Если в проде 1.30 и Ingress NGINX — пусть и локально будет так же. Разъезд версий — источник «у меня работало».
  • Реальные манифесты (Helm/Kustomize), а не docker-compose. Один и тот же набор YAML для локалки и прода, с подстановкой значений через values или overlay.
  • requests и limits на CPU/память у каждого контейнера. Без них под может либо голодать, либо съесть всю ноду. Локально это ещё и страхует ваш ноутбук.
  • liveness-проба. Kubernetes сам перезапускает зависший контейнер. Для myapp это простой GET /healthz, который только подтверждает «процесс жив» и не ходит в зависимости. См. документацию по пробам.
  • readiness-проба. Под выводится из эндпоинтов Service, пока не готов принимать трафик, — но без перезапуска. Для myapp это GET /ready, который проверяет коннект к PostgreSQL (детально разница liveness и readiness разобрана в главе 13).
  • ConfigMap/Secret вместо значений в коде. Конфиг отделён от кода — это идея dev/prod parity из 12-factor app.
  • Ingress как в проде. Если снаружи в прод ходят через Ingress — ходите так же и локально, чтобы поведение маршрутизации совпадало (см. главу 11).
  • Быстрый inner loop. Сохранил файл — увидел результат за секунды. Если каждый цикл — это ручная пересборка и kubectl apply, вы будете избегать кластера, а это убивает всю затею.

Это чек-лист именно про паритет окружений. Когда дело дойдёт до реальной выкатки, сверьтесь ещё и с production-readiness чек-листом из главы 13, где разобраны graceful shutdown, rolling update и QoS-классы.

Дальше — три направления, куда расти. Это уже не «обязательная программа» для новичка, а расширения, которые имеет смысл подключать по мере роста проекта и команды. Не пытайтесь внедрить всё сразу.

Куда копать дальше: GitOps (ArgoCD/Flux)

Пока вы один и деплоите через kubectl apply или Tilt — это нормально. Но когда команда и количество окружений растут, появляется вопрос: «а какое состояние сейчас в кластере и кто его туда положил?». Ответ — GitOps: единственным источником правды становится Git-репозиторий, а специальный контроллер в кластере непрерывно приводит реальное состояние к описанному в Git.

Два главных инструмента, оба со статусом CNCF Graduated (высшая степень зрелости в фонде):

  • Argo CD — декларативный GitOps CD. Контроллер сравнивает живое состояние кластера с тем, что в Git, помечает расхождения как OutOfSync и синхронизирует. Понимает Helm, Kustomize, Jsonnet и просто YAML. Главная фишка для новичка — богатый веб-интерфейс, где приложение (CRD Application) видно как дерево объектов с подсветкой статусов. Умеет в multi-cluster, SSO и RBAC. Argo принят в CNCF и получил статус Graduated.
  • Flux — это GitOps Toolkit, набор контроллеров (source, kustomize, helm, notification). Из коробки умеет image automation (сам обновляет тег образа в Git, когда вышла новая сборка) и работу с OCI-реестрами («Gitless GitOps»). Flux тоже CNCF Graduated. Нюанс: нативного веб-UI у Flux нет — для дашборда ставят сторонние инструменты вроде Weave GitOps или Capacitor. Так что обещанной «кнопочной» панели, как у Argo CD, из коробки не ждите.

Частый на практике паттерн: Argo CD для приложений (удобный UI разработчикам) и Flux для инфраструктуры. Но это не догма — выберите один и начните с него.

Попробовать Argo CD локально в вашем же dev-кластере можно за пару команд:

bash
1helm repo add argo https://argoproj.github.io/argo-helm
2helm install argocd argo/argo-cd -n argocd --create-namespace
3
4# доступ к веб-интерфейсу ArgoCD
5kubectl port-forward svc/argocd-server -n argocd 8080:443
6
7# зарегистрировать приложение из вашего репозитория
8argocd app create myapp \
9  --repo https://github.com/<user>/<repo>.git \
10  --path k8s \
11  --dest-server https://kubernetes.default.svc \
12  --dest-namespace myapp

С Flux вход обычно через bootstrap прямо в Git:

bash
1flux bootstrap github \
2  --owner=<user> \
3  --repository=<repo> \
4  --path=clusters/dev

Observability-стек (Prometheus, Grafana, OpenTelemetry)

В главе 12 мы смотрели на кластер «руками» — через kubectl logs и k9s — и там же вводили три столпа наблюдаемости (метрики, логи, трейсы). Следующий уровень — собирать их системно, а не глазами.

Самый быстрый способ получить полный стек метрик — kube-prometheus-stack, Helm-чарт от сообщества prometheus-community. Одной командой он ставит Prometheus Operator, сам Prometheus, Alertmanager, Grafana, kube-state-metrics и node-exporter — плюс готовые дашборды и правила алертов:

bash
1helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
2helm install kps prometheus-community/kube-prometheus-stack \
3  -n monitoring --create-namespace
4
5# Grafana (логин по умолчанию admin / prom-operator)
6kubectl port-forward svc/kps-grafana -n monitoring 3000:80

Важная оговорка: этот стек тяжёлый. Prometheus, Grafana и операторы вместе способны положить слабенький k3d-кластер. На ноутбуке с небольшим объёмом памяти отключайте ненужные компоненты в values или ограничивайте requests, иначе кластер начнёт задыхаться.

Чтобы Prometheus собирал метрики именно вашего myapp, не нужно править его конфиг вручную. Prometheus Operator вводит CRD ServiceMonitor и PodMonitor: вы просто описываете, какой Service скрейпить, через label-селекторы, без Prometheus-специфичного языка:

yaml
1apiVersion: monitoring.coreos.com/v1
2kind: ServiceMonitor
3metadata:
4  name: myapp
5  namespace: myapp
6  labels:
7    release: kps   # чтобы наш Prometheus подхватил этот монитор
8spec:
9  selector:
10    matchLabels:
11      app: myapp
12  endpoints:
13    - port: http     # имя порта из Service
14      path: /metrics
15      interval: 15s

(Для этого myapp должен отдавать метрики в формате Prometheus — например, через библиотеку prometheus-fastapi-instrumentator на эндпоинте /metrics.)

Метрики — это половина наблюдаемости. Вторая половина — трейсы и логи, и здесь индустрия сходится на OpenTelemetry: это vendor-neutral observability-фреймворк под крылом CNCF с тремя сигналами — traces, metrics, logs. У него есть SDK (с авто-инструментацией для популярных фреймворков, включая FastAPI) и Collector, который принимает, обрабатывает и экспортирует телеметрию куда угодно. Типичное направление развития: ставят OpenTelemetry Collector, метрики уводят в Prometheus, трейсы — в Tempo, логи — в Loki, и всё это смотрят в одной Grafana. Прелесть подхода в том, что один и тот же стек масштабируется от локального k3d до большого продакшена.

Подключение к удалённому кластеру (Telepresence/mirrord) для тяжёлых случаев

Эти инструменты мы вводно упоминали в обзоре в главе 3; здесь — короткое резюме с акцентом на то, когда их вообще доставать.

Локальный кластер закрывает большинство задач. Но бывают «тяжёлые случаи»: сервис тянет за собой десяток зависимостей, которые дорого или невозможно поднять на ноутбуке, или вам нужно отлаживать код против данных и соседей из реального (стейджингового) кластера. Тогда помогают инструменты, которые соединяют ваш локальный процесс с удалённым кластером.

  • Telepresence (open source) — поднимает «удалённое dev-окружение»: вы ставите клиент на свою машину и traffic manager в кластер, после чего ваш локальный код, IDE и дебаггер работают так, будто запущены внутри кластера. Механизм intercept перенаправляет трафик выбранного сервиса на ваш локальный порт. Работает по модели VPN/tun и поэтому требует root-прав на машине плюс установки компонента в кластер — путь мощный, но не самый лёгкий.
    bash
    1telepresence helm install
    2telepresence connect
    3telepresence intercept myapp --port 8080:80
  • mirrord — запускает ваш локальный бинарник так, будто он живёт внутри пода в кластере, но без root и без контейнеризации. Он инжектит mirrord-layer в ваш процесс и поднимает временный mirrord-agent рядом с целевым подом. Ключевой нюанс — режимы входящего трафика:
    • mirror (по умолчанию) — вашему процессу присылается копия входящего трафика. Безопасно для общих dev-кластеров: вы видите запросы, но не забираете их у других.
    • steal — ваш процесс перехватывает входящий трафик пода. Удобно для отладки, но в общем кластере вы уведёте чужие запросы себе — будьте аккуратны.
    bash
    1# mirror-режим (безопасно для общего окружения)
    2mirrord exec --target pod/<pod> -- uvicorn app.main:app --port 8080
    3
    4# steal-режим (перехват входящего трафика)
    5mirrord exec --target deployment/myapp --steal -- uvicorn app.main:app --port 8080

Сравнение механизмов этих инструментов хорошо разобрано в блоге Kubernetes. Главное: тянитесь к ним только когда локальный кластер реально не вытягивает сценарий. Для повседневной разработки myapp ваша k3d-локалка с Tilt быстрее и проще.

Источники

Хотите вырасти за пределы локального Kubernetes?
Готовы развивать локальное окружение Kubernetes дальше — GitOps, observability-стек или отладка против удалённого кластера? Помогу выбрать и внедрить правильный следующий шаг.