Вступление: проблема обновлений ПО и мой подход к ней

Я уже несколько раз писал про обновление разнообразного ПО, которым пользуюсь. Как правило, поводом, побуждающим меня к такому творчеству - писать про обновления - являются проблемы, появляющиеся именно после каких-то обновлений. И правда, ну о чём писать, если всё работает, как часы?

Я долго пытался обезопасить себя от ломающих софт обновлений, и, в какой-то момент, подумал было, что закрыл для себя этот вопрос: перешёл на использование контейнеров docker с нужным мне ПО и контейнера же со специальным сервисом watchtower - для отслеживания появления новых версий образов этих самых контейнеров. Причём, я специально остановился на режиме работы watchtower, при котором он только присылает оповещения о вышедших новых версиях образов, не выполняя автоматического их обновления, так как прекрасно представляю себе, к чему может привести такое безответственное поведение - безоглядное автоматическое обновление... как говорится: плавали - знаем. Да, я трачу какое-то время на просмотр изменений, нововведений, требований новых версий, о которых сообщает watchtower, но, как результат (и награда) - я уверен, что у меня не будет проблем. Был уверен... моя картинка мира была разрушена - в очередной раз.

Всё началось очень обыденно и безобидно: watchtower прислал письмо со списком очередных обновлений. Были среди них и обновления образов, которые использовались для создания контейнеров, входящих в состав моего сервиса для работы с Kanban досками - wekan. Причём, обновление было как для самого сервиса, так и для используемой им БД - mongo.

Надо отметить, что для запуска сервиса wekan при помощи docker compose, авторы предлагают использовать YAML файл, специально разработанный ими для этих целей. К его разбору мы ещё вернёмся, а сейчас будет небольшое отступление - экскурс в мир docker и docker compose.

Использование тегов для версионирования образов docker

Как известно, при указании образов, из которых будут созданы контейнеры, можно задавать (а можно и не задавать) теги. Обычно, теги могут либо быть связаны с конкретными версиями ПО, либо являться специальными метками, которые авторы образа вольны использовать по своему усмотрению - например, для определения статуса образа. Примерами таких меток-тегов могут служить master, stable, dev, production, test и вообще всё, что только может прийти вам на ум[1] - фантазию никто не ограничивает. Ну и, конечно же, не будем забывать про тег latest: если пользователь явно ничего не указывает, будет использован именно этот специальный тег.

Конечно же, образы, помеченные тегами, должны присутствовать в репозитории - а для этого авторы их там должны разместить, указав (сюрприз!) те же самые теги, ну, или не указав - тогда будет использован... правильно! Тег latest.

И вот с этой специальной меткой-тегом (latest) не всё так просто. Большинство простых пользователей, и я в том числе, обычно воспринимают её, как последнюю версию образа, которую и следует использовать для создания контейнеров. С другой стороны, и это достаточно забавно, авторы образов, зачастую, и вкладывают этот смысл, публикуя самые свежие образы именно с таким тегом. Но, увы, во-первых, не все и не всегда! А во-вторых, понятие "последний образ" может нести разный смысл для автора и для пользователя. И вот тут-то и возникает вопрос - а эта последняя версия действительно отвечает самой последней версии ПО и достаточно ли она стабильна, чтобы использовать её в своём рабочем окружении?

Если обратиться к первоисточнику знаний - документации по docker, то становится ясно, что авторы этого инструмента для контейнеризации ПО, не закладывали никакого глубокого смысла, вводя тег latest в качестве тега по умолчанию. Тут, со стороны пользователей, имеет место простой и, зачастую, неправильный(!), перенос понятия "latest image/последний образ" на последнюю (самую свежую) стабильную (вероятно) версию ПО, которое упаковали в этот самый образ. Опять-таки, с достаточно большой долей вероятности будет именно так, но это - не обязательно.

На самом деле, автора образа никто не засавляет, но если он, будь то компания или энтузиаст-одиночка, явно озвучивает в документации образа свою стратегию присвоения тегов, я проникаюсь, как минимум, благодарностью - сразу становится понятно, что пользователи ему не безразличны. Ведь именно исходя из этой стратегии можно выработать свой алгоритм обновления образа. Если же автор не указал, что он понимает под теми или иными тегами, то остаётся только метод проб и ошибок. И тут, как показала жизнь, можно наткнуться на ошибку, даже спустя достаточно длительный промежуток времени после первоначальной успешной пробы.

Разбор случая с docker-compose.yml для wekan

Да, именно так и произошло в случае с обновлением контейнеров wekan. Следите, что называется, за руками.

Долгое время в файле docker-compose.yml от авторов wekan были следующие строки для сервиса mongo:

wekandb:
# ==== MONGODB AND METEOR VERSION ====
    # a) For Wekan Meteor 1.8.x version at master branch, use mongo 4.x
    # DOES NOT WORK: mongo 4.4, see https://github.com/wekan/wekan/issues/3247
    # WORKS: mongo 3.x and 4.2
    image: mongo:4.2

Ну и для самого wekan:

wekan:
#-----------------------------------------------------------------------
    # ==== MONGODB AND METEOR VERSION ====
    # a) Quay automatic builds do work work, https://quay.io/wekan/wekan
    image: quay.io/wekan/wekan
    # b) Using specific version tag:
    # image: quay.io/wekan/wekan:v4.52
    # c) Docker Hub builds do work https://hub.docker.com/r/wekanteam/wekan
    # image: wekanteam/wekan
    #-------------------------------------------------------------------

Как видим, для базы данных предлагалось использовать образ mongo версии 4.2 (определено при помощи соответствующего тега), а для самого приложения - образ wekan без какого-либо определённого тега, то есть, latest.

Спустя какое-то время авторы поменяли конфигурацию, изменив yml файл следующим образом - было:

    image: mongo:4.2

стало:

    image: mongo:latest

то есть, вместо конкретной версии mongo теперь предлагалось использовать образ, имеющий тег latest.

Наверное, к счастью для себя, я не сразу увидел, что появилась новая версия файла. Если честно, то я не всегда слежу за изменениями в авторском файле docker-compose.yml - он довольно большой, и, каюсь, мне бывает иногда лениво исследовать и анализировать изменения, и переносить (или не переносить) их в свою версию файла. Дело в том, что авторы при разработке, видимо, используют методологию Agile, из-за чего обновления "прилетают" довольно часто (я бы даже сказал, слишком часто). Из-за этого, некоторые обновления я просто игнорирую: ну в самом деле, что может отличать четыре версии, выпущенные за два дня. Понятно, что многое, но... Так что - да, глубокий анадиз я делаю не всегда, а лишь время от времени.

В общем, какое-то время назад, изучая историю изменений файла, я увидел, что авторы "мучаются" с версией (тегом) и репозиторием mongo, и, поэтому, не стал спешить с правками, тем более, что у меня и так всё работало. Потом я сделал перерыв - не следил за этим файлом, но, получив последнее оповещение об обновлении, решил, что пора, и вновь глянул на него (вернее, в него). Там я увидел, что метания авторов прекратились - теперь для образа mongo явно указан конкретный тег , а именно, 4.4. Это послужило для меня сигналом, свидетельствующим о том, что авторы проверили работоспособность своего приложения (wekan) с новой версией mongo и больше нет необходимости быть завязанным на старую версию 4.2. Поэтому предварительно, перед тем как перезапускать сервисы, я сделал соответствующие правки в своём yml файле - указал новый тег для образа mongo. Последующие события показали, что я несколько погорячился.

Последствия перехода на новый образ

Собственно, первый же запуск сервисов после правки файла docker-compose.yml, привёл к постоянной перезагрузке сервиса mongo. Если честно, я испугался - дело в том, что я проигнорировал процедуру создания резервной копии данных перед всеми этими манипуляциями, хотя, обычно, не бываю столь беспечен. Особенно меня огорчил тот факт, что сделал я это намеренно - из-за того, что менялась только минорная версия, я, почему-то, решил, что никаких изменений, ломающих совместимость, быть не должно. А собственно испуг был связан с тем, что если вдруг это моё предположение неверно, и такие изменения, всё-таки, имеют место быть, то откатиться на предыдущую версию будет ой как не просто.

К счастью, всё оказадось не столь ужасно - перезапуск с указанием старого тега (4.2) прошёл успешно, что позволило мне выдохнуть и начать разбираться с проблемой спокойно и обстоятельно.

Поиск причин проблемы

Первым делом я решил посмотреть, не было ли у кого похожих проблем. И, как водится, я в очередной раз убедился в своей неисключительности - на github был описан очень похожий случай. Я не стал детально сравнивать логи, предпочтя более простой способ - проверить, правильно ли установлен в моей базе параметр featureCompatibilityVersion. Для этого я выполнил следующие манипуляции:

  • прежде всего, сделал резервную копию своей базы
  • подключился к работающему контейнеру mongo,выполнив команду:
docker exec -it mongo-db bash
  • для проверки значения параметра выполнил следующую команду (уже будучи "внутри" контейнера):
mongo wekan --eval 'db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } );'

Как и описывалось в топике на github, в ответе я получил значение 4.0. После этого я выполнил следующую команду:

mongo wekan --eval 'db.adminCommand( { setFeatureCompatibilityVersion: "4.2" } );'

и вновь перепроверил значение нужного мне параметра (featureCompatibilityVersion) - в этот раз он был равен 4.2.

Получив этот обнадёживающий результат, я остановил сервисы, вновь отредактировал файл docker-compose.yml (указал тег 4.4 для образа mongo), и... с чуством хорошо выполненной работы, продолжил работать со своими Kanban досками после того, как docker успешно пересоздал и запустил контейнеры в ответ на команду:

docker-compose up -d

Заключение: осмысление произошедшего

Несмотря на счастливое завершение всей этой истории, у меня остались некоторые вопросы. Первый, конечно, это почему у авторов wekan не возникла та же ошибка, что и у меня? Ведь они выкатили новую версию файла docker-compose.yml не просто так - они долго боролись с какими-то проблемами и, в конце концов, победили их.

Второй вопрос, который меня интересует, связан с тем топиком, который я нашёл на github: ведь этот топик закрыт - он довольно старый и авторы по нему сделали исправления. Тогда почему эти исправления не сработали у меня? В общем, как-то это странно.

Ну и третий вопрос - так как уже имеется версия 5.0 базы данных mongo, то чего мне следует ожидать (и бояться?) при переходе wekan на неё?!

Послесловие

Кстати, есть ещё один интересный момент, который всплыл, пока я разбирался с этим случаем. В закреплённом (на момент написания статьи) топике на github встретился такой совет: не используйте образ с тегом latest. И очень простое пояснение к нему: авторы размещают в репозитории с таким тегом образ, содержащий их текущую версию приложения, а там могут быть фичи, которые ещё не доработаны до конца. Предлагается использовать теги, связанные с конкретными релизными версиями. Это как раз то, о чём я писал несколько выше. Правда, на мой взгляд, правильнее было бы давать такой совет не в топике с обсуждением проблемы, пусть и закреплённом, а в описании ПО.

Но, если честно, я, по-прежнему, сам себе злобный буратино - использую тег latest (вернее, вообще не указываю тег). Ведь если я укажу какой-то конкретный тег, например, 5.35, то я никогда не получу уведомление о выходе какой-нибудь 5.41 - watchtower будет мониторить обновление версии 5.35 - наверное, вечно. Авторы попытались ввести в обиход тег stable, но, на момент написания этого материала, что-то у них не получилось, и они не публикуют сейчас образы с таким тегом. Такая вот история.


  1. Но должно подчиняться требованиям, предъявляемым со стороны docker ↩︎