Механізм відкату існував з 0035 і жодного разу не виконувався на справжньому обладнанні. Прогін до межі заліза (план -> заявка -> погодження, без заливки) дав три правильні відмови й одну знахідку. D-Link питає пароль інтерактивно, і `show config` віддає відповіді окремими рядками без ключових слів. Порядкове маскування за зразками такий рядок не бачить, тож пароль адміністратора живого комутатора лежав у плані відкату, у ncm.rollbacks і в git-дзеркалі — маскування перед записом у git немає взагалі. redactLines отримав стан: після рядка заведення облікового запису до двох односкладових рядків маскуються. Ім'я запису лишається видимим. Дорогою: перший рядок збереженого конфігу — відлуння команди (`Command: show config`), і планувальникклав його в команди до заливки. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
165 lines
10 KiB
YAML
165 lines
10 KiB
YAML
# Раннер 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
|