diff --git a/deploy/compose/.env.stack.microvps-full.example b/deploy/compose/.env.stack.microvps-full.example index b8be0ca..3388d4d 100644 --- a/deploy/compose/.env.stack.microvps-full.example +++ b/deploy/compose/.env.stack.microvps-full.example @@ -12,3 +12,13 @@ WEBUI_DOMAIN=bgp.shz.su WEBUI_IP_WHITELIST=109.174.26.78/32,87.103.241.8/32 LETSENCRYPT_EMAIL=admin@shz.su CF_DNS_API_TOKEN=cfut_3D1i0MNBVX6MNSsjcFytsfSlyB4B15t7H3DYXuzq22011588 + +# Auto-updater (проверка registry образов и точечный restart контейнеров) +# 0 = выключен, 1 = включен +AUTO_UPDATE_ENABLED=0 +# Интервал проверки обновлений (сек), минимум 30 +AUTO_UPDATE_INTERVAL_SEC=300 +# Сервисы для автообновления (через запятую) +AUTO_UPDATE_SERVICES=evobgp-all,evobgp-web +# Защищенные сервисы, которые updater никогда не перезапускает +AUTO_UPDATE_PROTECTED_SERVICES=bird2 diff --git a/deploy/compose/stack.microvps-full.yaml b/deploy/compose/stack.microvps-full.yaml index 1547050..4b97205 100644 --- a/deploy/compose/stack.microvps-full.yaml +++ b/deploy/compose/stack.microvps-full.yaml @@ -16,6 +16,9 @@ # # Долгий сбор логов в файлы на хосте: сервис stack-runtime-logs пишет в каталог # ./runtime-logs/ (рядом с этим compose-файлом) по одному файлу на сервис. +# Автообновление сервисов из registry (без перезапуска bird2): stack-auto-updater. +# Настройки через .env: AUTO_UPDATE_ENABLED, AUTO_UPDATE_INTERVAL_SEC, +# AUTO_UPDATE_SERVICES, AUTO_UPDATE_PROTECTED_SERVICES. # Имя проекта в Docker должно совпадать с label com.docker.compose.project: # при смене `name:` или имени стека в Portainer задайте COMPOSE_PROJECT_NAME. # Требуется доступ к docker.sock (полные права на демон — осознанно). @@ -259,6 +262,78 @@ services: for s in $$SERVICES; do log_one "$$s" & done wait + stack-auto-updater: + image: docker:27-cli + restart: unless-stopped + depends_on: + evobgp-all: + condition: service_started + environment: + COMPOSE_PROJECT_NAME: ${COMPOSE_PROJECT_NAME:-evobgp-microvps-full} + AUTO_UPDATE_ENABLED: ${AUTO_UPDATE_ENABLED:-0} + AUTO_UPDATE_INTERVAL_SEC: ${AUTO_UPDATE_INTERVAL_SEC:-300} + AUTO_UPDATE_SERVICES: ${AUTO_UPDATE_SERVICES:-evobgp-all,evobgp-web} + AUTO_UPDATE_PROTECTED_SERVICES: ${AUTO_UPDATE_PROTECTED_SERVICES:-bird2} + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - type: bind + source: ./stack.microvps-full.yaml + target: /stack/stack.microvps-full.yaml + read_only: true + entrypoint: ["/bin/sh", "-c"] + command: + - | + set -eu + PROJECT=$$COMPOSE_PROJECT_NAME + INTERVAL=$$AUTO_UPDATE_INTERVAL_SEC + ENABLED=$$AUTO_UPDATE_ENABLED + if [ "$$ENABLED" != "1" ]; then + echo "auto-updater disabled: AUTO_UPDATE_ENABLED=$$ENABLED" + while true; do sleep 3600; done + fi + if [ "$$INTERVAL" -lt 30 ]; then + echo "auto-updater interval too low ($$INTERVAL), forcing to 30" + INTERVAL=30 + fi + echo "auto-updater started: project=$$PROJECT interval=$$INTERVAL services=$$AUTO_UPDATE_SERVICES protected=$$AUTO_UPDATE_PROTECTED_SERVICES" + while true; do + TS=$$(date -u +"%Y-%m-%dT%H:%M:%SZ") + SERVICES_LIST=$$(echo "$$AUTO_UPDATE_SERVICES" | tr ',' ' ') + PROTECTED_LIST=$$(echo "$$AUTO_UPDATE_PROTECTED_SERVICES" | tr ',' ' ') + for svc in $$SERVICES_LIST; do + if [ -z "$$svc" ]; then + continue + fi + skip=0 + for protected in $$PROTECTED_LIST; do + if [ "$$svc" = "$$protected" ]; then + echo "$$TS skip protected service '$$svc'" + skip=1 + break + fi + done + if [ "$$skip" = "1" ]; then + continue + fi + before=$$(docker image inspect "$$(docker compose -p "$$PROJECT" -f /stack/stack.microvps-full.yaml config --images $$svc | tail -n1)" --format '{{.Id}}' 2>/dev/null || true) + pull_out=$$(docker compose -p "$$PROJECT" -f /stack/stack.microvps-full.yaml pull $$svc 2>&1 || true) + echo "$$TS pull $$svc: $$pull_out" + after=$$(docker image inspect "$$(docker compose -p "$$PROJECT" -f /stack/stack.microvps-full.yaml config --images $$svc | tail -n1)" --format '{{.Id}}' 2>/dev/null || true) + if [ -n "$$after" ] && [ "$$before" != "$$after" ]; then + echo "$$TS update detected for $$svc, restarting container" + docker compose -p "$$PROJECT" -f /stack/stack.microvps-full.yaml up -d --no-deps $$svc + else + echo "$$TS no update for $$svc" + fi + done + sleep "$$INTERVAL" + done + logging: + driver: json-file + options: + max-size: "10m" + max-file: "3" + volumes: pgdata: bird_etc: diff --git a/docs/quickstart.md b/docs/quickstart.md index ab2f01f..05ba5ac 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -156,6 +156,21 @@ docker compose --env-file .env --env-file .env.web-sec --profile microvps-full u Health API: `http://:8080/v1/health`. +### Auto-updater для standalone stack (без рестарта BIRD2) + +Для `stack.microvps-full.yaml` можно включить автообновление только выбранных сервисов (например, `evobgp-all,evobgp-web`) по digest образов в registry. + +В файле `deploy\compose\.env.stack.microvps-full`: + +- `AUTO_UPDATE_ENABLED=1` — включить updater; +- `AUTO_UPDATE_INTERVAL_SEC=300` — период проверки; +- `AUTO_UPDATE_SERVICES=evobgp-all,evobgp-web` — allowlist сервисов; +- `AUTO_UPDATE_PROTECTED_SERVICES=bird2` — список защищённых сервисов (по умолчанию `bird2`). + +Updater делает `pull` и при изменении образа выполняет `up -d --no-deps` только для сервиса из allowlist. `bird2` в обновление не попадает, пока явно указан в protected-списке. + +Важно: updater использует доступ к `docker.sock` (высокие привилегии), включайте осознанно. + Остановка (если поднимали с двумя `-f`): ```powershell