Реальная настройка 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.
92 lines
18 KiB
Markdown
92 lines
18 KiB
Markdown
# Нарратив работы в АО ТНИИС
|
||
|
||
Живой рассказ о работе поверх сухого таймлайна из [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-решений.
|
||
|
||
## Состав отдела (черновой ориентир, подтвердить/поправить)
|
||
|
||
Отдел сопровождения и мониторинга — небольшая команда: начальник отдела и порядка 6–7 инженеров: 1–2 инженера сопровождения (включая меня), 1–2 инженера мониторинга, 1–2 Java-разработчика на стороне сопровождаемых сервисов. Смежные подразделения: группа Linux-администраторов (обслуживают парк VM целиком) и профильный отдел разработки (пишет и релизит сами Java-сервисы, я — со стороны эксплуатации и мониторинга).
|
||
|
||
**Если на собеседовании спрашивают про сложные кейсы, а готового ответа нет:** нормально сослаться на команду — «эту часть решали совместно с администраторами» или «советовался с более опытным коллегой по мониторингу» — так и было в реальности, младший инженер не решает всё в одиночку.
|
||
|
||
## Распорядок дня
|
||
|
||
Утро начинается с короткого дейлика (15–30 минут): начальник отдела опрашивает по текущим задачам и инцидентам, задачи ведутся в 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 — облачная и контейнерная оркестрация, гибкий формат работы — и такое развитие ограничено спецификой текущего места. Деньги как причину не упоминаем.
|
||
|
||
## Бытовые детали
|
||
|
||
- **ОКБ СУХОЙ** — работал на таганрогской площадке кооперации ОАК (в Таганроге исторически работает авиастроительная площадка, связанная с программами ОКБ Сухого), не в головном офисе в Москве — снимает вопрос «как совмещали с учёбой в ЮФУ, где физически был офис».
|
||
- Учёба в магистратуре ЮФУ (2022–2024) шла параллельно с работой в том же городе — не требует объяснять переезды.
|
||
- **АО ТНИИС** — Таганрог, офис на площадке предприятия; график 5/2, точный адрес и время в пути — `[уточнить самостоятельно перед собеседованием, если спросят]`, тип офиса — `[уточнить: опенспейс/кабинеты]`.
|