Netpulse_SasS/deploy/docker-compose.ci.yml
byrsapty c83324ae3e
Some checks failed
CI / hygiene (push) Successful in 9s
CI / web (push) Successful in 1m13s
CI / server (push) Successful in 1m34s
CI / dbtest (push) Successful in 1m52s
CI / agent (push) Has been cancelled
Відкат на живому залізі: пароль адміністратора лежав відкритим
Механізм відкату існував з 0035 і жодного разу не виконувався на
справжньому обладнанні. Прогін до межі заліза (план -> заявка ->
погодження, без заливки) дав три правильні відмови й одну знахідку.

D-Link питає пароль інтерактивно, і `show config` віддає відповіді
окремими рядками без ключових слів. Порядкове маскування за зразками
такий рядок не бачить, тож пароль адміністратора живого комутатора
лежав у плані відкату, у ncm.rollbacks і в git-дзеркалі — маскування
перед записом у git немає взагалі.

redactLines отримав стан: після рядка заведення облікового запису до
двох односкладових рядків маскуються. Ім'я запису лишається видимим.

Дорогою: перший рядок збереженого конфігу — відлуння команди
(`Command: show config`), і планувальникклав його в команди до заливки.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 23:42:43 +03:00

165 lines
10 KiB
YAML
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.

# Раннер Forgejo Actions для NetPulse — окремим стеком.
#
# Окремий файл, а не сервіс у docker-compose.yml, свідомо: CI не має
# ані підніматись, ані падати разом із продуктом. `docker compose down`
# на стенді не повинен забирати з собою раннер, а перезапуск раннера не
# повинен торкатись бази.
#
# ─────────────────────────────────────────────────────────────────────
# РЕЄСТРАЦІЯ (робиться один раз, руками)
#
# 1. У Forgejo: Налаштування → Actions → Runners → Create registration
# token. Рівень вибирає, що раннер бачитиме:
# репозиторій — лише netpulse (для цієї задачі досить);
# організація/інстанс — усі репозиторії, включно з майбутніми.
# Раннер має root-доступ до докера машини, тому ширший рівень
# означає, що будь-який workflow у будь-якому репозиторії отримує
# цей доступ. Беріть найвужчий, який покриває потребу.
#
# 2. Реєстрація (виконати В КАТАЛОЗІ repo/deploy):
#
# docker compose -f docker-compose.ci.yml run --rm runner \
# forgejo-runner register --no-interactive \
# --instance https://git.zotac.keenetic.link \
# --token <REGISTRATION_TOKEN> \
# --name netpulse-ci \
# --labels docker:docker://node:22-alpine
#
# Результат — файл .runner у томі runner-data. Він переживає
# перестворення контейнера; повторно реєструватись не треба.
#
# 3. Запуск:
#
# docker compose -f docker-compose.ci.yml up -d
# docker compose -f docker-compose.ci.yml logs -f runner
#
# У Forgejo раннер має зʼявитись у списку зі станом «idle».
#
# ЯКЩО FORGEJO НА ЦІЙ САМІЙ МАШИНІ. Публічне імʼя git.zotac.keenetic.link
# з контейнера може не резолвитись у себе (розворот NAT на роутері
# роблять не всі). Ознака — раннер не реєструється або мовчить після
# старту. Лікується одним рядком у сервісі runner:
#
# extra_hosts:
# - "git.zotac.keenetic.link:host-gateway"
#
# ─────────────────────────────────────────────────────────────────────
# ЧОГО ЦЕЙ ФАЙЛ КОШТУЄ
#
# Памʼять у спокої: раннер ~40 МБ + прибиральник ~5 МБ.
# Памʼять під час прогону: одна робота за раз (capacity: 1), стеля
# контейнера роботи — 1600 МБ (deploy/act-runner.config.yml), плюс
# контейнер Postgres у роботах server і dbtest (~400 МБ із
# TS_TUNE_MEMORY). Роботи з базою дві, але йдуть вони по черзі, тож
# пік від цього не росте: ~2 ГБ понад те, що вже їсть бойовий стек.
# Диск: образи ~1.1 ГБ (alpine 8 МБ, node:22-alpine ~180 МБ,
# golang:1.25-alpine ~350 МБ, timescaledb ~450 МБ, сам раннер
# ~120 МБ) + кеші зі стелями 1200/900/400 МБ, які тримають самі
# роботи наприкінці кожного прогону.
# Разом у найгіршому випадку ~3.6 ГБ диска.
#
# ─────────────────────────────────────────────────────────────────────
name: netpulse-ci
services:
runner:
# ВЕРСІЮ ЗВІРТЕ ЗІ СВОЇМ FORGEJO. Раннер і сервер сумісні не в
# будь-яких парах, а який саме Forgejo стоїть у вас — звідси не
# видно. Це єдиний рядок у цьому файлі, який неможливо перевірити
# без доступу до стенду.
image: ${FORGEJO_RUNNER_IMAGE:-code.forgejo.org/forgejo/runner:6}
container_name: netpulse-ci-runner
restart: unless-stopped
command: ["forgejo-runner", "daemon", "--config", "/etc/forgejo/runner.yml"]
working_dir: /data
environment:
DOCKER_HOST: unix:///var/run/docker.sock
TZ: ${TZ:-Europe/Kyiv}
# Група власника сокета докера. Образ раннера працює не від root
# (uid 1000), а сокет має права rw лише для власника й групи — без
# цього рядка демон падає в циклі з «permission denied ... docker.sock»
# і жодна робота не стартує.
#
# Номер групи різний на різних машинах, тому змінна. Свій дізнатись:
# stat -c %g /var/run/docker.sock
# Помилка тут видима одразу: демон не піднімається й пише причину.
group_add:
- "${DOCKER_GID:-991}"
volumes:
# Сокет докера, а не docker-in-docker. DinD означав би ще один
# демон, власний пул образів (тобто ДРУГУ копію golang, node і
# timescaledb) і власний шар зберігання — на машині з ~7 ГБ це
# не поміщається. Ціна вибору названа чесно: усе, що потрапить у
# workflow, виконується з правами root на цьому докері.
- /var/run/docker.sock:/var/run/docker.sock
- runner-data:/data
- ./act-runner.config.yml:/etc/forgejo/runner.yml:ro
# Сам демон нічого важкого не робить — уся робота в дочірніх
# контейнерах, і їхню стелю задає container.options у конфізі.
mem_limit: 256m
# Прибиральник. Половина сенсу цього стеку.
#
# act лишає по собі зупинені контейнери робіт і сервісів, а зміна
# тега образу лишає «висячий» попередній. Саме по собі це не
# зникає, і на диску, якого ~7 ГБ, воно закінчується не роками, а
# тижнями. CI, який забив диск, зупинить продукт, а не покращить.
#
# Кешів Go й npm цей сервіс НЕ чіпає навмисно: їх підрізають самі
# роботи, останнім кроком. У той момент точно ніхто не компілює, тож
# чистка не може вирвати файл з-під `go build`. Прибиральник, який
# ходить за розкладом, такої гарантії не має.
gc:
image: docker:28-cli
container_name: netpulse-ci-gc
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# Томи кешів підключені лише щоб їх БАЧИТИ: compose створює
# іменований том тоді, коли його хтось монтує, а розмір у логу
# прибиральника — єдине місце, де за ним можна стежити, не
# заходячи на машину.
- gomod:/caches/gomod:ro
- gobuild:/caches/gobuild:ro
- npm:/caches/npm:ro
group_add:
- "${DOCKER_GID:-991}"
entrypoint: ["/bin/sh", "-c"]
# Список з ОДНИМ елементом, а не рядок. `command:` рядком compose
# розбиває на слова за правилами оболонки, і `/bin/sh -c` отримує
# аргументом саме «while» — контейнер падає в циклі з «syntax error:
# unexpected end of file (expecting "do")». Блоковий скаляр у списку
# лишається одним аргументом, як і задумано.
command:
- |
while :; do
# БЕЗ -a і БЕЗ --volumes. `prune -a` знесла б образи бойового
# стеку, які просто зараз не запущені (наприклад, під час
# оновлення), а `--volumes` — дані. Тут прибирається лише те,
# що вже нічим не тримається: зупинені контейнери, підвішені
# образи, порожні мережі, кеш складання.
docker system prune -f --filter 'until=72h' >/dev/null 2>&1 || true
free=$$(df -Pm /caches/gobuild 2>/dev/null | awk 'NR==2{print $$4}')
echo "$$(date -Iseconds) CI-gc: вільно $${free:-?} МБ; кеші:" \
"$$(du -sh /caches/gomod /caches/gobuild /caches/npm 2>/dev/null | tr '\n' ' ')"
sleep 21600
done
mem_limit: 64m
volumes:
# Реєстрація раннера (.runner) — без неї доведеться реєструватись
# заново після кожного перестворення контейнера.
runner-data:
# Кеші збірок. Імена задані явно, БЕЗ префікса проєкту: у
# .forgejo/workflows/ci.yml вони пишуться саме так, а контейнери робіт
# створює act напряму, а не compose, тож жодного префікса він не
# додасть. Ці ж імена мають бути в container.valid_volumes конфігу
# раннера, інакше роботи впадуть на монтуванні.
gomod:
name: netpulse-ci-gomod
gobuild:
name: netpulse-ci-gobuild
npm:
name: netpulse-ci-npm