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: environment:
DOCKER_HOST: unix:///var/run/docker.sock DOCKER_HOST: unix:///var/run/docker.sock
TZ: ${TZ:-Europe/Kyiv} 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: volumes:
# Сокет докера, а не docker-in-docker. DinD означав би ще один # Сокет докера, а не docker-in-docker. DinD означав би ще один
# демон, власний пул образів (тобто ДРУГУ копію golang, node і # демон, власний пул образів (тобто ДРУГУ копію golang, node і
@ -112,20 +122,28 @@ services:
- gomod:/caches/gomod:ro - gomod:/caches/gomod:ro
- gobuild:/caches/gobuild:ro - gobuild:/caches/gobuild:ro
- npm:/caches/npm:ro - npm:/caches/npm:ro
group_add:
- "${DOCKER_GID:-991}"
entrypoint: ["/bin/sh", "-c"] entrypoint: ["/bin/sh", "-c"]
command: | # Список з ОДНИМ елементом, а не рядок. `command:` рядком compose
while :; do # розбиває на слова за правилами оболонки, і `/bin/sh -c` отримує
# БЕЗ -a і БЕЗ --volumes. `prune -a` знесла б образи бойового # аргументом саме «while» — контейнер падає в циклі з «syntax error:
# стеку, які просто зараз не запущені (наприклад, під час # unexpected end of file (expecting "do")». Блоковий скаляр у списку
# оновлення), а `--volumes` — дані. Тут прибирається лише те, # лишається одним аргументом, як і задумано.
# що вже нічим не тримається: зупинені контейнери, підвішені command:
# образи, порожні мережі, кеш складання. - |
docker system prune -f --filter 'until=72h' >/dev/null 2>&1 || true while :; do
free=$$(df -Pm /caches/gobuild 2>/dev/null | awk 'NR==2{print $$4}') # БЕЗ -a і БЕЗ --volumes. `prune -a` знесла б образи бойового
echo "$$(date -Iseconds) CI-gc: вільно $${free:-?} МБ; кеші:" \ # стеку, які просто зараз не запущені (наприклад, під час
"$$(du -sh /caches/gomod /caches/gobuild /caches/npm 2>/dev/null | tr '\n' ' ')" # оновлення), а `--volumes` — дані. Тут прибирається лише те,
sleep 21600 # що вже нічим не тримається: зупинені контейнери, підвішені
done # образи, порожні мережі, кеш складання.
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 mem_limit: 64m
volumes: volumes: