Обновление RocketChat

Сколько нужно времени, чтобы обновить RocketChat с 7 на 8 версию? Пять минут? А нет — пять дней с перерывами.

Как же так получилось? Неужели всё сломалось, гипс снимают, клиент уезжает… Ой, не та опера. Начнём издалека для тех, кто не в теме.

Преамбула

Есть такой мессенджер Ма^ RocketChat, сервер которого можно развернуть локально. Развёртывание мне проще всего проводить через docker compose. Там всего два сервиса: сам сервер и база данных. Сервер отвечает за интерфейс и хранение вложений, база данных на mongodb отвечает за хранение сообщений и настроек. Есть официальный репозиторий — https://github.com/RocketChat/Rocket.Chat в котором ведётся разработка и выкладываются релизы, почитав которые, можно быть в курсе, что вышла новая версия и какие там произошли изменения. Есть репозиторий специально для докера — https://github.com/RocketChat/Docker.Official.Image.
Обновление сервера производить проще простого: поменял тег в образе в композ файле для сервиса rocketchat, выполнил «docker compose up -d» и всё. Сервер обновился, пользователи радуются новым рюшечкам.

С базой тоже всё просто. Раньше использовалась пятая версия от bitnami (компания специализирующаяся на создании защищённых сборок программ и образов). Потом они перешли на шестую, но неудобств от перехода не было — сменил версию и автоматизация внутри сделает своё дело. Знай меняй версии на новые и горя не знай. Для удобства можно даже клонировать и обновлять репозиторий, всё автоматически обновится.

Фабула

Однако первый звоночек прозвенел в сентябре 2025 года, когда в композ файле официального образа для докера появилась строка

This compose file is deprecated, please migrate to https://github.com/RocketChat/rocketchat-compose

«Ну и отлично же», — воскликнет любимый читатель, пройдёт по ссылке, прочитает простую инструкцию, склонирует репозиторий и будет радоваться, как за него любимого и красивого всё сделали. Так-то оно так, но «есть нюанс» — у вас микросервисы в проде, и у меня микросервисы в проде…

Сделали, конечно, там немало, но и добавили много чего ещё, что лично мне нафиг не нужно, например Grafana и Prometheus. Так что я со спокойной душой взял, что нужно из композ файлов и просто обновлял версии, забив на новый репозиторий.

Второй звонок прозвучал в октябре 2025 года, когда ссылка на образ базы данных из репозитория сменилась с docker.io/bitnami/mongodb:6.0 на docker.io/bitnamilegacy/mongodb:6.0. (Здесь и далее не буду приводить ссылку с переменными, как в репозитории, для лучшей удобочитаемости). Предупреждающую надпись я увидел не сразу и смена адреса образа базы данных прошла одновременно со сменой репозитория. В общем, стало понятно, что bitnami перестали поддерживать защищённые образы и надо бы думать куда переходить в скором времени. Скорое время как обычно не наступило, все забили\забыли, пока не прозвучал колокол обновления rocketchat’а на восьмую версию.

Обновление

Итак.
Дано:
– RocketChat 7.13.1 (последняя стабильная на момент обновления версия)
– Mongodb 6.0 от bitnami
– Система контейнеризации docker с использованием compose плагина. Для удобства запуска.

Лирическая часть

На странице релиза RocketChat белым по чёрному (тёмная тема всё же) написано:

«Breaking changes
This release introduces a wide set of breaking changes focused on removing deprecated, end-of-life, and legacy functionality. Support for MongoDB 5.0 and 6.0 has been discontinued, and workspaces must upgrade to MongoDB 8.2 before moving to Rocket.Chat v8.0.0…»

«Фигня вопрос», – скажет пытливый читатель и обновит тег в образе для mongodb с 6.0 на 8.2

«Error response from daemon: manifest for bitnamilegacy/mongodb:8.2 not found», – ответит докер и не станет ничего качать.

А всё потому что bitnami, будучи купленными ещё в 2019 году VMWare, которую в 2023 году купила Broadcom, опубликовали новость, где рассказали, что ограничат бесплатный доступ к своим образам. Таким образом, разработчикам придётся или платить за использование образов ПО, либо искать альтернативы.
Вот и получается, чтобы обновить rocketchat до 8 версии, нужно сначала обновить mongodb, а у нас денег нет репозитория нет.

«Так давайте зайдём на официальный репозиторий, да увидим ссылку на новый образ», — выдвинет предположение читатель, и я с ним полностью соглашусь. В самом деле, для чего ещё эти официальные репозитории нужны?

Заходим (в начале января) туда и видим множество yml файлов с сервисами. Удобно, никаких простыней кода, всё разложено по полочкам. Но чу, что мы видим в файле compose.database.yml? Файл изменён два месяца назад и в нём тот же старый адрес старого образа от bitnami. По ссылке можно посмотреть.

«Но как же так?», — огорчится читатель, — «Неужели разработчики забыли исправить нужные теги или сами не знают где брать новый образ». Получается, что так и есть.

Но давайте любопытства ради, а не злорадства для, зайдём на старый репозиторий, в котором всё так же написано, что этот репозиторий устарел, используйте вон тот новый (и будет вам счастье). Там наверное и коммитов не будет? Ага, щас. Репозиторий цветёт и пахнет, а в compose.yml указан адрес mongodb/mongodb-community-server:8.2-ubi8

И вот как вот в таком случае верить написанному? Как доверять разработчикам, которые «лучше знают». «А вот никак, бардак там, причём полный», — подумал я, и внёс в свой композ файл необходимый адрес.

И тут новая база подкинула сюрприз. И не один, а целых… много.

  • Первый. В образе от bitnami владелец файлов, он же пользователь внутри контейнера имел id 1001, а в образе от community версии владелец уже с id 998.
  • Второй. Поменялся внутренний путь к файлам. Раньше он был /bitnami/mongodb, а стал /data/db.
  • Третий. Раньше база инициализировалась с опцией «MONGODB_REPLICA_SET_MODE: primary», что означало создание кластера из нескольких нод, теперь этой опции нет, mongo стартует как одиночный сервер. В этом коммите ясно видно удаление этих опций.
  • Четвёртый. Так как новый образ не от bitnami, то при старте необходимо проинициализировать сервер для репликации вручную, а не передаваемыми переменными, которые раньше были встроены в старый образ Делается добавлением в композ файл entrypoint с командами инициализации.

Так что каждый раз при тестировании и попытках миграции, необходимо было остановить контейнер с базой, сменить на хосте владельца файлов, отредактировать композ файл и запустить контейнер с новой базой

Дальше были попытки нахрапом взять эту крепость запустить новую базу на основе старой. Было замечено следующее:
— запуск 7-й версии mongodb от Bitnami успешен c 6-й.
— запуск 8-й версии от bitnami (устаревшей, но тем не менее существующей) закончился неудачей при миграции с 7-й
— то же самое наблюдалось при использовании 8-й версии rocketchat’а. Версия rocketchat’а в общем-то не играет роли, главное — мигрировать базу, а с 7-й на 8-ую версию она просто так не мигрирует.

Значит надо делать бэкап текущей базы (можно даже 6-й версии) и восстанавливать на новую базу. При этом надо указать в проброшенных в контейнер volumes новое место, чтобы база 8-й версии проинициализировалась и на неё уже накатить бэкап.

Бэкап в mongodb делается просто.

docker compose exec mongodb mongodump --gzip -d rocketchat --archive=/bitnami/mongodb/backup-rchat.gz

, где
mongodb — имя сервиса в композ файле;
-d rocketchat — имя базы данных;
archive= — расположение создаваемого архива. Путь указан в volumes композ файла

Теперь останавливаем контейнер, указываем в композ файле новые данные для образа БД и новые данные. Запускаем контейнер, ждём инициализации новой базы, а затем импортируем из бэкапа:

docker compose exec mongodb mongorestore --gzip --drop --archive=/data/db/backup-rchat.gz

Теперь можно запустить rocketchat новой версии и убедиться, что всё заработало.

Техническая часть

Теперь по шагам опишу, как корректно выполнить обновление.

Вот изначальные файлы сервисов:

volumes:
  mongodb_data: { driver: local }

