Тег latest в Docker — бомба замедленного действия. Наш Metabase упал на 3 часа из-за автообновления образа. Решение — всегда пинить конкретную версию в docker-compose.yml. Инцидент затронул дашборды клиента, а причина нашлась случайно: одно слово в конфиге.
Мы ведем аналитику для музыкального лейбла в Metabase. Дашборды, метрики артистов, финансы — все в одном месте. Инструмент, который настроили один раз и перестали о нем думать. Работало месяцами.
Утро, когда Metabase перестал отвечать
Одним утром Metabase перестал отвечать.
Сергей полез разбираться: логи чистые, конфигурация не менялась, сервер в порядке. Перезапуск контейнера, проверка базы, чтение issues на GitHub. Три часа по кругу — ни одна из очевидных причин не подтвердилась.
Пока шла диагностика, клиент не мог посмотреть аналитику по свежим релизам. Три часа даунтайма из-за причины, которая нашлась случайно.
Одно слово: latest
Docker-образ стоял на теге latest. При рестарте контейнера хостинг подтянул свежую версию автоматически. Metabase рекомендует делать бекап перед каждым обновлением — даже минорным. На форумах десятки тредов с тем же сценарием: latest подтянул новую версию, что-то сломалось.
«Они тайком в старые версии подпихивают новые фиксы — и не понимаешь, что изменилось», — Сергей после трех часов диагностики.
Попытка откатиться не помогла. Старая версия уже содержала чужие изменения. Пришлось перезагружать сервер из веб-панели хостера вручную. Не через SSH, не через Docker CLI — из веб-панели. Контейнер повис наглухо.
Цепочка выглядит нелепо: локальный кеш обновился → непредусмотренный апгрейд → потеря сервиса → аварийный ребут. Из-за одной строки в docker-compose.yml.
docker-compose.yml: до и после
Было — образ обновляется при каждом рестарте:
services:
metabase:
image: metabase/metabase:latest
ports:
- "3000:3000"Стало — версия закреплена, обновление только вручную:
services:
metabase:
image: metabase/metabase:v0.52.2
ports:
- "3000:3000"Теперь все образы закреплены
(Мы знали правило: закрепляй версии в production. Применяли для клиентских сервисов. Но к «внутреннему инструменту, который и так работает» — не применили. Оказалось, именно такие ломаются первыми. Никто не мониторит то, что «и так работает».)
Теперь все Docker-образы в наших проектах — включая внутренние — закреплены на конкретных версиях. Обновляем вручную, после проверки changelog. Скучнее. И предсказуемее.
Похожий принцип — вкладывать в контекст заранее, чтобы потом не разгребать последствия. А если вы строите оповещения, которые чинят себя сами, закрепленные версии — первый шаг к предсказуемой инфраструктуре.
Частые вопросы
Почему тег latest опасен в production?
При каждом рестарте контейнера Docker подтягивает свежий образ. Новая версия может содержать breaking changes, и вы узнаете об этом только когда сервис упадет.
Как узнать текущую версию Docker-образа?
docker inspect --format='{{.Config.Image}}' container_name покажет образ. Для Metabase — версия видна в footer интерфейса или через API /api/health.
Как автоматизировать обновление Docker-образов?
Используйте Dependabot или Renovate для отслеживания новых версий. Они создают PR с обновлением, который можно проверить перед мержем.
