Поплыл на Kubernetes. Оффер всё равно получил
Вот собеседование, после которого я получил оффер на 450К. Не вспомнил anti-affinity, запутался со StatefulSet, не ответил про доступность реплик. Можно выключить запись и написать, что таких вообще нельзя брать на работу. А можно посмотреть, что там происходило на самом деле. Я бы выбрал второе.
Я не делаю из своих записей парад идеальных ответов. Здесь есть и нормальный разговор про рабочие задачи, и моменты, где я откровенно плыву. Ниже — что у меня спросили, что я тогда ответил и как объяснил бы это сейчас. Новые пояснения не выдаю за слова из старого собеса.
Сама запись — 34 минуты 38 секунд
Смотреть собеседование на YouTube · 34:38 →
Видео опубликовано 14 июня 2025 года. 450К — сумма из истории этого интервью, а не ценник на любого DevOps сегодня. Запись открывается на YouTube, ниже можно перейти сразу к нужному моменту.
Таймкоды ведут к началу обсуждения. Ответы ниже сокращены по смыслу, это не дословная стенограмма. Самого оффера в записи нет — это результат, который я указал в названии ролика. Про внутренние обсуждения работодателя ничего не сочиняю: здесь видно собеседование, а не то, как компания принимала решение.
04:59 — Зачем Argo CD, если уже есть GitLab
Что спросили. Почему для деплоя выбрали Argo CD, какие у него преимущества и стоит ли ради этого содержать дополнительный инструмент.
Что я ответил. Argo предложил технический руководитель: у него уже был такой опыт, а я столкнулся с инструментом впервые. Дальше говорю про удобный интерфейс, отображение ресурсов, логи и синхронизацию с Git. В объяснение залезают «взаимодействия сервисов». После уточнений это уже звучит менее убедительно, чем мне хотелось бы.
Как объяснил бы сейчас. Удобный интерфейс — нормальный аргумент, я его не отбрасываю. Но дерево Kubernetes-ресурсов не равно карте реальных запросов между сервисами. По нему нельзя автоматически понять, кто кому звонил и где потерялась задержка. Для этого нужны другие данные, например трассировки.
Я бы начал с конкретной задачи: хочу видеть расхождение между состоянием в Git и кластером, управлять синхронизацией и отделить сборку от доставки. А потом уже обсудил, стоит ли это обслуживания Argo именно здесь. Ответ «ещё одним инструментом больше, ещё одним меньше» цену обслуживания не отменяет.
07:37 — Идеальный пайплайн упёрся в релизное окно
Что спросили. Как я представляю идеальный пайплайн и какие в нём должны быть этапы.
Что я ответил. Сначала — чтобы разработчик запушил изменения и они спокойно доехали до прода. Потом перечисляю проверки, сборку, тесты, деплой на dev. Для продакшена предлагаю canary или blue-green. А на 10:05 мне объясняют: у их клиентов обновления идут в согласованное окно, когда пользователи уже не работают. После этого вспоминаю знакомый мне похожий режим.
Как объяснил бы сейчас. Меня попросили представить идеальный вариант, не обязательно тот, который я уже внедрял. На общий вопрос я ответил общим вариантом. А потом выяснилось, как выпускаются именно их проекты. Вот тут и начинается разница между красивой схемой и конкретным релизом. Blue-green от этого не становится плохим — просто название технологии не отвечает на вопрос, можно ли обновлять систему посреди рабочего дня.
Сначала спросил бы, кто и когда разрешает выпуск, допустим ли простой, что происходит с данными и как возвращаться назад. Потом — проверки, один проверенный артефакт для следующих окружений и подходящий способ выкладки. Мне не нужен кубок за самый модный деплой. Мне нужно, чтобы конкретный релиз доехал и не съел выходные.
В банке: этапы пайплайна, blue-green и canary, что делать после неудачного релиза.
11:23 — Безопасность: где заканчивается мой опыт
Что спросили. Какие меры безопасности я знаю для контейнеров, Kubernetes, пайплайнов и секретов.
Что я ответил. Сразу обозначаю, что глубоко в безопасность не уходил. Называю запуск без root, внешнее хранение секретов, Vault, git-crypt и отсутствие открытых ключей в конфигах. Позже пытаюсь вспомнить название решения с зашифрованными файлами в Git и оператором в кластере. Название не вспоминаю и говорю, что сам с ним не работал: собирались, но не внедрили.
Как объяснил бы сейчас. Название я не вспомнил. И внедрения у меня не было — только обсуждали. Зато сам подход здесь стоит разобрать.
Технически «зашифровано в Git» и «пароль лежит открытым текстом» — разные вещи. Но одного слова «зашифровано» мало: кто может расшифровать, где ключ, как меняются доступы и как обновлённый секрет получает приложение? И если настоящий ключ уже утёк, удаления строки из репозитория недостаточно — ключ нужно отозвать или заменить.
В банке: что делать с утёкшим секретом и non-root и rootless — не одно и то же.
15:17 — Vault и Kubernetes Secrets
Что спросили. Зачем Kubernetes Secrets, если есть Vault, и в каких случаях выбирать одно или другое.
Что я ответил. Начинаю с менее чувствительных данных и закрытых окружений. Потом называю централизованные доступы, аудит, временные токены и отзыв в Vault. Про срок жизни обычных Kubernetes Secrets говорю неуверенно. Единого понятного критерия выбора в ответе так и не собираю.
Как объяснил бы сейчас. Secret — не специальная сущность для «несерьёзных паролей». Это механизм Kubernetes, которому нужны нормальные права доступа и защита хранения. А обычный Secret сам по себе не получает универсальный TTL с автоматическим отзывом пароля. Короткоживущий токен ServiceAccount — отдельная история.
Vault может централизованно выдавать доступы и, для поддерживающих это механизмов, динамические секреты с lease. Но он не отменяет Kubernetes Secrets автоматически: например, External Secrets Operator может переносить данные из внешнего хранилища в обычный Secret. Тогда копия в кластере остаётся, и её тоже надо защищать.
Я бы выбирал не по принципу «Vault взрослый, Secret игрушечный», а по тому, кто выдаёт доступ, как его обновлять и что будет при недоступности хранилища. Сам Vault тоже нужно обслуживать. В записи мы к этому приходим через обсуждение unseal, но своего чёткого разбора я там не даю.
В банке: ConfigMap и Secret, как устроен Vault, защита секретов Kubernetes.
22:27 — Контейнер жив. А работа идёт?
Что спросили. Как понять, что компоненты работают, и настроить алерты. Потом вопрос сужают: контейнер может не завершаться, но зависнуть и перестать делать полезную работу.
Что я ответил. Сначала ухожу в инструменты и доставку уведомлений. После уточнения вспоминаю liveness/readiness, Prometheus, экспортёры, HTTP 200, проверку порта и логи. Пример с обработчиком потока, у которого надо проверять продвижение работы, развивает уже интервьюер — это не моя удачная находка в записи.
Как объяснил бы сейчас. На вопрос «как поймёшь, что сломалось» я начал отвечать «куда пришлю сообщение». Это разные задачи. Открытый порт подтверждает открытый порт, а не то, что обработчик разобрал очередь.
Я бы сначала определил полезный результат: сообщения обрабатываются, очередь не растёт без причины, время последней успешной обработки соответствует ожидаемому потоку. Нет входных данных — это ещё не зависание. И только потом выбирал проверки и алерты. Readiness убирает неготовый под из обслуживания трафика Service, а liveness при повторяющемся провале ведёт к перезапуску контейнера. Само по себе это ещё не контроль бизнес-результата.
В банке: liveness, readiness и startup, SLI и SLO, осмысленный алертинг.
26:30 — Три реплики на одной ноде
Что спросили. Как сделать компонент отказоустойчивым. После уточнения задача конкретная: в кластере много нод, приложению нужны три реплики, и нельзя, чтобы они оказались на одной машине.
Что я ответил. Сначала предлагаю DaemonSet для запуска на каждой ноде, потом говорю про несколько реплик. Когда просят гарантировать размещение на разных нодах, снова вспоминаю DaemonSet, затем селекторы. Нужный механизм не называю. На 28:05 anti-affinity произносит интервьюер.
Как объяснил бы сейчас. Вот тут я не просто недостаточно красиво сформулировал. Я не ответил на уточнённую задачу. DaemonSet меняет требование на «агент на каждой подходящей ноде», а нам нужны всего три реплики.
Для этого случая я бы рассмотрел pod anti-affinity по метке приложения с topologyKey: kubernetes.io/hostname. Жёсткое правило запрещает планировать подходящие реплики вместе, мягкое только выражает предпочтение. За гарантию есть цена: если подходящих нод не хватает, часть подов останется Pending. И разнесение по машинам не означает автоматически разнесение по зонам.
В банке: Deployment, StatefulSet и DaemonSet, как разбирать Pending и ограничения размещения.
28:16 — StatefulSet: понимаю примерно, объясняю плохо
Что спросили. Чем Deployment отличается от StatefulSet.
Что я ответил. Переспрашиваю, зависаю, говорю, что в основном описывал всё в Deployment. Вспоминаю базы данных, Redis с сохранением состояния и имена подов. На именах возникает путаница и поправка. Спокойного объяснения, зачем репликам стабильная идентичность, у меня не получается.
Как объяснил бы сейчас. «Там, где нужны данные» — слишком расплывчато. Важнее стабильная идентичность реплик: имена, сетевые адреса, привязка каждой реплики к своему хранилищу при использовании шаблонов PVC. В Deployment реплики обычно взаимозаменяемы.
StatefulSet не превращает любую базу в надёжный кластер и не пишет за неё репликацию. Поэтому я бы объяснял выбор через требования приложения, а не через магическое слово «данные». На записи такого собранного ответа у меня нет. Это и есть то место, которое стоит разобрать после собеса, а не оправдывать десятью годами стажа.
В банке: различия контроллеров и нюансы PVC.
29:24 — Доступность реплик: ушёл не в ту сторону
Что спросили. Есть Deployment с тридцатью репликами. Как при обновлении сохранить не меньше десяти работающих экземпляров?
Что я ответил. Ухожу в масштабирование, говорю, что примерно понимаю, но сам этого не касался. Дальше получается путаный обмен уточнениями, без моего чёткого ответа. Не буду дописывать за интервьюера, какой именно термин он ждал: сейчас важнее разделить две разные задачи.
Как объяснил бы сейчас. Я бы уточнил операцию. Для rolling update у Deployment есть maxUnavailable и maxSurge: сколько экземпляров допустимо временно потерять и сколько создать сверх желаемого числа. Это не HPA. А добровольные выселения через Eviction API, например при обслуживании ноды, — отдельная история с PodDisruptionBudget. PDB не управляет rolling update контроллера Deployment.
В упрощённом примере с тридцатью здоровыми репликами maxUnavailable: 20 задаёт границу в десять доступных при штатной выкладке. Но это не обещание пережить любые одновременные аварии и не доказательство, что десять реплик выдержат нагрузку. Я бы проверил readiness, реальную ёмкость и условия обновления, а не ограничился вычитанием 30 − 20.
В банке: rolling update и доступность, за что на самом деле отвечает HPA.
30:54 — GitLab поднять и GitLab обслуживать
Что спросили. Где хранили код и был ли свой GitLab. Дальше разговор переходит к его обновлениям, бэкапам и миграциям.
Что я ответил. Говорю, что сам разворачивал GitLab на серверах, и упрощаю это до запуска установочного скрипта. Когда обсуждают сложный переезд в одной из компаний, отдельно признаю: им занималась другая группа инженеров, я этого не делал.
Как объяснил бы сейчас. Поднять GitLab и потом пережить тяжёлое обновление — разные задачи. В записи я рассказывал про установку. А если разбирать обслуживание сейчас, начал бы с резервной копии данных и конфигурации, проверенного восстановления, обязательных промежуточных версий и завершения фоновых миграций. «Накатим последнее» — не план.
Что я из этого забираю
Можно работать с Kubernetes и поплыть на базовом вопросе. У меня именно так и вышло. Это не делает неправильный ответ правильным, но и не превращает всё собеседование в автоматический отказ. Оффер я получил. Почему компания выбрала меня — по этой записи не установишь, и сказку про «взяли за уверенность» я придумывать не собираюсь.
Мой вывод проще: не вычёркивать себя из найма раньше работодателя. Я не ждал дня, когда смогу ответить на любой вопрос. Ходил на разговоры, ошибался, разбирался, шёл дальше. Рабочий опыт добирал уже за зарплату. Но после такого эпизода полезнее закрыть конкретный пробел, чем сто раз повторить себе, что собес был дурацкий.
Если готовишься сам, останови запись до моего ответа на 26:30, 28:16 и 29:24. Попробуй объяснить вслух, потом досмотри уточнения. Не узнал термин — разберись. Узнал, но не смог связно ответить — это тоже полезная находка. Ради этого я и оставляю запись, а не только красивую историю про сумму оффера.