services:
  rocketchat:
    image: ${IMAGE:-registry.rocket.chat/rocketchat/rocket.chat}:${RELEASE:-latest}
    restart: always
    labels:
      traefik.enable: "true"
      traefik.http.routers.rocketchat.rule: Host(`${DOMAIN:-}`)
      traefik.http.routers.rocketchat.tls: "true"
      traefik.http.routers.rocketchat.entrypoints: https
      traefik.http.routers.rocketchat.tls.certresolver: le
    environment:
      MONGO_URL: "${MONGO_URL:-\
        mongodb://${MONGODB_ADVERTISED_HOSTNAME:-mongodb}:${MONGODB_INITIAL_PRIMARY_PORT_NUMBER:-27017}/\
        ${MONGODB_DATABASE:-rocketchat}?replicaSet=${MONGODB_REPLICA_SET_NAME:-rs0}}"
      MONGO_OPLOG_URL: "${MONGO_OPLOG_URL:\
        -mongodb://${MONGODB_ADVERTISED_HOSTNAME:-mongodb}:${MONGODB_INITIAL_PRIMARY_PORT_NUMBER:-27017}/\
        local?replicaSet=${MONGODB_REPLICA_SET_NAME:-rs0}}"
      ROOT_URL: ${ROOT_URL:-http://localhost:${HOST_PORT:-3000}}
      PORT: ${PORT:-3000}
      DEPLOY_METHOD: docker
      DEPLOY_PLATFORM: ${DEPLOY_PLATFORM:-}
      REG_TOKEN: ${REG_TOKEN:-}
    depends_on:
      - mongodb
    expose:
      - ${PORT:-3000}
    ports:
      - "${BIND_IP:-0.0.0.0}:${HOST_PORT:-3000}:${PORT:-3000}"

  mongodb:
    image: docker.io/bitnamilegacy/mongodb:${MONGODB_VERSION:-6.0}
    restart: always
    volumes:
      - ${MONGODB_HOST_PATH:-mongodb_data}:/bitnami/mongodb
    environment:
      MONGODB_REPLICA_SET_MODE: primary
      MONGODB_REPLICA_SET_NAME: ${MONGODB_REPLICA_SET_NAME:-rs0}
      MONGODB_PORT_NUMBER: ${MONGODB_PORT_NUMBER:-27017}
      MONGODB_INITIAL_PRIMARY_HOST: ${MONGODB_INITIAL_PRIMARY_HOST:-mongodb}
      MONGODB_INITIAL_PRIMARY_PORT_NUMBER: ${MONGODB_INITIAL_PRIMARY_PORT_NUMBER:-27017}
      MONGODB_ADVERTISED_HOSTNAME: ${MONGODB_ADVERTISED_HOSTNAME:-mongodb}
      MONGODB_ENABLE_JOURNAL: ${MONGODB_ENABLE_JOURNAL:-true}
      ALLOW_EMPTY_PASSWORD: ${ALLOW_EMPTY_PASSWORD:-yes}

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

RELEASE=7.13.1
MONGODB_VERSION=6.0
MONGODB_HOST_PATH=/mnt/rocketchat/mongodb

Сначала останавливаем rocketchat, чтобы никаких изменений в базу не было внесено.

docker compose stop rocketchat

Делаем дамп БД

docker compose exec mongodb mongodump --gzip -d rocketchat --archive=/bitnami/mongodb/backup-rchat.gz

Останавливаем всё

docker compose down

Меняем владельца файлов

chown -R 998:998 /mnt/rocketchat/mongodb

Меняем содержимое композ файла на новое (выделил жирным)

volumes:
  mongodb_data: { driver: local }

services:
  rocketchat:
    image: ${IMAGE:-registry.rocket.chat/rocketchat/rocket.chat}:${RELEASE:-latest}
    restart: always
    labels:
      traefik.enable: "true"
      traefik.http.routers.rocketchat.rule: Host(`${DOMAIN:-}`)
      traefik.http.routers.rocketchat.tls: "true"
      traefik.http.routers.rocketchat.entrypoints: https
      traefik.http.routers.rocketchat.tls.certresolver: le
    environment:
      MONGO_URL: mongodb://mongodb:27017/rocketchat?replicaSet=rs0
      ROOT_URL: ${ROOT_URL:-http://localhost:3000}
      PORT: ${PORT:-3000}
      DEPLOY_METHOD: docker
      DEPLOY_PLATFORM: ${DEPLOY_PLATFORM:-}
      REG_TOKEN: ${REG_TOKEN:-}
    depends_on:
      - mongodb
    expose:
      - ${PORT:-3000}
    ports:
      - "${BIND_IP:-0.0.0.0}:${HOST_PORT:-3000}:${PORT:-3000}"

  mongodb:
    image: mongodb/mongodb-community-server:${MONGODB_VERSION:-8.2}-ubi8
    restart: on-failure
    volumes:
      - ${MONGODB_HOST_PATH:-mongodb_data}:/data/db
    environment:
      MONGODB_REPLICA_SET_NAME: ${MONGODB_REPLICA_SET_NAME:-rs0}
      MONGODB_PORT_NUMBER: ${MONGODB_PORT_NUMBER:-27017}
      MONGODB_INITIAL_PRIMARY_HOST: ${MONGODB_INITIAL_PRIMARY_HOST:-mongodb}
    entrypoint: |
      bash -c
        "mongod --replSet $$MONGODB_REPLICA_SET_NAME --bind_ip_all &
          sleep 2;
          until mongosh --eval \"db.adminCommand('ping')\"; do
            echo '=====> Waiting for Mongo...';
            sleep 1;
          done;
          echo \"=====> Initiating ReplSet $$MONGODB_REPLICA_SET_NAME at $$MONGODB_INITIAL_PRIMARY_HOST:$$MONGODB_PORT_NUMBER...\";
          mongosh --eval \"rs.initiate({_id: '$$MONGODB_REPLICA_SET_NAME', members: [{ _id: 0, host: '$$MONGODB_INITIAL_PRIMARY_HOST:$$MONGODB_PORT_NUMBER' }]})\";
          echo '=====> Initiating ReplSet done...';
        wait"

Меняем содержимое файла .env

RELEASE=8.0.1
MONGODB_VERSION=8.2
MONGODB_HOST_PATH=/mnt/rocketchat/mongodb

Запускаем только базу данных

docker compose up mongodb -d

Ждём запуска и инициализации и заливаем бэкап

docker compose exec mongodb mongorestore --gzip --drop --archive=/data/db/backup-rchat.gz

Запускаем rocketchat

docker compose up -d

PROFIT

Эпилог

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

В 8-й версии rocketchat как обычно убрали старые баги, добавили новые, поменяли интерфейс и сделали всё, чтобы пользователи привыкали к новому, а иначе мозг застаивается и костенеет.

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

И неужели нельзя было сначала подготовить репозиторий с уже внедрённым способом автоматического обновления, чем вот так вот гнать пользователей\админов на новый репозиторий, при этом не ведя там никакой работы. Бардак. И людей мало. Opensource же.

Подписаться
Уведомить о
guest

0 комментариев
Новые
Старые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии