Раздел 5 · К собеседованию — глава 5.2
Защита резюме: вопросы по вашему опыту
Сильное резюме само создаёт сложные вопросы. Если в нём написано «мигрировал мониторинг», вас будут спрашивать не определение Prometheus, а как переносили данные, избегали двойных алертов и проверяли полноту метрик. Эта глава закрывает только такие углубления — по заявленному опыту, без повторения остальных глав.
Главное правило
Каждый сильный пункт резюме подготовьте в формате: контекст → ограничение → ваше решение → проверка → измеримый результат → что сделали бы иначе. Инструмент в этой истории вторичен. «Развернул Grafana» звучит как операция; «убрал слепую зону, добавив метрики JVM, и по ним нашли причину OOM» — как инженерная работа.
§1Как защищать опыт, а не перечислять инструменты
По каждому достижению собеседующий обычно проверяет пять вещей:
- Масштаб. Сколько кластеров, узлов, сервисов, команд, метрик или окружений?
- Ваша зона ответственности. Что решили и сделали именно вы, а что команда или готовый продукт?
- Компромиссы. Почему выбрали этот способ и от чего отказались?
- Безопасность изменения. Как тестировали, откатывали и понимали, что ничего не потеряли?
- Результат. Как изменилась скорость, надёжность, видимость или трудозатраты?
Не придумывайте цифры задним числом. Если точных измерений не было, честная формулировка сильнее: «формально MTTR не считали, но до изменения причину OOM находили по косвенным признакам, после — видели heap, off-heap и рестарты на одном дашборде».
| Пункт опыта | Куда почти наверняка копнут |
|---|---|
| Flux CD / GitOps | Reconcile loop, drift, порядок зависимостей, секреты, rollback |
| VictoriaMetrics / Alertmanager | Кардинальность, recording rules, дедупликация, миграция без слепой зоны |
| JVM Micrometer и OOM | Heap против RSS, cgroup limit, GC, metaspace, direct buffers |
| Keycloak и миграция realm | OAuth 2.0 против OIDC, типы токенов, ключи подписи, совместимость клиентов |
| Vault | Аутентификация без секрет-ноль, leases, unseal, политики, ротация |
| Air-gap контуры | Зеркала, цепочка доверия, обновления, SBOM, воспроизводимость |
| RAID10 / LVM / VM backup | Что переживёт отказ, а что не является бэкапом |
| Операторы Postgres | Reconcile loop, ownership, backup/restore, split-brain |
§2GitOps и Flux: не «Git запускает деплой»
GitOps — это модель, в которой Git хранит желаемое состояние, а агент внутри кластера постоянно сравнивает его с реальностью и устраняет расхождение. Ключевое слово — reconcile. CI может собрать и опубликовать образ, но применять состояние в кластер должен контроллер, а не runner с вечным admin-token.
В Flux полезно уверенно объяснить назначение объектов: source-controller получает Git/Helm/OCI-источник; kustomize-controller применяет Kustomize и обычные YAML; helm-controller ведёт HelmRelease; notification-controller отправляет события. Зависимости между частями задают явно, а готовность — health checks, иначе приложение может примениться раньше CRD, оператора или секрета.
Rollback в GitOps — обычно новый commit, возвращающий желаемое состояние. Но откат манифеста не откатывает данные. Миграция БД должна быть обратно совместимой: сначала добавить новое, выкатить код, перевести трафик, и только потом удалять старое. Иначе старый образ после rollback не сможет работать с новой схемой.
Спросят
«Кто-то сделал kubectl edit. Что будет?» — Если поле контролируется GitOps, следующий reconcile вернёт значение из Git. Но не все различия одинаковы: часть полей добавляют admission-контроллеры и сами операторы. Нужно понимать ownership и настраивать diff/ignore только для действительно внешне управляемых полей, иначе можно скрыть реальный drift.
§3VictoriaMetrics, Alertmanager и история с JVM OOM
Самая опасная тема в метриках — не объём запросов, а кардинальность: каждая уникальная комбинация labels создаёт временной ряд. Label с user_id, URL с динамическим ID или stack trace способен породить миллионы рядов. Правило простое: label должен принимать ограниченный, понятный набор значений; уникальные детали идут в лог или trace.
При миграции мониторинга правильная история включает:
- инвентаризацию targets, scrape-конфигураций, rules, dashboards и маршрутов Alertmanager;
- параллельный сбор старой и новой системой на ограниченный период;
- сравнение количества targets, ключевых запросов и результатов recording rules;
- подавление двойных уведомлений до переключения;
- проверку восстановления конфигурации и данных, если их сохранение входило в требования.
Alertmanager не вычисляет условие — это делает Prometheus или vmalert. Alertmanager группирует события, дедуплицирует одинаковые, применяет routing, inhibition и silences, затем отправляет уведомления. Silence временно подавляет совпавшие алерты; inhibition автоматически скрывает дочерние симптомы при активной корневой проблеме, например алерты всех сервисов при недоступном кластере.
История JVM OOM требует разделять четыре числа:
| Что | Почему важно |
|---|---|
| Heap | Объекты приложения; ограничивается -Xmx или процентом памяти |
| Non-heap | Metaspace, code cache и служебные структуры JVM |
| Native memory | Стеки потоков, direct buffers, JNI, allocator |
| RSS / cgroup usage | То, что в итоге сравнивается с memory limit контейнера |
java.lang.OutOfMemoryError выбрасывает JVM, когда исчерпан конкретный пул. OOMKilled делает ядро, когда весь процесс пересёк лимит cgroup; JVM может не успеть записать heap dump. Поэтому один график heap недостаточен: нужны RSS/container memory, heap used/max, metaspace, direct buffers, число потоков, GC pause/rate и рестарты контейнера.
§4Keycloak: OAuth 2.0, OIDC и миграция realm
OAuth 2.0 отвечает на вопрос «как приложению получить ограниченный доступ к ресурсу». OpenID Connect добавляет поверх OAuth идентификацию пользователя: ID token, endpoint UserInfo и правила проверки identity. Фраза «OAuth — это логин» неточна; логин появляется в OIDC.
ID token предназначен клиенту и описывает факт аутентификации. Access token предъявляют API; API проверяет подпись, issuer, audience, срок и права. Refresh token нужен для получения новых токенов и хранится осторожнее остальных. Для браузерных и мобильных публичных клиентов нужен Authorization Code + PKCE; старый implicit flow не нужен.
При миграции realm проверяют не только пользователей и роли. Нужны clients и redirect URI, client scopes и protocol mappers, группы, identity providers, required actions, SMTP/темы, политики паролей, service accounts, flow bindings и ключи подписи. Если ключи сменились, старые токены ещё могут быть в обращении: ресурсные серверы должны корректно обновить JWKS, а окно миграции — учитывать TTL токенов.
Грабли
Экспорт realm не всегда равен полной миграции живого инстанса: пароли, внешние user storages, секреты клиентов и поведение custom providers зависят от способа экспорта и версии. Сильный ответ — рассказать, как проверяли логин, refresh, роли, service accounts и совместимость клиентов на копии до переключения.
§5Vault: как получить первый секрет без другого секрета
Секрет-ноль решается через доверенную идентичность платформы. В Kubernetes под предъявляет service account JWT, Vault проверяет его и сопоставляет namespace/service account с ролью. В ответ выдаётся короткоживущий Vault token с ограниченной policy.
Authentication method доказывает, кто клиент. Policy определяет, что ему разрешено. Secret engine хранит или генерирует секрет. Lease задаёт срок жизни; renew продлевает, revoke отзывает. Динамический пользователь БД сильнее вечного пароля: его права ограничены, а срок жизни конечен.
Seal означает, что Vault не может расшифровать данные. Unseal предоставляет материал для восстановления master key; auto-unseal делегирует эту операцию KMS/HSM. Это не то же самое, что HA: HA отвечает за доступность нескольких узлов и лидерство, storage backend — за сохранность зашифрованных данных, а unseal — за доступ к ключу расшифрования.
На практике заранее готовят ответ про ротацию: кто обновляет секрет, как приложение узнаёт об изменении, нужно ли ему перечитать файл или перезапуститься, что произойдёт со старыми соединениями и как отозвать значение без полного простоя.
§6Air-gap: это управление цепочкой поставки
Закрытый контур — не просто «скачать пакеты заранее». Нужно построить контролируемый путь каждого артефакта от внешнего мира до prod.
Минимальный набор вопросов: откуда берутся доверенные корневые сертификаты, кто обновляет зеркала, как проверяется подпись и checksum, где фиксируется SBOM, как отзывается уязвимый образ, как проходит обновление самого Kubernetes и что произойдёт, если внешняя лицензия или OCSP/CRL недоступны.
Воспроизводимость означает, что prod получает тот же digest образа, который прошёл тесты. Пересборка «того же» исходника внутри закрытого контура может дать другой результат из-за версий зависимостей, базового образа и времени сборки. Поэтому артефакт продвигают, а не пересоздают на каждом окружении.
Спросят
«Как обновлять air-gap кластер?» — Сначала собрать точный Bill of Materials релиза: образы, charts, пакеты ОС, CRD и зависимости; скачать из доверенных источников, проверить, загрузить во внутренние зеркала; прогнать обновление на копии; проверить совместимость API и операторов; подготовить backup/restore и только потом идти по средам. Фраза «перенесли tar с образами» описывает транспорт, а не безопасный процесс.
§7CI/CD: кеш, артефакт и продвижение
Кеш ускоряет повторный запуск и может быть удалён без потери результата: зависимости Maven, Gradle cache. Артефакт — результат конкретной сборки, который нужно передать дальше: бинарник, image digest, отчёт тестов. Использовать кеш как артефакт опасно: он не обязан быть полным, неизменяемым или привязанным к коммиту.
Хороший pipeline строит один артефакт и продвигает его:
Ретраи допустимы для явно временных сбоев — сетевой запрос к registry с ограниченным числом попыток и backoff. Ретрай всего pipeline скрывает нестабильный тест и делает зелёный цвет недостоверным. Smoke-тест после деплоя должен проверять пользовательский путь и иметь понятный timeout; «порт открылся» — это readiness, но не доказательство работоспособности продукта.
Для Jenkins стоит уметь объяснить разницу между declarative и scripted pipeline, где хранится shared library, как ограничиваются credentials, почему нельзя запускать недоверенный код на privileged agent и как не допустить параллельного деплоя двух версий в одно окружение.
§8Бэкап и восстановление: RPO, RTO, PITR
RPO — сколько данных допустимо потерять, измеряется временем назад. RTO — сколько сервис может восстанавливаться. Из них следуют архитектура и частота проверки: RPO 24 часа допускает ночной backup, RPO 5 минут требует журналов или репликации; RTO 15 минут не совместим с ручным поиском инструкции и загрузкой терабайта по медленному каналу.
Репликация защищает от отказа узла, но повторяет DELETE, повреждение и шифрование. Снапшот удобен для быстрой точки отката, но может быть crash-consistent, а не application-consistent. Бэкап становится бэкапом только после успешного восстановления в отдельное место с проверкой данных и времени.
Для PostgreSQL PITR нужен базовый backup и непрерывный архив WAL. Восстановление: развернуть базовый снимок → проиграть WAL → остановиться перед ошибочной транзакцией или на заданном времени → проверить данные → переключить клиентов. В Kubernetes оператор автоматизирует шаги, но не отменяет требования тестировать restore и хранить копии вне самого кластера.
Готовый рассказ
Назовите реальное RPO/RTO или честно скажите, что они не были формализованы. Затем: где лежали копии, чем шифровались, как контролировалась полнота, как часто делали restore drill, сколько он занимал и кто принимал решение о переключении.
§9HAProxy и виртуальный IP: где живёт отказоустойчивость
HAProxy распределяет соединения и проверяет backend, но сам по себе остаётся одной точкой отказа. Пара узлов обычно получает виртуальный IP через VRRP/keepalived или внешний механизм. Активный узел владеет адресом; при отказе резервный забирает его и рассылает gratuitous ARP, чтобы соседи обновили соответствие IP → MAC.
Собеседующий спросит про split-brain: что, если оба узла считают себя master? Нужны корректные VRRP priorities, unicast/multicast с учётом сети, проверка не только процесса keepalived, но и работоспособности HAProxy/маршрута, а в критичных схемах — fencing. После переключения часть существующих TCP-соединений обычно оборвётся: VIP переехал, но conntrack и состояние HAProxy не переехали вместе с ним.
L4 health check проверяет, что порт принимает TCP. L7 проверяет осмысленный HTTP endpoint. Слишком поверхностная проверка шлёт трафик в «живое», но бесполезное приложение; слишком глубокая, завязанная на все зависимости, способна одновременно выбить все backend при отказе одной общей БД.
§10RAID, LVM и снапшоты: три разных уровня
RAID10 объединяет зеркалирование и striping: переживает отказ как минимум одного диска, а иногда нескольких — если они не из одной зеркальной пары. Полезная ёмкость примерно половина сырой. Он улучшает доступность и производительность, но не защищает от удаления, шифровальщика, ошибки контроллера или пожара.
LVM отделяет физические устройства от логических томов: PV входят в VG, из свободных extents создаются LV. Это удобно для расширения, перемещения и снапшотов, но LVM не создаёт избыточность автоматически — под ним всё ещё нужен RAID или надёжное хранилище.
Классический LVM snapshot хранит старые блоки по copy-on-write. Сначала он маленький, затем растёт по мере изменений оригинала; если пространство snapshot заполнится, он станет непригоден. Долгоживущий snapshot ухудшает I/O. И снова: snapshot рядом с оригиналом — удобная точка отката, но не независимый backup.
§11Оператор Kubernetes: контроллер с предметной логикой
CRD добавляет в API новый тип объекта, а controller реализует его поведение. Оператор — контроллер, в который зашита операционная логика конкретной системы: создать кластер БД, настроить репликацию, выполнить backup, заменить узел, обновить версию.
Reconcile loop не выполняет «шаги один раз», а постоянно приближает фактическое состояние к spec. Поэтому операция должна быть идемпотентной. Наблюдаемое состояние пишется в status; условия должны объяснять, готов объект или почему нет. Finalizer задерживает физическое удаление CR до внешней очистки — и способен навечно оставить объект в Terminating, если контроллер сломан.
Работая с оператором Postgres, заранее выясняют:
- кто владеет Service, StatefulSet, PVC и конфигурацией — оператор или пользователь;
- как устроены failover, fencing и возврат старого primary;
- куда уходят backups и как выполняется restore в новый кластер;
- как обновляются Postgres и сам оператор, какие версии совместимы;
- что произойдёт при удалении CR: останутся ли PVC и backup.
§12Границы опыта: где честность усиливает ответ
В резюме Terraform указан через Grafana Provider. Не стоит превращать это в «глубокий Terraform для облака». Сильная позиция: «реально применял provider для управления Grafana; понимаю state, locking, plan/apply, import и модульность, но большие cloud landing zones руками не строил». Это точнее и защищается лучше.
С Kubernetes формулировки тоже должны совпадать с реальной самостоятельностью. Если установка и обновление Deckhouse выполнялись по документации, с поддержкой коллег или без глубокого понимания control plane, так и разделяйте: «эксплуатировал и выполнял регламентные операции; архитектурную базу сейчас систематизирую». Не называйте себя экспертом по Kubernetes только потому, что много работали рядом с ним: интервью быстро уйдёт в scheduler, requests, probes, CNI, storage и RBAC.
То же с базами: администрирование и автоматизация backup/restore не обязаны означать опыт тонкой оптимизации SQL или internals Oracle RAC. Сначала обозначьте границу, потом подробно расскажите свой участок. Уверенное разделение «делал / участвовал / понимаю теорию / не делал» вызывает доверие.
Финальная тренировка
Запишите по двухминутной истории на каждый пункт ниже и попросите собеседника перебивать уточнениями:
- миграция мониторинга без слепой зоны;
- как метрики JVM привели к причине OOM;
- миграция realm Keycloak между версиями;
- доставка релиза в air-gap контур;
- восстановление БД или VM из копии;
- самый рискованный GitOps/CI/CD деплой и способ отката.