Если у тебя в homelab больше десятка контейнеров, ты наверняка сталкивался с проблемой как обновлять свои контейнеры:
- руками раз в пару месяцев проходить по всем
docker-compose.ymlи проверять теги образов; - установить какой-нибудь Watchtower и надеяться, что очередное автоматическое обновление контейнера с тегом
:latestне сломает нужный тебе сервис в самый неподходящий момент. - использовать контейнер Diun, который проверяет за тебя выход новых версий образов и уведомляет тебя. Что не отменяет необходимости ручного обновления.
Есть четвертый, куда более интересный вариант: пиновать (а может и пинить, как там по русски должно быть???) образы конкретными версиями и автоматизировать сам процесс проверки обновлений. Раз в неделю бот сканирует все compose-файлы, которые мы разместили в своем гит-репозитории Forgejo, находит новые теги, открывает Pull Request с описанием изменений - а ты решаешь, мерджить его сразу или сначала почитать changelog. После мерджа деплой происходит уже без твоего участия.
В идеале, еще настроить 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, а после мерджа запускается тот же самый вебхук, который у тебя уже работает. Если ты не читал те две статьи, часть терминов и структура репозитория здесь будут не очевидны.
Домены, логины и пути в примерах ниже используются исключительно в демонстрационных целях (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.
Не забудь поле File Paths - по умолчанию Komodo ищет файл compose.yaml, а наш называется docker-compose.yml. Без явного указания имени в этом поле деплой упадет на шаге валидации с ошибкой Missing files: compose.yaml, даже если сам файл физически на месте - просто под другим именем. Подробно про разницу между Run Directory и File Paths - в статье про GitOps.
На той же форме есть тумблеры 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#
Создаем аккаунт. Не используй свой личный аккаунт - заведи отдельного пользователя
renovate-bot(Admin Panel → Users → Create User). На этом экране заполняются только логин, email и пароль. Отдельный бот-аккаунт дает два плюса: в истории PR-ов сразу видно, что правка автоматическая, и права бота можно ограничить нужным репозиторием.Выдаем доступ к репозиторию. Тут действуем уже под своим обычным аккаунтом (не
renovate-bot) - логинимся как обычно и заходим в тот репозиторий со стеками, который принадлежит нам и за которым должен следить Renovate. В нем: Settings → Collaborators → Add Collaborator → вводимrenovate-bot(это тот пользователь, которого мы создали на шаге 1) → в появившемся выпадающем списке с уровнем доступа выбираем Write.
Шаг 2. Токен доступа#
Залогинься под renovate-bot и создай Access Token (Settings → Applications → Generate New Token) со скоупами:
read:repository,write:repositoryread:userread:organizationwrite:issue
Токен пригодится в следующем шаге как секрет RENOVATE_TOKEN.
Без 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 - файл поврежден или подменен при скачивании, удаляй и качай заново, дальше не продолжай.
Строка 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В статьях и видео про 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из варианта А, и именно его я использую.
Дальше на любой из этих страниц одинаковая последовательность действий:
- Заходишь под своим обычным аккаунтом (не под
renovate-bot- регистрация раннера не связана с правами бота на репозиторий, это отдельная сущность). - Открываешь нужную страницу из списка выше и жмешь Create new runner.
- В поле имени вводишь
renovate-runner(можно оставить необязательное описание пустым). - Жмешь Create, и Forgejo сразу показывает страницу с готовыми UUID и секретом (сгенерированным автоматически, руками через
opensslтут ничего вводить не нужно). - Копируешь оба значения - они уходят в
config.yamlна следующем шаге, туда же, куда попали бы значения из варианта А.
Секрет показывается один раз и больше нигде не хранится в открытом виде - если закрыл страницу, не скопировав его, придется удалить эту регистрацию раннера и создать новую.
Шаг 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/nullrunner - отдельный системный пользователь, которого мы завели на предыдущем шаге (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).
Кроме правки 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 и предназначен, так что здесь он подходит без всяких оговорок:
- Заходишь в репозиторий
stilicho/youtubeпод своим обычным аккаунтом, открываешь веткуmain. - Жмешь + (или Add File → New File, в зависимости от версии интерфейса) и в поле пути сразу набираешь
.forgejo/workflows/renovate.yml- Forgejo сам создаст обе недостающие папки. - Вставляешь содержимое файла из блока выше во встроенный редактор (там же есть подсветка синтаксиса YAML и переключение в режим предпросмотра).
- Внизу страницы - “Commit Changes”, коммитишь напрямую в
main(без отдельной ветки и PR, как и в способе А).
Оба способа дают идентичный результат - разница только в инструменте.
После коммита (любым из двух способов) Forgejo сам обнаружит новый workflow - специально регистрировать или “включать” его отдельно не нужно, достаточно того, что файл лежит по правильному пути в ветке main. Проверить, что он подхватился, можно во вкладке Actions репозитория - там появится запись про renovate.yml, даже если он еще не запускался ни разу.
Тег образа renovate/renovate стоит пинить конкретной версией, а не :latest. У Renovate периодически случаются регрессии именно в работе с Forgejo/Gitea (например, ошибки схемы при организациях без email на аккаунте) - если версия внезапно “поломается”, проще откатить один тег в workflow, чем разбираться, что изменилось. Раз в 1-2 месяца проверяй, не вышло ли обновление, и поднимай версию вручную.
Шаг 7. Деплой - уже готов#
И вот здесь весь смысл всей связки: специально для Renovate в Komodo ничего настраивать не нужно, потому что деплой у нас уже был построен раньше, в статье про GitOps. Напомню механику оттуда:
- PR от Renovate смержен в
mainтого же репозиторияstilicho/youtube, который Komodo уже отслеживает. - Forgejo отправляет тот самый вебхук на пуш в
main, который был настроен на Komodo Proceduredeploy-on-push. - 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 при этом мог не открыться.
"schedule": ["every weekend"] в renovate.json ограничивает не то, когда запускается сам бот, а то, когда ему разрешено создавать PR. Если ты нажал force-run не в выходные, Renovate честно найдет обновление nginx, но вместо PR создаст (или обновит) issue «Dependency Dashboard» в репозитории - он включен по умолчанию в Renovate начиная с v26 через config:recommended, который у нас в extends. Внутри этого issue - список чекбоксов с найденными, но отложенными обновлениями:
- Открой issue «Dependency Dashboard» в репозитории.
- Отметь чекбокс у строки про обновление
nginx- это команда «создай PR прямо сейчас, игнорируя расписание». - Запусти workflow еще раз через
workflow_dispatch- только на повторном прогоне Renovate прочитает отмеченный чекбокс и реально откроет PR. Сама отметка галочки PR не создает.
2. Мерджим PR и проверяем, что стек обновился. Тот же вебхук срабатывает снова - теперь уже штатно, без ручного Deploy, потому что Komodo уже знает про demo-nginx. Komodo передеплоивает стек с новым тегом:
docker inspect --format='{{.Config.Image}}' nginxЕсли версия в выводе поменялась - вся цепочка Renovate → Forgejo → Komodo работает целиком, от обнаружения устаревшего образа до реального редеплоя, без единого ручного шага после мерджа.
Если мердж-коммит уже есть в истории репозитория (видно на странице 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 маловероятен.
Об этом - в одной из следующих статей.




