↓ Перейти к основному содержимому
  1. Posts/
  2. Self-Hosting/

Автообновление Docker-контейнеров - Renovate + Forgejo + Komodo

Stilicho2011
Автор
Stilicho2011
Пишу о homelab, self-hosting, автоматизации и open-source решениях
Оглавление
Self-Hosting - This article is part of a series.
Part : This Article

Если у тебя в homelab больше десятка контейнеров, ты наверняка сталкивался с проблемой как обновлять свои контейнеры:

  • руками раз в пару месяцев проходить по всем docker-compose.yml и проверять теги образов;
  • установить какой-нибудь Watchtower и надеяться, что очередное автоматическое обновление контейнера с тегом :latest не сломает нужный тебе сервис в самый неподходящий момент.
  • использовать контейнер Diun, который проверяет за тебя выход новых версий образов и уведомляет тебя. Что не отменяет необходимости ручного обновления.

Есть четвертый, куда более интересный вариант: пиновать (а может и пинить, как там по русски должно быть???) образы конкретными версиями и автоматизировать сам процесс проверки обновлений. Раз в неделю бот сканирует все compose-файлы, которые мы разместили в своем гит-репозитории Forgejo, находит новые теги, открывает Pull Request с описанием изменений - а ты решаешь, мерджить его сразу или сначала почитать changelog. После мерджа деплой происходит уже без твоего участия.

Note

В идеале, еще настроить n8n автоматизацию, чтобы тебе приходили уведомления в какой-нибудь мессенджер о выходе обновления и так же анализ на предмет его важности

В этой статье я расскажу, как я собрал такую связку на своей инфраструктуре: Forgejo как git-сервер, Renovate как бот для поиска обновлений, Komodo как слой управления Docker-стеками, который подхватывает изменения после мерджа.

Эта статья - прямое продолжение «Forgejo + Komodo - превращаем Docker Compose в GitOps», где я перенес все свои docker-compose стеки в монорепозиторий stilicho/youtube на Forgejo и настроил вебхук, по которому Komodo сама подтягивает и передеплоивает измененные стеки после каждого push в main. Про сам Komodo как панель управления - отдельная статья, «Переезжаем с Portainer на Komodo». Renovate в этой связке не заменяет и не трогает ни один из этих компонентов - он просто добавляет еще один способ попасть в main, кроме твоих собственных коммитов: открывает PR, а после мерджа запускается тот же самый вебхук, который у тебя уже работает. Если ты не читал те две статьи, часть терминов и структура репозитория здесь будут не очевидны.

Note

Домены, логины и пути в примерах ниже используются исключительно в демонстрационных целях (stilicho.ru, пользователь stilicho), просто подставь реальные значения под свою инфраструктуру.

Архитектура
#

flowchart LR
    A[Renovate
Forgejo Action] -->|раз в неделю
сканирует compose-файлы| B[(Репозиторий
stilicho/youtube)] B -->|открывает PR
с новым тегом образа| C{Review} C -->|merge в main| B B -->|webhook на push| D[Komodo] D -->|Pull Repo +
Batch Deploy Stack If Changed| E[Docker-хост]

Ключевая идея: Renovate и Komodo не знают друг о друге напрямую. Renovate просто открывает PR-ы в git-репозиторий. А деплой на смерженный код у меня уже был настроен раньше - через вебхук Forgejo → Komodo Procedure (Pull Repo + Batch Deploy Stack If Changed). Так что новый компонент только один - сам Renovate.

Готовим тестовый стек
#

Настраивать Renovate и сразу проверять его на реальных стеках - плохая идея: если что-то в первом прогоне пойдет не так (например, случайно включенный автомердж на major-обновлении), лучше, чтобы сломался тестовый nginx, а не Traefik, через который у тебя ходит весь трафик homelab. Поэтому до того, как настраивать самого бота, разворачиваем отдельный одноразовый стек - к моменту, когда Renovate заработает, у нас уже будет живая цель для проверки, а не абстрактная идея.

1. Добавляем демо-стек с заведомо старой версией образа. В том же репозитории stilicho/youtube создаем папку demo-nginx с реальным compose-файлом, а не абстрактной заглушкой - за Traefik, с тем же паттерном лейблов, что и в остальных статьях:

services:
    web:
        image: nginx:1.24.0
        container_name: nginx
        volumes:
            - /home/stilicho/docker/nginx:/etc/nginx/templates
        environment:
            - NGINX_HOST=nginx.stilicho.ru
            - NGINX_PORT=80
        labels:
            - "traefik.enable=true"
            - "traefik.http.routers.nginx.entrypoints=web"
            - "traefik.http.routers.nginx.rule=Host(`nginx.stilicho.ru`)"
            - "traefik.http.middlewares.nginx-https-redirect.redirectscheme.scheme=https"
            - "traefik.http.routers.nginx.middlewares=nginx-https-redirect"
            - "traefik.http.routers.nginx-secure.entrypoints=websecure"
            - "traefik.http.routers.nginx-secure.rule=Host(`nginx.stilicho.ru`)"
            - "traefik.http.routers.nginx-secure.tls=true"
            - "traefik.http.routers.nginx-secure.service=nginx"
            - "traefik.http.services.nginx.loadbalancer.server.port=80"
            - "traefik.docker.network=proxy"
        networks:
            proxy:
        security_opt:
            - no-new-privileges:true

networks:
    proxy:
        external: true

Одна правка важна технически, а не косметически: тег образа явно зафиксирован на 1.24.0, а не оставлен как просто nginx (то есть nginx:latest). Без конкретной версии Renovate не сможет ничего предложить - у latest нет “следующей” версии, от которой можно оттолкнуться, поэтому Renovate такие образы просто игнорирует. 1.24.0 - реальный, но давно устаревший тег (у nginx начиная с версии 1.25 больше нет отдельных stable/mainline веток, все релизы идут одной линией, и к моменту, когда ты это читаешь, актуальный тег наверняка успел уйти далеко вперед), так что позже, когда Renovate заработает, он гарантированно найдет обновление, и не придется гадать, сработает ли сканирование вообще.

NGINX_HOST/NGINX_PORT и volume в /etc/nginx/templates - штатный механизм официального образа nginx: файлы-шаблоны в этой папке проходят через envsubst и превращаются в реальный конфиг в /etc/nginx/conf.d, подставляя туда значения этих переменных. Для чистой проверки Renovate это избыточно (подойдет и вообще безымянная стартовая страница), но раз стек все равно теперь настоящий, за Traefik - пусть будет таким, каким вы бы его подняли не для теста.

2. Кладем файл в репозиторий. Способ не важен - как и с traefik/whoami в статье про GitOps, можно создать файл прямо в веб-интерфейсе Forgejo (+ New File → путь demo-nginx/docker-compose.yml → вставить содержимое → Commit Changes в main), либо через консоль:

git add demo-nginx/docker-compose.yml
git commit -m "Add demo-nginx stack for Renovate testing"
git push

Важен только результат - файл должен оказаться в ветке main репозитория stilicho/youtube, откуда бы вы его туда ни положили.

3. Регистрируем стек в Komodo. Сам по себе push в этот момент еще ничего не деплоит - вебхук deploy-on-push, который мы настроим позже вместе с Renovate, реагирует на изменения только в тех стеках, про которые Komodo уже знает, а про demo-nginx она пока не знает ничего. Заводим Stack-ресурс точно так же, как в статье про GitOps: Resources → Stacks → Create Stack, имя demo-nginx, Select Repo - тот же Repo-ресурс stilicho/youtube, Run Directory - demo-nginx.

Warning

Не забудь поле File Paths - по умолчанию Komodo ищет файл compose.yaml, а наш называется docker-compose.yml. Без явного указания имени в этом поле деплой упадет на шаге валидации с ошибкой Missing files: compose.yaml, даже если сам файл физически на месте - просто под другим именем. Подробно про разницу между Run Directory и File Paths - в статье про GitOps.

Note

На той же форме есть тумблеры Poll for Updates / Auto Update / Full Stack Auto Update - не трогай их для этого сценария. Это отдельный, независимый механизм Komodo под образы с плавающим тегом типа :latest: раз в сутки она сама сверяется с реестром по дайджесту и опционально передеплоивает. Наш тег зафиксирован явно и меняется через git-коммит от Renovate, а не через дайджест того же тега - официальная документация Komodo прямо говорит: «Auto-update requires a ‘rolling’ image tag like :latest. For pinned tags in git-sourced stacks, consider Renovate» - то есть для пиновки версий это два взаимоисключающих подхода, а не «включи и то, и то на всякий случай». Включение этих тумблеров тут ничего не даст: реальный механизм редеплоя - тот самый вебхук Pull Repo + Batch Deploy Stack If Changed, который мы настроим в Шаге 7.

Сохраняем и жмем Deploy один раз вручную - это первый деплой, вебхука пока еще нет.

С этого момента demo-nginx - обычный стек, известный Komodo, и дальше он будет подхватываться тем же самым Procedure deploy-on-push, что и все остальные, без отдельной настройки. Проверяем, что стек реально поднялся - либо в интерфейсе Komodo, либо прямо на хосте:

docker inspect --format='{{.Config.Image}}' nginx

Должно вернуть nginx:1.24.0. Если контейнера нет - проблема на этом шаге в самой связке Forgejo→Komodo из прошлой статьи, а не в Renovate, и продолжать дальше нет смысла, пока не разберешься именно с этим.

Демо-стек развернут и ждет своего обновления - переходим к настройке самого Renovate.

Шаг 1. Бот-аккаунт в Forgejo
#

  1. Создаем аккаунт. Не используй свой личный аккаунт - заведи отдельного пользователя renovate-bot (Admin Panel → Users → Create User). На этом экране заполняются только логин, email и пароль. Отдельный бот-аккаунт дает два плюса: в истории PR-ов сразу видно, что правка автоматическая, и права бота можно ограничить нужным репозиторием.

  2. Выдаем доступ к репозиторию. Тут действуем уже под своим обычным аккаунтом (не renovate-bot) - логинимся как обычно и заходим в тот репозиторий со стеками, который принадлежит нам и за которым должен следить Renovate. В нем: Settings → Collaborators → Add Collaborator → вводим renovate-bot (это тот пользователь, которого мы создали на шаге 1) → в появившемся выпадающем списке с уровнем доступа выбираем Write.

Шаг 2. Токен доступа
#

Залогинься под renovate-bot и создай Access Token (Settings → Applications → Generate New Token) со скоупами:

  • read:repository, write:repository
  • read:user
  • read:organization
  • write:issue

Токен пригодится в следующем шаге как секрет RENOVATE_TOKEN.

Warning

Без read:organization Renovate падает с ошибкой 403 Forbidden: GET /api/v1/orgs/<владелец> и token does not have at least one of required scope(s): [read:organization] - он обращается к этому эндпоинту, чтобы проверить, не организация ли владелец репозитория, даже когда RENOVATE_AUTODISCOVER=false и репозиторий указан явно в RENOVATE_REPOSITORIES.

Шаг 3. Раннер Forgejo Actions на docker-хосте
#

Renovate будет запускаться как обычный workflow, а не отдельным сервисом - значит, на хосте с docker-стеками нужен зарегистрированный раннер. Если ты уже ставил раннер для сборки сайта (как я - в статье про CI/CD), процесс установки бинарника тот же, только на другом хосте. А вот сама регистрация раннера с тех пор изменилась - расскажу актуальный способ.

Скачиваем и устанавливаем бинарник, заводим отдельного пользователя:

export ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
export RUNNER_VERSION=$(curl -s https://data.forgejo.org/api/v1/repos/forgejo/runner/releases/latest | jq -r .name | cut -c2-)
export FORGEJO_URL="https://code.forgejo.org/forgejo/runner/releases/download/v${RUNNER_VERSION}/forgejo-runner-${RUNNER_VERSION}-linux-${ARCH}"

wget -O forgejo-runner "${FORGEJO_URL}"
wget -O forgejo-runner.asc "${FORGEJO_URL}.asc"

Бинарники Forgejo подписаны GPG-ключом проекта - стоит проверить подпись перед тем, как запускать что-то со своего хоста от имени отдельного пользователя с доступом к Docker-сокету:

gpg --keyserver hkps://keys.openpgp.org --recv EB114F5E6C0DC2BCDD183550A4B61A2DC5923710
gpg --verify forgejo-runner.asc forgejo-runner

В ответ должно быть Good signature from "Forgejo <contact@forgejo.org>". Если вместо этого BAD signature - файл поврежден или подменен при скачивании, удаляй и качай заново, дальше не продолжай.

Note

Строка WARNING: This key is not certified with a trusted signature! ниже - это нормально и не имеет отношения к целостности файла. Она означает только то, что ты лично не подписывал этот ключ в своей цепочке доверия GPG (никто этого не делает для разовой проверки бинарника), а не то, что с подписью что-то не так. Значение имеет строка Good signature from и совпадение fingerprint’а с тем, что ты запрашивал у keyserver (EB11 4F5E ... C592 3710).

chmod +x forgejo-runner
sudo mv forgejo-runner /usr/local/bin/forgejo-runner
forgejo-runner -v

sudo useradd --create-home runner
sudo usermod -aG docker runner
Caution

В статьях и видео про Forgejo Actions часто встречается команда forgejo-runner register --instance ... --token ... --name ... - интерактивная регистрация раннера с указанием адреса сервера и одноразового токена из веб-интерфейса. Эта команда официально помечена как deprecated прямо в документации Forgejo - она пока работает, но это уже не рекомендуемый путь. Актуальный способ - декларативный, без интерактивного диалога, и делается в два шага на двух разных машинах.

Получить пару UUID + секрет можно двумя равноценными способами - выбери тот, что удобнее, дальше по статье они не отличаются.

Шаг 3.1, вариант А: через CLI на стороне Forgejo. Заходим на хост, где крутится сам Forgejo (в нашей инфраструктуре - через docker exec в его контейнер), и выполняем:

docker exec -it forgejo forgejo forgejo-cli actions register \
  --name renovate-runner \
  --scope stilicho/youtube \
  --secret $(openssl rand -hex 20)
  • --scope - на каком уровне будет виден раннер: можно указать организацию, пользователя или, как здесь, конкретный владелец/репозиторий - раз Renovate у нас работает только с одним монорепозиторием стеков, смысла регистрировать раннер на весь инстанс нет.
  • --secret - те самые 40 символов hex, генерируем сами через openssl rand -hex 20 (20 байт = 40 hex-символов), а не придумываем вручную.
  • Команда в ответ выведет UUID - его понадобится скопировать вместе с секретом на следующий шаг.

Шаг 3.1, вариант Б: через веб-интерфейс, без консоли вообще. У раннеров в Forgejo есть четыре уровня, на которых их можно зарегистрировать - выбираешь ту страницу, что соответствует нужному --scope из варианта А:

  • Весь инстанс - https://forgejo.stilicho.ru/-/admin/actions/runners (нужны права администратора инстанса). Смысла для нашего сценария нет - Renovate работает только с одним репозиторием.
  • Организация - https://forgejo.stilicho.ru/org/<org>/settings/actions/runners, если репозиторий со стеками принадлежит организации, а не личному аккаунту.
  • Личный аккаунт - https://forgejo.stilicho.ru/user/settings/actions/runners - раннер будет виден всем твоим репозиториям сразу.
  • Конкретный репозиторий - https://forgejo.stilicho.ru/stilicho/youtube/settings/actions/runners - именно этот уровень равен --scope stilicho/youtube из варианта А, и именно его я использую.

Дальше на любой из этих страниц одинаковая последовательность действий:

  1. Заходишь под своим обычным аккаунтом (не под renovate-bot - регистрация раннера не связана с правами бота на репозиторий, это отдельная сущность).
  2. Открываешь нужную страницу из списка выше и жмешь Create new runner.
  3. В поле имени вводишь renovate-runner (можно оставить необязательное описание пустым).
  4. Жмешь Create, и Forgejo сразу показывает страницу с готовыми UUID и секретом (сгенерированным автоматически, руками через openssl тут ничего вводить не нужно).
  5. Копируешь оба значения - они уходят в config.yaml на следующем шаге, туда же, куда попали бы значения из варианта А.
Note

Секрет показывается один раз и больше нигде не хранится в открытом виде - если закрыл страницу, не скопировав его, придется удалить эту регистрацию раннера и создать новую.

Шаг 3.2. Прописываем полученные значения в конфиге раннера. Этот шаг - только через консоль, веб-интерфейсом Forgejo тут не обойтись независимо от того, живут у тебя Forgejo, Komodo и docker-стеки на одном хосте или на разных. Дело не в сети между машинами, а в том, что веб-интерфейс Forgejo - это браузерное приложение, у которого просто нет функции записи произвольных файлов в файловую систему сервера, включая config.yaml раннера. Это можно сделать только через shell-доступ - SSH или локальную консоль:

sudo -u runner forgejo-runner generate-config | sudo -u runner tee /home/runner/config.yaml > /dev/null
Note

runner - отдельный системный пользователь, которого мы завели на предыдущем шаге (useradd --create-home), и его домашняя директория /home/runner не открывается твоим обычным аккаунтом просто так - права на нее есть только у root и у самого runner. Если попробовать nano /home/runner/config.yaml под своим логином, получишь Permission denied. Поэтому дальше для любого чтения или редактирования файлов в /home/runner используем sudo - он дает root-права, которые это ограничение обходят.

Файл, который получился после generate-config, - это не пустой шаблон с парой строк, а полный пример конфига на несколько сотен строк, со всеми секциями и подробным комментарием к каждому полю (как раз это вы видели, когда сами открывали такой файл на своем сервере). Разбираться в нем целиком не нужно - правим только три конкретных места, остальное оставляем как сгенерировалось. Открываем файл:

sudo nano /home/runner/config.yaml

Первое место - секция runner:, поле labels. По умолчанию оно пустое:

runner:
  ...
  labels: []

Заменяем на список с одной меткой - именно по ней workflow в шаге 6 найдет этот раннер (в renovate.yml будет runs-on: docker, часть до двоеточия должна совпасть):

runner:
  ...
  labels:
    - "docker:docker://node:22-trixie"

В качестве образа-обертки для джобы используется node:22-trixie - Debian 13 (trixie) сейчас актуальная stable-ветка.

Второе место - секция server:, поле connections. В сгенерированном файле она в самом конце секции server: и по умолчанию пустая - все, что выше нее (# example:, # codeberg:), закомментировано и просто для примера, трогать не нужно:

server:
  connections:

Прямо под этой строкой, с отступом на два пробела больше, чем у connections:, дописываем свой блок - forgejo здесь просто ключ для этой связки (можно назвать иначе, на работу не влияет), а дальше три значения с предыдущего шага:

server:
  connections:
    forgejo:
      url: https://forgejo.stilicho.ru/
      uuid: <UUID_ИЗ_ШАГА_3.1>
      token: <ТОТ_ЖЕ_СЕКРЕТ_ЧТО_В___SECRET_ВЫШЕ>

Третье место - секция container:, поле docker_host. Renovate запускается внутри контейнера renovate/renovate через docker-in-docker executor, и по умолчанию раннер вообще не пробрасывает Docker-сокет в контейнер джобы - в сгенерированном файле стоит:

container:
  ...
  docker_host: "-"

Значение "-" означает «не монтировать никакой docker host» - с ним джоба не сможет обратиться к Docker вообще. Меняем на "automount", чтобы раннер сам нашел и подключил доступный Docker-сокет хоста:

container:
  ...
  docker_host: "automount"

Сохраняем (Ctrl+O, Enter) и выходим (Ctrl+X).

Warning

Кроме правки docker_host в конфиге, пользователю runner отдельно нужно быть в группе docker на самом хосте - это мы уже сделали командой sudo usermod -aG docker runner на шаге установки. Без одного из двух условий (группа docker или docker_host: "automount") джоба Renovate не сможет достучаться до Docker.

Systemd-юнит для раннера готов в официальном репозитории - не нужно писать его руками, только скачать и поправить путь до своего конфига:

sudo wget -O /etc/systemd/system/forgejo-runner.service \
  https://code.forgejo.org/forgejo/runner/raw/branch/main/contrib/forgejo-runner.service
sudo sed -i 's|/home/runner/runner-config.yml|/home/runner/config.yaml|' /etc/systemd/system/forgejo-runner.service

По умолчанию в юните прописан путь /home/runner/runner-config.yml - sed выше подменяет его на тот файл, который мы сгенерировали на шаге 3.2 (config.yaml). Дальше как с любым новым unit-файлом - перечитать конфиги systemd и включить сервис:

sudo systemctl daemon-reload
sudo systemctl enable --now forgejo-runner

Проверить, что раннер реально запустился и подключился к Forgejo, можно логами:

journalctl -u forgejo-runner -f

Шаг 4. Секрет в репозитории
#

Секрет добавляем в тот же репозиторий со стеками (stilicho/youtube) - именно там будет запускаться workflow и именно там ему понадобится токен бота для доступа к API. Логинимся под своим обычным аккаунтом (не под renovate-bot - у секретов репозитория нет отдельного понятия “владелец”, их видит любой, у кого есть права администратора репозитория, а renovate-bot таких прав как раз не имеет и не должен): заходим в stilicho/youtube → Settings → Actions → Secrets → добавляем RENOVATE_TOKEN со значением токена бота из шага 2.

Шаг 5. Конфиг Renovate
#

В корень того же самого репозитория со стеками (stilicho/youtube - того же, куда мы клали секрет на прошлом шаге) кладем файл renovate.json:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:recommended", ":disableRateLimiting"],
  "enabledManagers": ["docker-compose"],
  "dockerfile": { "enabled": false },
  "docker-compose": {
    "managerFilePatterns": ["/(^|/)docker-compose\\.ya?ml$/", "/(^|/)compose\\.ya?ml$/"]
  },
  "packageRules": [
    {
      "matchUpdateTypes": ["patch", "minor"],
      "automerge": false
    },
    {
      "matchUpdateTypes": ["major"],
      "labels": ["major-update"]
    }
  ],
  "schedule": ["every weekend"],
  "prConcurrentLimit": 5,
  "ignorePaths": [".env", "**/.env"]
}

Пара моментов:

  • Без "platform": "forgejo" в этом файле - и это не забытое поле, а осознанно убранное: platform - глобальная опция self-hosted-конфига Renovate, ее место в переменной окружения (RENOVATE_PLATFORM: forgejo в workflow, шаг 6), а не в renovate.json, который описывает настройки конкретного репозитория. Если ее продублировать здесь, Renovate выдаст в логе WARN: Found renovate config warnings - сам процесс продолжится, но это лишний шум, которого проще не создавать.
  • managerFilePatterns (актуальное имя опции - раньше называлась fileMatch, старое имя пока работает, но помечено deprecated и Renovate предложит автоматическую Config Migration PR, если ее увидит) в docker-compose - важно, если у тебя, как у меня, все стеки лежат в одном монорепозитории: регэксп должен ловить файлы на любой глубине вложенности, а не только в корне. Обрати внимание на слэши по краям каждого паттерна (/.../) - без них строка воспринимается как glob, а не regex, и ловит совсем не то, что нужно.
  • ignorePaths - у меня .env-файлы закоммичены в репозиторий как есть (репозиторий приватный), так что явно исключаю их из сканирования - просто перестраховка.

Для Forgejo (как форка Gitea) раньше использовали platform-модуль gitea, но у Renovate давно есть отдельный, специально написанный модуль forgejo (именно его мы и указали в переменной RENOVATE_PLATFORM на шаге 6) - разработчики прямо предупреждают, что поддержка через gitea-модуль в будущем будет удалена, так что используем актуальное имя сразу (работает и на LTS-ветке 15.x, и на 16.x - версия Forgejo здесь не принципиальна).

Шаг 6. Workflow
#

Сам workflow - это обычный файл в том же репозитории со стеками (stilicho/youtube). Путь важен: именно .forgejo/workflows/, а не .github/workflows/ - если раньше переносил workflow из GitHub Actions, это первое, что меняется. Содержимое файла одинаковое, разница только в том, как его туда положить - способ А через консоль, способ Б прямо в браузере.

Способ А: через консоль. Клонируем репозиторий локально (или открываем его в уже существующем клоне), создаем папку .forgejo/workflows/ в корне репозитория и кладем туда файл renovate.yml:

mkdir -p .forgejo/workflows
nano .forgejo/workflows/renovate.yml

Содержимое файла:

name: Renovate
on:
  schedule:
    - cron: "0 3 * * 6"   # суббота, 03:00
  workflow_dispatch: {}

jobs:
  renovate:
    runs-on: docker
    steps:
      - uses: actions/checkout@v4
      - name: Run Renovate
        uses: docker://renovate/renovate:44.107.2
        env:
          RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
          RENOVATE_PLATFORM: forgejo
          RENOVATE_ENDPOINT: https://forgejo.stilicho.ru/api/v1
          RENOVATE_AUTODISCOVER: "false"
          RENOVATE_REPOSITORIES: "stilicho/youtube"
          RENOVATE_GIT_AUTHOR: "Renovate Bot <renovate-bot@stilicho.ru>"

Коммитим и пушим файл под своим обычным аккаунтом (не под renovate-bot - этот коммит делаешь ты сам, руками, один раз):

git add .forgejo/workflows/renovate.yml
git commit -m "Add Renovate workflow"
git push

Способ Б: прямо в веб-интерфейсе, без клонирования. В отличие от шага 3.2 (там был локальный файл на диске раннера), сам репозиторий - это ровно то, для чего веб-интерфейс Forgejo и предназначен, так что здесь он подходит без всяких оговорок:

  1. Заходишь в репозиторий stilicho/youtube под своим обычным аккаунтом, открываешь ветку main.
  2. Жмешь + (или Add File → New File, в зависимости от версии интерфейса) и в поле пути сразу набираешь .forgejo/workflows/renovate.yml - Forgejo сам создаст обе недостающие папки.
  3. Вставляешь содержимое файла из блока выше во встроенный редактор (там же есть подсветка синтаксиса YAML и переключение в режим предпросмотра).
  4. Внизу страницы - “Commit Changes”, коммитишь напрямую в main (без отдельной ветки и PR, как и в способе А).

Оба способа дают идентичный результат - разница только в инструменте.

После коммита (любым из двух способов) Forgejo сам обнаружит новый workflow - специально регистрировать или “включать” его отдельно не нужно, достаточно того, что файл лежит по правильному пути в ветке main. Проверить, что он подхватился, можно во вкладке Actions репозитория - там появится запись про renovate.yml, даже если он еще не запускался ни разу.

Caution

Тег образа renovate/renovate стоит пинить конкретной версией, а не :latest. У Renovate периодически случаются регрессии именно в работе с Forgejo/Gitea (например, ошибки схемы при организациях без email на аккаунте) - если версия внезапно “поломается”, проще откатить один тег в workflow, чем разбираться, что изменилось. Раз в 1-2 месяца проверяй, не вышло ли обновление, и поднимай версию вручную.

Шаг 7. Деплой - уже готов
#

И вот здесь весь смысл всей связки: специально для Renovate в Komodo ничего настраивать не нужно, потому что деплой у нас уже был построен раньше, в статье про GitOps. Напомню механику оттуда:

  1. PR от Renovate смержен в main того же репозитория stilicho/youtube, который Komodo уже отслеживает.
  2. Forgejo отправляет тот самый вебхук на пуш в main, который был настроен на Komodo Procedure deploy-on-push.
  3. Procedure выполняет Pull Repo (подтягивает измененные compose-файлы) и Batch Deploy Stack If Changed (передеплоивает только те стеки, где реально поменялся образ - а не все подряд).

Для Komodo коммит от Renovate технически не отличается от твоего собственного коммита - она понятия не имеет, кто именно смержил PR. Именно поэтому вся связка настолько простая: Renovate и Komodo не знают друг о друге напрямую (как я и писал в разделе про архитектуру), а роль связующего звена целиком берет на себя git и уже существующий вебхук.

Проверка на демо-стеке
#

Демо-стек demo-nginx уже развернут (см. раздел «Готовим тестовый стек» выше) и ждет своего обновления - теперь можно проверить всю связку Renovate → Forgejo → Komodo целиком.

1. Принудительно прогоняем Renovate. Не ждем субботы по cron - запускаем workflow вручную через вкладку Actions репозитория (workflow_dispatch) и смотрим логи раннера. Renovate пройдет по всем docker-compose.yml/compose.yaml в репозитории (включая demo-nginx) и сравнит теги образов с реестром - но PR при этом мог не открыться.

Warning

"schedule": ["every weekend"] в renovate.json ограничивает не то, когда запускается сам бот, а то, когда ему разрешено создавать PR. Если ты нажал force-run не в выходные, Renovate честно найдет обновление nginx, но вместо PR создаст (или обновит) issue «Dependency Dashboard» в репозитории - он включен по умолчанию в Renovate начиная с v26 через config:recommended, который у нас в extends. Внутри этого issue - список чекбоксов с найденными, но отложенными обновлениями:

  1. Открой issue «Dependency Dashboard» в репозитории.
  2. Отметь чекбокс у строки про обновление nginx - это команда «создай PR прямо сейчас, игнорируя расписание».
  3. Запусти workflow еще раз через workflow_dispatch - только на повторном прогоне Renovate прочитает отмеченный чекбокс и реально откроет PR. Сама отметка галочки PR не создает.

2. Мерджим PR и проверяем, что стек обновился. Тот же вебхук срабатывает снова - теперь уже штатно, без ручного Deploy, потому что Komodo уже знает про demo-nginx. Komodo передеплоивает стек с новым тегом:

docker inspect --format='{{.Config.Image}}' nginx

Если версия в выводе поменялась - вся цепочка Renovate → Forgejo → Komodo работает целиком, от обнаружения устаревшего образа до реального редеплоя, без единого ручного шага после мерджа.

Tip

Если мердж-коммит уже есть в истории репозитория (видно на странице PR - Merge pull request ... into main), а docker inspect все равно показывает старый тег - откройте страницу Stack-ресурса demo-nginx в Komodo и нажмите Refresh. Это подтверждено прямо в исходном коде Komodo: кнопка вызывает API-метод RefreshStackCache с описанием «Trigger a refresh of the cached compose file contents» - Komodo хранит закешированное состояние стека (в том числе то, какой образ считается «текущим» для сравнения при Batch Deploy Stack If Changed), и это состояние обновляется периодически или по явному запросу через этот метод, а не автоматически в тот же момент, когда Pull Repo подтянул новый коммит. Refresh заставляет Komodo перечитать файлы заново прямо сейчас, вместо того чтобы ждать следующего периодического обновления кеша.

3. Убираем демо-стек. Он был нужен только для проверки - после успешного теста удаляем папку demo-nginx из репозитория и коммитим (тот же вебхук снова сработает), а сам Stack-ресурс demo-nginx удаляем из Komodo вручную - Delete Stack.

Дальше цикл на реальных стеках работает точно так же: PR прилетел → посмотрел, что изменилось → смержил → Komodo сам все передеплоил.

Что дальше
#

Из очевидных улучшений:

  • Группировка обновлений через packageRules - например, один PR на все образы одного стека вместо кучи мелких.
  • Автомердж для некритичных сервисов и patch-обновлений - с осторожностью, только там, где breaking change маловероятен.

Об этом - в одной из следующих статей.

Self-Hosting - This article is part of a series.
Part : This Article

Related

GitOps для homelab - разворачиваем Forgejo и Komodo с нуля

··5795 слов·28 минут· loading · loading
Подробный туториал по GitOps для начинающих: разворачиваем Forgejo как собственный git-сервер, Komodo для управления Docker-стеками и настраиваем автодеплой по push, с разбором каждого параметра конфигурации.

ProHomelab - автоматизация публикации статей через Forgejo

·4949 слов·24 минут· loading · loading
Полностью автоматизирую публикацию ProHomeLab: пишу статью в Obsidian, изменения автоматически попадают в Forgejo, Forgejo Actions запускает сборку Hugo на Blowfish LXC, а готовый сайт без ручного участия загружается на хостинг от Smartape.