CI-раннер: дві поломки, які видно лише на живому запуску
Some checks failed
CI / hygiene (push) Successful in 13s
CI / web (push) Successful in 44s
CI / server (push) Successful in 1m58s
CI / agent (push) Failing after 22s

Обидві знайдені першим справжнім стартом на стенді — саме там, де автор
файла чесно написав «поведінка act_runner це міркування з документації,
а не спостереження».

1. Демон падав у циклі з «permission denied … docker.sock». Образ
   раннера працює від uid 1000, а сокет належить root:docker з правами
   лише для власника й групи. Додано group_add із номером групи сокета;
   номер різний на різних машинах, тому змінна DOCKER_GID і команда для
   пошуку в коментарі.

2. Прибиральник падав у циклі з «syntax error: unexpected end of file
   (expecting "do")». `command:` рядком compose розбиває на слова за
   правилами оболонки, тож /bin/sh -c отримував аргументом саме «while».
   Тепер список з одного блокового скаляра — один аргумент, як і
   задумано.

Друга особливо показова: YAML валідний, синтаксис sh валідний, і кожна
перевірка окремо зелена. Ламається лише поєднання, і лише при запуску.
This commit is contained in:
byrsapty 2026-08-27 17:52:19 +03:00
parent 3f6bcbc5a0
commit 4b77c14168

View file

@ -75,6 +75,16 @@ services:
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 і
@ -112,20 +122,28 @@ services:
- gomod:/caches/gomod:ro
- gobuild:/caches/gobuild:ro
- npm:/caches/npm:ro
group_add:
- "${DOCKER_GID:-991}"
entrypoint: ["/bin/sh", "-c"]
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
# Список з ОДНИМ елементом, а не рядок. `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: