Skip to content

fix(panel): Update закрепляет образ панели по digest, а не по плавающему тегу - #128

Merged
agentHits merged 1 commit into
AgentHits-Devfrom
fix/update-pin-image-digest
Oct 29, 2026
Merged

agentHits merged 1 commit into
AgentHits-Devfrom
fix/update-pin-image-digest

Conversation

@agentHits

@agentHits agentHits commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Зачем

Панель сама переходила на свежую невыпущенную сборку agenthits-dev. Последний раз это случилось 2026-10-29 в 12:19 UTC: панель перешла с agenthits-v1.0.9 на agenthits-dev. Первую причину чинит #127: Server → Reload запускал команду обновления. Этот PR убирает вторую причину.

Команда Update записывала в сервис dokploy плавающий тег ghcr.io/agenthits/dokploy:agenthits-dev без digest. Swarm заново скачивает образ по тегу при каждом старте задачи. Поэтому любой перезапуск задачи панели мог молча поднять более новую сборку: падение контейнера, healthcheck, перезагрузка сервера, рестарт Docker.

Что изменилось

  • После docker pull скрипт обновления читает RepoDigests скачанного образа. Он берёт digest того же репозитория и запускает docker service update --no-resolve-image --image <репозиторий>:<тег>@sha256:…. Если образ уже есть на сервере, swarm его не скачивает. Если образа нет, swarm скачивает ровно эту сборку, а не то, на что тег указывает сейчас.
  • Если digest этого репозитория не нашёлся (например, образ собран на сервере), в сервис записывается ID образа, как в Reload из fix(panel): hang up container terminal shells on close, keep Reload on the running build #127. Если после pull не нашёлся и сам образ, скрипт завершается с ошибкой и сервис не трогает. Плавающий тег как запасной вариант не используется.
  • Официальный канал (getOfficialUpdateCommand) работает так же. Причина: теги версий v0.x.y на Docker Hub не меняются, но в эту же команду попадают canary и feature, а это плавающие теги. Проверка обновлений для canary/feature сравнивает digest из spec сервиса с digest тега на Docker Hub. Для версии закрепление ничего не меняет: digest указывает на ту же сборку, что и тег.
  • Без изменений:
    • маркер [dokploy-update] image pulled сразу после pull;
    • запись DOKPLOY_PREVIOUS_IMAGE;
    • переменные RELEASE_TAG, DOKPLOY_OFFICIAL_VERSION, DOKPLOY_FORK_VERSION, DOKPLOY_KEEP_OLD_IMAGES;
    • --update-order stop-first и --update-failure-action rollback.
  • Проверка обновлений тоже не менялась. getServiceImageDigest и раньше брал digest из <образ>@sha256:…, а getAgentHitsUpdateData сравнивает его с digest тега в GHCR. Сборка agenthits публикуется одним манифестом amd64 без index. Поэтому digest в RepoDigests совпадает с digest тега, и после обновления панель не предлагает ту же сборку снова. Это проверяет тест. После fallback на ID образа digest-проверка молчит, и обновление определяется по версиям из метаданных образа, как раньше при spec без digest.

Связь с #127

Продолжение #127 (уже влит): там то же закрепление по digest сделано для Server → Reload. Ветка перенесена на AgentHits-Dev после его мержа, в diff только изменения этого PR.

Проверки

  • bunx vitest run --config __test__/vitest.config.ts в apps/dokploy: 4343 теста прошли. 5 тестов в vector-validate.test.ts падают локально и без этого PR (на ветке fix(panel): hang up container terminal shells on close, keep Reload on the running build #127 до мержа): они запускают настоящий docker run с образом Vector, и на macOS он не проходит.
  • tsc --noEmit в apps/dokploy и packages/server: без ошибок.
  • biome check по изменённым файлам: без замечаний.
  • Новые тесты в dokploy-image-cleanup.test.ts прогоняют сгенерированный скрипт в sh с фейковым docker в PATH:
    • digest найден: AgentHits пишет в сервис ghcr.io/agenthits/dokploy:agenthits-dev@sha256:… со всеми прежними флагами и переменными; официальный canary пишет dokploy/dokploy:canary@sha256:…. Digest другого репозитория, если он тоже есть у образа, пропускается;
    • digest не найден: в сервис пишется ID образа;
    • pull упал: маркера нет, кроме pull ничего не вызывается;
    • образ не найден после pull: скрипт завершается с ошибкой, docker service update не вызывается;
    • после такого обновления getAgentHitsUpdateData не предлагает ту же сборку, а более новую предлагает.
  • На локальном Docker 29 проверено, что RepoDigests выглядят как <репозиторий>@sha256:… и что ссылка <репозиторий>:<тег>@sha256:… находит образ, уже лежащий на машине.

Что проверить вручную на dev

  1. До обновления посмотреть образ в spec: docker service inspect dokploy --format '{{.Spec.TaskTemplate.ContainerSpec.Image}}'. Сейчас там тег без @sha256.
  2. Перед первым Update после этого PR нажать Server → Reload из fix(panel): hang up container terminal shells on close, keep Reload on the running build #127. Reload закрепит текущую сборку по digest, и если Update не пройдёт, swarm откатится на закреплённую сборку. Без этого шага откат вернёт spec с плавающим тегом, и swarm скачает по нему ту же новую сборку.
  3. Обновить панель через Update. В spec должен оказаться ghcr.io/agenthits/dokploy:agenthits-dev@sha256:…, и этот digest должен совпадать с docker image inspect --format '{{index .RepoDigests 0}}' образа работающего контейнера.
  4. Проверить обновления в настройках веб-сервера: панель не должна предлагать ту же сборку.
  5. После следующей сборки agenthits-dev перезапустить задачу панели (docker kill контейнера панели или docker service update --force dokploy). Панель должна подняться на прежней сборке: docker inspect --format '{{.Image}}' нового контейнера не меняется. При этом проверка обновлений должна показать новую сборку.

Риск: старые сборки agenthits-dev без тега еженедельно удаляются из GHCR. Пока образ лежит на сервере, swarm реестр не нужен, а очистка образов никогда не удаляет работающую и предыдущую сборки. Если такой образ удалить с сервера вручную, задача панели не поднимется, пока не сделать Update.

🤖 Generated with Claude Code

@agentHits
agentHits force-pushed the fix/update-pin-image-digest branch from 2ef600e to 3f4c94f Compare October 29, 2026 15:05
…ему тегу

Команда Update записывала в сервис dokploy плавающий тег
ghcr.io/agenthits/dokploy:agenthits-dev без digest. Swarm заново
скачивает образ по тегу при каждом старте задачи, поэтому падение
контейнера, healthcheck, перезагрузка сервера или рестарт Docker могли
молча поднять более новую сборку.

Теперь после docker pull скрипт читает RepoDigests скачанного образа,
берёт digest того же репозитория и запускает docker service update
--no-resolve-image --image <репозиторий>:<тег>@sha256:…. Swarm не
скачивает образ по digest, если он уже есть на сервере, а если его нет,
скачивает ровно эту сборку. Без digest этого репозитория в сервис
пишется ID образа, как в Reload. Если после pull не нашёлся и сам образ,
скрипт завершается с ошибкой и сервис не трогает.

Официальный канал работает так же: в ту же команду попадают canary и
feature, а это плавающие теги. Для тегов версий закрепление ничего не
меняет.

Маркер после pull, DOKPLOY_PREVIOUS_IMAGE, RELEASE_TAG,
DOKPLOY_OFFICIAL_VERSION, DOKPLOY_FORK_VERSION, DOKPLOY_KEEP_OLD_IMAGES,
stop-first и rollback остались прежними. Проверка обновлений уже брала
digest из <образ>@sha256:…, и тест подтверждает, что после обновления
панель не предлагает ту же сборку снова.

Продолжает #127: там то же закрепление сделано для Server → Reload.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@agentHits
agentHits force-pushed the fix/update-pin-image-digest branch from 3f4c94f to 4715972 Compare October 29, 2026 15:05
@agentHits
agentHits merged commit c28d5b7 into AgentHits-Dev Oct 29, 2026
7 checks passed
@agentHits
agentHits deleted the fix/update-pin-image-digest branch October 29, 2026 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant