14 KiB
14 KiB
Runbook эксплуатации Kubernetes модуля
Документ относится к приложению AppsTemplate (модуль Kubernetes в веб-платформе). Репозиторий kind-k8s-develop хранит этот runbook рядом с утилитами локального kind.
Автор: Сергей Антропов
Сайт: https://devops.org.ru
1. Кластер недоступен
- Симптомы:
GET /api/v1/k8s/clusters/{id}/healthвозвращаетunreachable, preflight показывает ошибку connectivity. - Проверки:
- Валиден ли kubeconfig кластера в записи
k8s_clusters. - Доступен ли API endpoint кластера из контейнера приложения.
- Не истекли ли сертификаты/токены в kubeconfig.
- Валиден ли kubeconfig кластера в записи
- Действия:
- Обновить kubeconfig кластера через
PATCH /api/v1/k8s/clusters/{id}. - Повторно запустить health-check с
force=1. - При необходимости временно отложить массовую выдачу доступов.
- Обновить kubeconfig кластера через
1.1. Docker Desktop: kubeconfig с 127.0.0.1, приложение в контейнере
- Симптом: health-check и любые вызовы API кластера из приложения дают
unreachable, хотяkubectlс хоста работает. - Причина: в kubeconfig
server: https://127.0.0.1:…означает «loopback того процесса, который подключается». Внутри контейнера127.0.0.1— это не хост с Docker Desktop. - Что сделать: в записи кластера заменить адрес API на тот, который виден из контейнера приложения:
- macOS / Windows, Docker Desktop: обычно
https://host.docker.internal:ПОРТ(тот же порт, что был у127.0.0.1, часто6443). - Linux: при необходимости добавить в
docker-composeдля сервиса приложенияextra_hosts: ["host.docker.internal:host-gateway"]и использоватьhost.docker.internal, либо указать IP шлюза к хосту / LAN-IP.
- macOS / Windows, Docker Desktop: обычно
- Имя вида
Something.local(Bonjour / mDNS): с Mac такое имя обычно резолвится на хосте, но внутри контейнера приложения часто не резолвится — health-check снова будетunreachableпри том же kubeconfig. Для Docker Desktop надёжнееhttps://host.docker.internal:6443(или фиксированный LAN-IP Mac), а не*.local. - Только IPv6 у
host.docker.internal: если в контейнереgetent hosts host.docker.internalпоказывает один адресfdc4:...(IPv6), а API слушает IPv4, соединение может не установиться. В репозитории AppsTemplate для сервисаappвdocker-compose.ymlзаданоextra_hosts: ["host.docker.internal:host-gateway"]— послеdocker compose up -dперепроверьтеgetent(должен появиться маршрут через IPv4-шлюз хоста). Kubeconfig:server: https://host.docker.internal:6443. - TLS / hostname mismatch: при
server: https://host.docker.internal:6443сертификат API чаще всего выписан не на это имя → ошибка видаCERTIFICATE_VERIFY_FAILED/Hostname mismatch.GET /clusters/{id}/healthсначала подключается с kubeconfig из БД; при типичной ошибке TLS выполняется вторая попытка с временной копией, где для cluster изcurrent-contextвключёнinsecure-skip-tls-verify(в БД ничего не пишется). В ответе может бытьtls_insecure_fallback_used: true. Для apply RBAC / выдачи доступов по-прежнему нужен рабочий TLS в сохранённом kubeconfig или явныйinsecure-skip-tls-verifyв YAML. - Явный insecure в kubeconfig (рекомендуется для dev, если нужны не только health): в записи того же
clusterдобавьтеinsecure-skip-tls-verify: true. Пример фрагмента:В production так не делают: тамclusters: - name: docker-desktop cluster: server: https://host.docker.internal:6443 insecure-skip-tls-verify: true # certificate-authority-data: ... # при insecure можно убрать, чтобы не путатьсяserverи SAN в сертификате должны совпадать, проверка TLS включена. - Обновление kubeconfig: UI «Редактировать кластер» (
/k8s/clusters/{id}/edit) илиPATCH /api/v1/k8s/clusters/{id}.
2. Частично примененные манифесты RBAC
- Симптомы: часть пользователей получила доступ, часть — ошибки в
POST /api/v1/k8s/access/bulk. - Проверки:
- Использовать preflight (
/access/preflight,/access/bulk/preflight) перед повторной операцией. - Проверить существующие активные записи в
k8s_user_configs. - Проверить аудит
k8s_access_audit.
- Использовать preflight (
- Действия:
- Повторить операцию с
idempotency_keyтолько после устранения причины. - Для конфликтных пользователей выполнить точечный revoke/restore или delete/create.
- Если обнаружены дубликаты, очистить лишние записи и заново выдать доступ.
- Повторить операцию с
3. Восстановление после ошибок миграций
- Симптомы: ошибки
UndefinedTableErrorпри старте приложения. - Проверки:
- Убедиться, что применены миграции модуля из
app/db/migrations/modules/k8s/(репозиторий AppsTemplate). - Проверить наличие таблиц
k8s_*в БД.
- Убедиться, что применены миграции модуля из
- Действия:
- Применить восстановительную миграцию
app/db/migrations/102_k8s_repair_missing_tables.sql. - Перезапустить приложение.
- Проверить работу API
GET /api/v1/k8s/health.
- Применить восстановительную миграцию
4. Ротация ключа шифрования kubeconfig
- Основной источник ключа: настройка в БД
k8s.kubeconfig_encryption_key(страница Настройки → Модули → Kubernetes). При непустом значении в БД оно имеет приоритет над переменной окружения. - Резерв:
K8S_KUBECONFIG_ENCRYPTION_KEYв.env— используется только если в БД ключ пустой (удобно для первого запуска и CI; см.env.exampleв AppsTemplate). - Рекомендуемый порядок смены ключа:
- Перевести сервис в окно обслуживания.
- Считать и дешифровать существующие значения из
k8s_clusters.kubeconfig_encryptedиk8s_user_configs.kubeconfig_encryptedтекущим ключом (из БД или ENV — в том же порядке приоритета, что у приложения). - Перешифровать новым ключом и сохранить обратно в таблицы.
- Сохранить новый секрет в настройках модуля (или обновить ENV, если используете только резерв).
- Перезапустить приложение при необходимости и проверить health-check и скачивание kubeconfig.
- Важно: не удалять старый ключ до завершения полной перешифровки.
5. Мониторинг и безопасность фоновых задач
- Используйте страницу
/k8s/jobsи APIGET /api/v1/k8s/jobs(пагинацияskip/limit, фильтрstatus) иGET /api/v1/k8s/jobs/{job_id}для полного текста ошибки и результата. - Детальные статусы:
GET /api/v1/k8s/access/jobs/{job_id}GET /api/v1/k8s/access/bulk/jobs/{job_id}GET /api/v1/k8s/kubeconfig/merge/jobs/{job_id}
- Все job-status ответы проходят маскировку чувствительных полей (
kubeconfig,token,secret,password,private_key,certificate). - Для merge-задач поле
result.renderedне возвращается в статусе и доступно только через download endpoint. - Рекомендуется искать инциденты по
correlation_idв логах приложения и в записи задачи вk8s_jobs. - Утилита наблюдаемости:
GET /api/v1/k8s/observability/jobs/{job_id}для задач сjob_type=k8s.observability; UI —/k8s/observability.
6. Утилита стека наблюдаемости (Metrics Server / Prometheus)
- Настройки:
k8s.observability_metrics_server_manifest_url(по умолчанию официальныйcomponents.yamlmetrics-server),k8s.observability_metrics_server_kubelet_insecure_tls,k8s.observability_prometheus_manifest_bundle_url(опционально), таймауты и лимит кластеров за операцию. - Metrics Server: при типичных kubeadm/kind кластерах без корректных kubelet-сертификатов включите
--kubelet-insecure-tls(чекбокс в UI или настройка/тело запроса install). - Prometheus stack: полный
kube-prometheus-stackобычно ставят Helm вне приложения; через API имеет смысл подключать сокращённый multi-doc YAML, где все объекты имеют поддерживаемыеkind. Иначе часть документов попадёт вskippedв ответе задачи. - Откат:
POST .../uninstall/jobsудаляет ресурсы в обратном порядке того же бандла; при ручных правках в кластере возможны остаточные объекты — добейтеkubectl delete/ повторным uninstall.
6.1. Локальный кластер kind для разработки
Этот репозиторий (kind-k8s-develop): образ kind-k8s-tools, make create (Docker и make на хосте) поднимает kind; артефакты — clusters/<имя>/kubeconfig. Импорт kubeconfig в AppsTemplate см. §1.1 (адрес API должен быть достижим из контейнера приложения, не обязательно 127.0.0.1). Краткая инструкция по командам — в README.md в корне этого репозитория.
7. Срок действия доступа (access_expires_at)
- В
POST /access,POST /access/bulkиPATCH /access/{id}можно задать дату окончания; пустое значение в PATCH сбрасывает срок. - Фоновый цикл использует
k8s.access_expiry_check_interval_hours; отзыв выполняется так же, как ручной revoke (RBAC в кластере, уведомление владельцу; в аудитеreason: access_expired). - Уведомление при автоотзыве: в тексте указано «система (автоматически)».
8. Отправка kubeconfig в Telegram
- В настройках модуля задать
k8s.telegram_bot_token. У владельца доступа в профиле — полеtelegram_chat_id(числовой id; миграция105_profile_field_telegram_chat_id.sqlдобавляет описание в реестр полей). - Ссылка
https://t.me/...не подставляет chat_id: пользователь должен написать боту и узнать id (например через @userinfobot), затем сохранитьtelegram_chat_id. POST /api/v1/k8s/access/{config_id}/send-telegram: владелец или лид сmodules.k8s:update. Длинный YAML режется поk8s.telegram_kubeconfig_max_chars— тогда в чат уходит короткое сообщение со ссылкой на/k8s/my-configs.
9. Дрейф RBAC и сверка с кластером (reconcile)
- Симптом: в UI на карточке кластера колонка «Сверка RBAC» показывает
drift_detectedилиsync_error, либо администратор вручную удалил Role/Binding в кластере. - Проверки:
POST /api/v1/k8s/access/{config_id}/reconcile-check(или кнопка «Сверка» на вкладке «Доступы») — пересчитать статус по сохранённымrbac_manifests.- Убедиться, что у записи доступа непустые
rbac_manifests(иначе сначалаapply-manifestsили PATCH с пересборкой).
- Действия при дрейфе:
POST /api/v1/k8s/access/{config_id}/apply-manifests— повторное применение; после успешного apply статус сверки обновляется вместе с записью. - Настройки:
k8s.reconcile_check_timeout_seconds, опциональноk8s.reconcile_background_interval_hours(часы между фоновыми прогонами для активных доступов;0— только ручной вызов).