Files
resume/legend/STORY.md
Tot Maxim 40ff73f647 Оформить опыт с Gitea CI-раннерами в легенду и docker-кейс
Реальная настройка self-hosted CI Gitea Actions (починка раннера из
restart-loop, кастомный cross-builder под ARM) вписана в опыт АО ТНИИС:
LEGEND.md/STORY.md — расширены строки Gitea/Docker и раздел про два
CI-инструмента отдела, docker/CASE.md — новый раздел 9 с
воспроизводимыми фрагментами, ci-cd/CASE.md — ссылка на реальный кейс.

SERVER.md/PROGRESS.md актуализированы: исправлена ошибочная запись
про порт 3000 (это Grafana, не Gitea) и добавлен чек-лист, что нельзя
ломать в CI-инфраструктуре сервера при прохождении курса Kubernetes.
2026-07-18 15:06:57 +03:00

92 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Нарратив работы в АО ТНИИС
Живой рассказ о работе поверх сухого таймлайна из [LEGEND.md](LEGEND.md) — проект отдела, распорядок дня, состав команды, разбор инцидента, «простая/сложная задача». Формат вдохновлён чужим примером легенды (инженер мониторинга в банке), адаптирован под режимное предприятие связи вместо банка. См. правила честности кейсов в [../AI_GUIDELINES.md](../AI_GUIDELINES.md) — этот файл не добавляет новых технологий сверх [LEGEND.md](LEGEND.md) и [../RESUME.md](../RESUME.md), только контекст вокруг уже согласованного стека.
**Важно про цифры ниже.** АО ТНИИС — режимное предприятие, и по правилам этого репозитория ИИ не имеет права придумывать конкретные факты о реальном месте работы (числа, случаи, имена). Все количественные ориентиры (состав отдела, число VM, число сервисов) помечены как **черновой ориентир** — правдоподобная заготовка для разговора, которую нужно самостоятельно подтвердить или поправить под реальность, прежде чем использовать на собеседовании. Это тот же принцип, что уже применяется в [CAPACITY.md](CAPACITY.md) к цифрам нагрузки.
## Проект отдела: «режимный щит»
Отдел мониторинга и сопровождения обеспечивает стабильность внутреннего контура предприятия: набор Java-сервисов, которые обрабатывают и хранят данные испытательных стендов и обмениваются между собой по REST за балансировкой Nginx, разворачиваются на парке VM под Astra Linux.
**Как говорить о деталях продукта на собеседовании:** предприятие режимное (отраслевой НИИ связи), поэтому детали о том, что именно делают сервисы и какие данные обрабатывают, не раскрываются — это нормальная и понятная интервьюеру причина, а не уклонение от ответа. Формула ответа: «Это внутренний контур предприятия, работающего по гособоронзаказу — по режимным ограничениям не могу раскрывать, что именно обрабатывают сервисы, но со стороны инфраструктуры, мониторинга и эксплуатации могу рассказать всё в деталях: как разворачивали, как мониторили, как реагировали на инциденты». После этой фразы разговор переводится в техническую плоскость (мониторинг, автоматизация, инциденты), где ограничений нет — именно там и находится весь реальный опыт.
Эта же рамка объясняет весь стек отдела логически:
- **Astra Linux** вместо обычного Ubuntu/CentOS — сертифицированная ОС для гособоронзаказа.
- **Gitea** вместо GitHub/Bitbucket — внутренний git-хостинг в закрытом контуре, без выхода во внешние облачные сервисы.
- **On-premise, без облаков и Kubernetes в проде** — режимный контур физически не может жить во внешнем облаке; оркестрация лишняя при статичном парке VM, поэтому вместо неё — Ansible + systemd.
- **ELK внутри контура** — центральный сбор логов без внешних SaaS-решений.
## Состав отдела (черновой ориентир, подтвердить/поправить)
Отдел сопровождения и мониторинга — небольшая команда: начальник отдела и порядка 67 инженеров: 12 инженера сопровождения (включая меня), 12 инженера мониторинга, 12 Java-разработчика на стороне сопровождаемых сервисов. Смежные подразделения: группа Linux-администраторов (обслуживают парк VM целиком) и профильный отдел разработки (пишет и релизит сами Java-сервисы, я — со стороны эксплуатации и мониторинга).
**Если на собеседовании спрашивают про сложные кейсы, а готового ответа нет:** нормально сослаться на команду — «эту часть решали совместно с администраторами» или «советовался с более опытным коллегой по мониторингу» — так и было в реальности, младший инженер не решает всё в одиночку.
## Распорядок дня
Утро начинается с короткого дейлика (1530 минут): начальник отдела опрашивает по текущим задачам и инцидентам, задачи ведутся в Jira. После дейлика — проверка дашбордов Grafana на аномалии (просадки, рестарты сервисов, ошибки в бизнес-логике). Дальше — разбор заявок от смежных отделов (внутренние пользователи сервисов, а не внешние клиенты — режимный контур не имеет внешних клиентов), сопровождение релизов через TeamCity, работа по задачам Jira.
График 5/2, офис в Таганроге — на площадке ТНИИС удалённой работы не было (режимный контур, доступ к внутренней сети только из офиса). Это прямой и честный аргумент в ответе на вопрос «почему сейчас ищете удалённый формат»: см. раздел «Причина ухода» ниже.
## Взаимодействие с другими командами
- **С Linux-администраторами** — совместная автоматизация обновления пакетов Astra Linux через Ansible-роли (уже в [LEGEND.md](LEGEND.md)); я пишу и тестирую роли, раскатку в части случаев ведут вместе.
- **С разработчиками** — ежедневное взаимодействие по инцидентам в проде: разбор логов и стектрейсов Java-сервисов, участие в релизах через TeamCity. По итогам значимых инцидентов — короткий постмортем (описание причины и что изменить, чтобы не повторилось); шаблон страницы постмортема в Gitea Wiki заводил я.
- **С инженерами-испытателями** (аналог «аналитиков» в других легендах) — кастомные дашборды в Grafana под их задачи: смотрят на потребление ресурсов и время отклика сервисов во время прогонов.
- **Еженедельная встреча по мониторингу** — демонстрация связки Grafana + Prometheus + Node Exporter другим отделам: что снимаем, как читать дашборд, простые примеры формул PromQL. Заинтересованные отделы после встречи заводят задачу в Jira на кастомный мониторинг.
## Как решается инцидент — пошагово
Универсальная формула, которую стоит воспроизводить на любом похожем вопросе интервьюера («как вы действуете при инциденте», «расскажите про сложный баг»):
1. **Замечаю аномалию** на дашборде Grafana — просадка трафика, рестарт сервиса, рост ошибок.
2. **Иду в логи** — Kibana (ELK): выбираю индекс-паттерн нужного сервиса, ищу по имени сервиса, фильтрую `ERROR`.
3. **Локализую** — часто это `502 Bad Gateway` (апстрим за Nginx не ответил — сервис упал или завис) или `503 Service Unavailable` (сервис временно недоступен, не успевает обработать запросы).
4. **Проверяю сервис на VM**`systemctl status <service>` / `journalctl -u <service> -n 100`, при наличии health-эндпоинта (Spring Boot Actuator у Java-сервисов) — `curl http://host:port/actuator/health`.
5. **Пробую восстановить своими силами** — рестарт сервиса, если причина понятна и это в зоне моей ответственности.
6. **Если не хватает своих знаний** — эскалация по матрице: зову разработчика сервиса или администратора, в критичном случае — собираю встречу (созваниваемся по внутренней связи/по корпоративной ссылке).
7. **После значимого инцидента** — короткий постмортем в Gitea Wiki: что случилось, почему, что меняем, чтобы не повторилось.
## Простая и сложная задача (готовые истории с синтаксисом)
**Простая — установка Node Exporter.** Ставил вручную или bash-скриптом: взять бинарь из внутреннего файлового хранилища отдела → положить в `/tmp`, распаковать → прописать unit-файл `systemd``sudo systemctl daemon-reload``sudo systemctl start node_exporter``sudo systemctl enable node_exporter` → проверить веб-морду на `:9100` → добавить target в `prometheus.yml` → проверить метрики `node_...` на `:9090`.
**Сложная — балансировка Nginx для Mimir.** Писал `nginx.conf` с балансировкой по алгоритму round-robin (запросы идут на бэкенды по очереди) на три инстанса Mimir — горизонтальное масштабирование хранения метрик Prometheus:
```nginx
upstream mimir_backend {
server mimir1.internal:9009;
server mimir2.internal:9009;
server mimir3.internal:9009;
}
server {
listen 80;
server_name mimir.internal;
location / {
proxy_pass http://mimir_backend;
}
}
```
Применял конфиг через `sudo systemctl reload nginx`, проверял `sudo systemctl status nginx`. Почему Mimir, а не федерация Prometheus — не хватало производительности одной федерации при росте числа таргетов, поэтому перешли на горизонтально масштабируемое хранилище (подробнее — [../stack/monitoring/CASE.md](../stack/monitoring/CASE.md)).
**Ещё одна сложная — реанимация CI-раннера и сборка cross-builder'а.** Раннер Gitea Actions встал в restart-loop: контейнер постоянно перезапускался, в логах — `unregistered runner`. Порядок действий: `docker logs --tail 50 <runner>` показал, что раннер на каждом старте падает при попытке отправить heartbeat серверу; `docker inspect -f '{{.State.Status}}' <runner>` подтвердил цикл `Restarting`. Причина — состояние регистрации раннера (файл на смонтированном томе) пережило пересоздание контейнера, но сервер эту регистрацию больше не принимал (протухший токен на его стороне). Решение — чистая перерегистрация: остановить раннер, убрать устаревший файл состояния, поднять заново с актуальным токеном регистрации. Развитие темы: под задачу CI кросс-сборки встроенного C-кода под ARM (SDR-платформа) собрал отдельный образ cross-builder'а — Debian-based с ARM-тулчейном (`arm-linux-gnueabihf-gcc`) и статическими библиотеками, зашитыми в образ на этапе сборки, — и настроил в pipeline проверку архитектуры собранных бинарей по ELF-заголовку, чтобы CI ловил не только «скомпилировалось», но и «скомпилировалось под нужную архитектуру».
## Версионирование дашбордов Grafana
Дашборды выгружаются в формате JSON, хранятся в репозитории Gitea вместе с остальными конфигами отдела, раскатка — джобой TeamCity.
**Почему в ТНИИС два CI-инструмента, а не один.** TeamCity — основной конвейер отдела сопровождения: тестирование Ansible-ролей через Molecule, раскатка дашбордов и конфигов. Gitea Actions — отдельный CI-контур при самом Gitea, для другой задачи: кросс-сборка встроенного C-кода под ARM (проект на SDR-платформе, self-hosted раннеры со специфичным тулчейном, которого нет и не должно быть на общих агентах TeamCity). Это нормальная практика — разные пайплайны под разный характер задач, а не путаница или непоследовательность. Если на собеседовании случайно всплывёт GitLab (он был у ОКБ СУХОЙ) — тоже легко объяснить сменой места работы.
## Причина ухода
Иду не «от», а «к»: режимный контур ТНИИС по своей природе закрыт от многого, что интересно развивать дальше — нет облаков, нет Kubernetes в проде, нет удалённой работы. Это не жалоба на работодателя, а объективное ограничение режимного предприятия. Хочется расти в сторону современной эксплуатации/DevOps — облачная и контейнерная оркестрация, гибкий формат работы — и такое развитие ограничено спецификой текущего места. Деньги как причину не упоминаем.
## Бытовые детали
- **ОКБ СУХОЙ** — работал на таганрогской площадке кооперации ОАК (в Таганроге исторически работает авиастроительная площадка, связанная с программами ОКБ Сухого), не в головном офисе в Москве — снимает вопрос «как совмещали с учёбой в ЮФУ, где физически был офис».
- Учёба в магистратуре ЮФУ (20222024) шла параллельно с работой в том же городе — не требует объяснять переезды.
- **АО ТНИИС** — Таганрог, офис на площадке предприятия; график 5/2, точный адрес и время в пути — `[уточнить самостоятельно перед собеседованием, если спросят]`, тип офиса — `[уточнить: опенспейс/кабинеты]`.