MAATRIX / Блог / Ушёл ключевой разработчик: как понять, что вообще крутится на ваших серверах

Ушёл ключевой разработчик: как понять, что вообще крутится на ваших серверах

MAATRIX

В команде из четырёх разработчиков увольняется один — не единственный технарь, не тот, кто один держал все пароли, а просто человек, который два года «занимался бэкендом и заодно сервером». Остальные трое прекрасно пишут код и разбираются в архитектуре продукта. Но когда через неделю после его ухода падает ночной процесс, которого никто не видел в списке задач, выясняется странная вещь: формально доступ к серверу есть у всех, а понимания, что происходит в этой конкретной зоне, — почти ни у кого. Это не история про пропавшего единственного админа и не про разбор совсем чужого сервера с нуля — это про пробел внутри работающей команды, которая что-то знает, просто по кусочкам, и не про то, что нужно прямо сейчас.

Чем эта ситуация отличается от «ушёл единственный админ»

Разница принципиальная, и от неё зависит план действий. Когда пропадает единственный технический человек в компании, остальные не имеют вообще никакого доступа и контекста — систему приходится разбирать как полностью чужую, с нуля. Общая методология такого разбора — инвентаризация процессов, поиск конфигов, проверка бэкапов, осторожное наблюдение перед изменениями — подробно разобрана в статье «достался чужой сервер без документации», и если ваш случай именно такой — это правильная отправная точка.

Ситуация с уходом ключевого, но не единственного разработчика — мягче по форме и коварнее по содержанию. Доступ есть у всех: тот же root, тот же VPN, та же панель провайдера. Коллеги технически подкованы и способны прочитать любой конфиг. Но конкретно эта зона — скажем, интеграция с системой бронирования или скрипт синхронизации с партнёрским API — была де-факто в одиночном ведении одного человека, и остальные заходили туда эпизодически, «посмотреть, если что». Знание не отсутствует полностью — оно рассыпано на обрывки в головах трёх-четырёх человек, каждый из которых помнит что-то своё и не подозревает, что помнит важное. Стратегия меняется: вместо разведки с нуля нужна сборка мозаики из фрагментов, которые уже есть у команды, плюс техническая ревизия там, где фрагментов не хватило.

Собираем то, что помнят коллеги, пока это ещё помнят

Первый шаг — не техническая инвентаризация, а разговор, и провести его стоит буквально в первые дни после ухода, а не через месяц, когда детали сотрутся. Память о чужой работе выветривается быстро именно потому, что она была фоновой: никто специально не запоминал, что настраивал коллега, — фрагменты держатся в голове случайно и теряются так же, как забываются любые случайные детали.

Практический формат — короткий структурированный опрос каждого оставшегося члена команды, а не общий вопрос в чат вида «кто что помнит». Общий вопрос почти всегда даёт тишину: люди не осознают ценность своих обрывков, пока их не спросить прицельно. Работают конкретные вопросы:

  • «Когда ты последний раз заходил на прод по его просьбе — что смотрели вместе?»
  • «Упоминал ли он что-то вроде "у меня там скрипт по ночам гоняет" или "это временно, потом перепишу"?»
  • «Видел ли ты его переписку с подрядчиком, платёжным провайдером или API-партнёром?»
  • «Есть тикеты, где он писал технические детали в комментариях, а не только "готово"?»

Отдельный источник, который недооценивают, — история переписки в рабочих чатах и коммит-сообщения. Это не требует памяти коллег вообще, только целенаправленного поиска:

# файлы, к которым человек прикасался чаще всего — указатель на его зону
git log --author="Иван" --stat --since="2 years ago" | grep -E "^\s+\S+\s+\|" | \
  awk '{print $1}' | sort | uniq -c | sort -rn | head -20

# коммиты, которые обычно объясняют "почему", а не только "что"
git log --author="Иван" --grep="fix\|workaround\|hack\|hotfix\|временно" -i --oneline

Первая команда показывает файлы, к которым этот человек прикасался чаще всего, — прямой указатель на его фактическую зону ответственности, даже если формально она нигде не прописана. Поиск по слову «временно» в коммитах особенно продуктивен: разработчики почти всегда честны именно в момент, когда пишут костыль, — такие сообщения прямо указывают, где искать проблемные места в первую очередь.

Поиск по рабочим чатам (Slack, Telegram, Mattermost) по имени ушедшего и словам «настроил», «поднял», «добавил ключ», «это на моей стороне» часто восстанавливает контекст быстрее, чем попытка вспомнить его без подсказок. Все находки — даже противоречивые, даже неполные — стоит сразу сводить в один документ: три разных фрагмента от трёх коллег о синхронизации с CRM, сложенные вместе, дают куда более полную картину, чем каждый по отдельности.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Cron-задачи и фоновые процессы: чужая зона на сервере становится видимой только при полной инвентаризации

Личные привычки в организации фоновых задач — то, что разработчик обычно не согласовывает с командой: он завёл cron под своим или сервисным пользователем, назвал скрипт понятно только себе, и никто больше туда не заглядывал, потому что «это его штука и она работает». После ухода это превращается в набор процессов без ответственного.

Инвентаризация здесь технически не отличается от разбора незнакомого сервера, но отличается по цели: вы ищете не всё подряд, а специфически то, что относится к зоне ушедшего человека, сверяя находки с тем, что уже узнали от коллег на предыдущем шаге.

# все cron-задачи по каждому пользователю, не только под текущим логином
for u in $(cut -f1 -d: /etc/passwd); do
  echo "== $u =="
  crontab -l -u "$u" 2>/dev/null
done

# системные каталоги и systemd-таймеры — задачи, которые crontab -l не покажет
cat /etc/crontab
ls -la /etc/cron.d/
systemctl list-timers --all

# процессы, запущенные вручную и держащиеся на screen/tmux/nohup —
# частый признак личного, никому не показанного скрипта
ps auxf | grep -v grep
screen -ls 2>/dev/null
tmux ls 2>/dev/null

Для каждой найденной задачи, которая не соотносится с уже известными командными процессами, полезно сразу выяснить дату последнего изменения файла (stat /opt/scripts/имя.sh) и посмотреть лог за приличный период — это часто подсказывает, к какому проекту она относится.

Дальше задачу стоит соотнести с тем, что уже собрано от коллег: «Аня вспоминала, что он что-то настраивал для синхронизации заказов с партнёрским складом» плюс найденный скрипт sync_partner_orders.sh, запускающийся каждый час, — это уже не догадка, а подтверждённая версия. Подробная методология самой ревизии — как отличить нужную задачу от мусорной и безопасно отключить сомнительную, не сломав чужой процесс по неведению — разобрана в статье «ревизия cron-задач: сколько из них ещё нужны»; здесь тот же порядок действий, просто источник версий о назначении задачи — не логи, а в первую очередь память коллег.

Отдельно стоит обратить внимание на задачи с говорящими, но непонятными именами вроде fix2_final.sh или temp_check.py, которые крутятся месяцами. Часто это и есть тот самый «личный костыль», о котором ниже.

Нестандартные конфигурации и костыли, смысл которых знал только он

Отдельный класс пробелов — не отсутствующий процесс, а присутствующая, но необъяснённая странность: nginx проксирует эндпоинт через нестандартный порт, в приложении жёстко зашит retry с конкретным числом попыток, таблица в базе обновляется двумя разными путями, один из которых выглядит избыточным. Такие решения почти всегда появились как ответ на конкретную проблему в конкретный момент — и смысл их очевиден ровно одному человеку, который эту проблему решал, но не успел объяснить остальным.

Практический способ найти такие места — целенаправленный grep по комментариям в коде и конфигах, а не чтение всего подряд:

grep -rniE "todo|fixme|hack|workaround|важно|не трогать|временное решение" \
  /opt /etc/nginx /etc/systemd/system 2>/dev/null

Второй источник — git blame по файлам, которые уже определены как зона ушедшего человека (список файлов из предыдущего раздела про git-историю):

git blame -L 40,80 app/services/order_sync.py

Строки, автором которых значится ушедший разработчик, рядом с комментарием вроде # не менять, ломает синхронизацию с их API, — ровно те места, где стоит остановиться и не трогать код, пока смысл не восстановлен хотя бы предположительно. Здесь снова работает связка с командной памятью: если кто-то из коллег помнит контекст («это он добавил, когда партнёрский API стал отдавать дубли заказов»), это резко сокращает время, которое иначе ушло бы на реверс-инжиниринг чужого решения по коду.

Важно не спешить «причёсывать» такие места сразу после обнаружения. Костыль, поставленный намеренно и объяснимо, отличается от забытого мусора не по виду кода, а по тому, есть ли у него доказанная причина. Пока причина не установлена — обращайтесь с ним как с потенциально критичным, даже если хочется переписать его по-человечески.

Внешние интеграции и API: доступы, которые знал только один человек

Это самая рискованная категория пробелов: её последствия не технические, а внешние — партнёрский API молча перестаёт отвечать через месяц, потому что истёк токен, продлить который может только владелец аккаунта, а владельцем указан ушедший сотрудник с личной почтой.

Систематический поиск начинается с переменных окружения и конфигов на сервере:

# переменные окружения сервисов — ищем упоминания внешних доменов и ключей
for f in /opt/*/.env /etc/systemd/system/*.service; do
  echo "== $f =="
  grep -iE "api_key|secret|token|client_id|webhook" "$f" 2>/dev/null
done

# для Docker — переменные внутри контейнеров, они не всегда видны в .env рядом
docker inspect <container> | grep -A 30 '"Env"'

Дальше — не сами значения ключей (их всё равно предстоит ротировать при уходе сотрудника, это отдельная обязательная процедура безопасности), а вопрос «кто владелец аккаунта на стороне партнёра или сервиса». Выясняется это не техническими средствами, а прямыми обращениями: письмо в поддержку внешнего сервиса с вопросом, на какой email и чьё имя зарегистрирован аккаунт, часто быстрее, чем попытка восстановить это по обрывкам переписки. Если интеграция окажется зарегистрирована на личный аккаунт ушедшего человека — переносите владение на корпоративный аккаунт сразу, а не откладывайте до следующего сбоя.

Практично сразу составить таблицу по каждой найденной интеграции — она одновременно инвентаризация и черновик документации:

ИнтеграцияГде настроенаКто владелец аккаунтаСтатус выяснения
Синхронизация заказов с партнёрским складом/opt/sync/order_sync.py, cron каждый часпредположительно личная почта ушедшегописьмо в поддержку отправлено
Webhook от платёжного провайдераnginx, отдельный location /hooks/payкорпоративный аккаунт, подтвержденозакрыто
Уведомления в CRMsystemd service crm-notifyнеизвестнотребует разбора кода

Строка «неизвестно» в последней колонке — не провал, а честная фиксация текущего состояния разбора: видно, что уже закрыто, а что ещё требует внимания.

От разрозненных фрагментов к документации, которая переживёт следующий уход

Всё, что собрано на предыдущих шагах — обрывки из разговоров с коллегами, найденные cron-задачи, странности в коде, список интеграций с неясным владением, — ценно ровно до тех пор, пока не записано в одном месте. Собранное только в переписке и голове тех, кто разбирался, повторит судьбу знаний ушедшего сотрудника: рассыплется на фрагменты у следующих людей, если команда снова изменится.

Практичный принцип — документировать по ходу разбора, а не откладывать до момента, когда «наконец разобрались во всём». Второго момента может не наступить: команда переключится на текущие задачи, как только острая проблема перестанет гореть, а недописанные находки забудутся так же, как забылись знания ушедшего коллеги.

Минимальный набор, который стоит вести с первого дня разбора:

  1. Реестр процессов и задач с уровнем уверенности — не только «что это», но и «насколько уверены»: подтверждено, предположение по косвенным признакам, до сих пор неизвестно.
  2. Карта интеграций с владельцами доступов — таблица из предыдущего раздела, обновляемая по мере закрытия вопросов.
  3. Список решений с найденным обоснованием — костыли и конфиги, для которых удалось восстановить причину, с указанием источника (git blame, слова коллеги, тикет).
  4. Открытые вопросы — то, что не удалось выяснить. Такой список честнее молчания и подсказывает, куда возвращаться, если найдётся новая зацепка.

Общий подход к тому, что стоит фиксировать в документации сервера на регулярной основе, разобран в статье «документация сервера: что нужно вести» — можно взять оттуда структуру целиком. А чтобы новая документация не повторила судьбу старой (написана один раз в порыве энтузиазма и забыта через полгода), заведите регулярный ритуал сверки с реальностью — как именно, разобрано в статье про поддержание документации инфраструктуры актуальной.

Как не оказаться здесь снова: code review и обмен знаниями как страховка

Технический разбор после ухода конкретного человека — работа с последствиями, а организационная мера, снижающая вероятность повторения, — работа с причиной. Причина здесь обычно не в скрытности характера, а в побочном эффекте удобного распределения работы: раз человек хорошо разбирается в части системы, логично поручать связанные задачи именно ему, и со временем он становится единственным, кто там регулярно бывает.

Практические меры, которые снижают риск такой единоличной зоны для каждого конкретного разработчика, а не только для системного администратора:

  • Обязательный код-ревью для инфраструктурных изменений, а не только для прикладного кода продукта. Cron-задача или конфиг деплоя, добавленные без второй пары глаз, — будущий пробел с отложенным сроком проявления.
  • Ротация ответственности внутри команды раз в несколько месяцев — не полная передача зоны, а плановое «второй человек заходит и делает там что-то руками» вместе с владельцем.
  • Правило «важное решение — тикет с объяснением», а не только код. Комментарий в коде объясняет что, тикет или документация — почему. Именно «почему» теряется первым.
  • Короткая сверка знаний о серверной части раз в квартал, где каждый в двух словах рассказывает, что нового настроил или поддерживает, — дёшево по времени и ощутимо снижает риск слепых зон.

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

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

С чего начинать, если ушедший разработчик уже недоступен для вопросов?

С разговора с оставшимися коллегами по конкретным вопросам («когда в последний раз заходили туда вместе», а не «что вы помните»), параллельно с git-историей его коммитов — это быстрее восстанавливает контекст, чем разбор с нуля техническими средствами.

Нужно ли сразу менять пароли и ключи, к которым мог иметь доступ ушедший сотрудник?

Да, ротация доступов — обязательная процедура безопасности при уходе любого сотрудника с техническим доступом, и её стоит делать параллельно с разбором: смена ключей закрывает риск утечки, но не отвечает на вопрос, что вообще нужно поддерживать дальше.

Что делать, если найденный процесс явно относится к зоне ушедшего человека, но никто не понимает его назначения?

Не отключать сразу. Понаблюдать по логам и трафику, попробовать связаться с человеком напрямую, если отношения позволяют, и только при отсутствии ответа переходить к безопасному отключению с периодом наблюдения.

Сколько времени обычно занимает такой разбор для одной зоны ответственности?

Меньше, чем полный разбор незнакомого сервера с нуля, потому что часть контекста уже есть у команды — но закладывайте от нескольких дней до пары недель на зону среднего размера, с учётом времени на ответы внешних сервисов о владении аккаунтами.

Стоит ли делать этот разбор одному человеку или всей командой?

Всей командой, хотя бы на этапе сбора фрагментов памяти — именно распределённость знания была причиной проблемы, и только распределённый сбор её закрывает. Техническую часть может вести один человек, но опрос коллег эффективнее делать параллельно.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →