Устранение ошибки MongoDB 22988 в Docker-инфраструктуре Rocket.Chat

Практическое руководство по восстановлению работоспособности базы данных WiredTiger при конфликтах конфигурации в контейнеризированной среде. Курс предлагает последовательный алгоритм от диагностики причин сбоя до полного перезапуска связки сервисов.

1. Природа ошибки 22988 в MongoDB: причины несовместимости параметров WiredTiger

Природа ошибки 22988 в MongoDB: причины несовместимости параметров WiredTiger

Представьте ситуацию: вы обновляете Docker-контейнеры Rocket.Chat, ожидая новых функций, но вместо экрана входа видите бесконечную загрузку, а в логах базы данных мелькает загадочное сообщение: BadValue: WiredTiger error (-22988). Эта цифра — не просто порядковый номер сбоя, а сигнал о том, что база данных внезапно «забыла», как читать собственные файлы на диске.

Что скрывается за кодом 22988

Ошибка 22988 в MongoDB напрямую связана с движком хранения WiredTiger. Это основной механизм, который отвечает за то, как данные записываются в файлы, сжимаются и кэшируются. Когда MongoDB запускается, она сверяет текущие параметры конфигурации с теми метаданными, которые уже записаны в файлах данных (обычно в файле WiredTiger.turtle или WiredTiger).

> Ошибка 22988 (WiredTiger Error) — это состояние «несоответствия конфигурации», при котором параметры инициализации движка в текущей сессии противоречат параметрам, с которыми база была создана или запущена в последний раз. > > MongoDB Documentation

В контексте Docker и Rocket.Chat это означает, что контейнер с новой версией MongoDB пытается открыть «старую» папку с данными, используя настройки, которые движок считает недопустимыми или конфликтующими.

Почему это происходит в Docker-инфраструктуре

В изолированной среде Docker проблема редко возникает «сама по себе». Как правило, она становится следствием одного из трех сценариев, представленных в таблице ниже:

| Причина | Механизм возникновения | | :--- | :--- | | Скачок версии | Вы обновили образ MongoDB (например, с 4.4 до 5.0), минуя промежуточные этапы, и формат метаданных WiredTiger изменился. | | Смена параметров сжатия | В новой версии образа по умолчанию включен другой алгоритм (например, zstd вместо snappy), который несовместим с текущими файлами. | | Конфликт mmapv1 | Попытка запустить современные версии MongoDB на данных, которые когда-то были созданы очень старым движком mmapv1. |

Самая частая причина для администраторов Rocket.Chat — это автоматическое обновление через тег :latest в Docker Compose. Если вчера ваша база работала на версии 4.0, а сегодня Docker подтянул версию 6.0, движок WiredTiger заблокирует запуск, чтобы предотвратить необратимую порчу данных.

Конфликт параметров WiredTiger

Ключевой конфликт при ошибке 22988 часто кроется в строке конфигурации storage.wiredTiger.engineConfig.configString. В этой строке зашифрованы параметры создания системных таблиц.

Если вы попытаетесь изменить, например, размер внутренней страницы памяти или метод логирования в конфигурационном файле (или через флаги запуска контейнера), WiredTiger обнаружит, что эти значения отличаются от тех, что жестко зашиты в заголовках файлов .wt в вашем Docker Volume.

Результат всегда один:

  • MongoDB видит несоответствие.
  • Выбрасывает исключение -22988.
  • Контейнер переходит в статус Exited (14) или бесконечный Restarting.
  • Взаимосвязь с Rocket.Chat

    Для работы Rocket.Chat критически важна стабильность Replica Set (набора реплик) MongoDB. Даже если у вас всего один узел базы, он инициализируется как реплика. Ошибка 22988 разрывает эту цепочку: база не может стартовать -> Replica Set не инициализируется -> Rocket.Chat не может подключиться и падает с ошибкой Selection timeout.

    Проблема усугубляется тем, что данные находятся внутри Docker Volume. Мы не можем просто «подправить» файл внутри упавшего контейнера, так как он постоянно перезапускается. В следующих разделах мы разберем, как «подступиться» к этим данным и заставить WiredTiger снова их принять.

    2. Диагностика состояния контейнеров и структуры томов данных через Docker CLI

    Диагностика состояния контейнеров и структуры томов данных через Docker CLI

    Знаете ли вы, что контейнер, который выглядит «запущенным» в выводе docker ps, может находиться в бесконечном цикле перезагрузки, так и не добравшись до стадии готовности принимать подключения? В контексте ошибки 22988 это критический момент: Rocket.Chat будет бесконечно ждать базу данных, а MongoDB — пытаться инициализировать WiredTiger и падать. Чтобы не гадать, нужно научиться «смотреть сквозь» абстракцию Docker.

    Статус-контроль: поиск «петли перезагрузки»

    Когда инфраструктура Rocket.Chat дает сбой, первым делом необходимо определить текущее состояние системы. Если вы используете Docker Compose, стандартная команда docker ps покажет список контейнеров, но нас интересует столбец STATUS.

    > Если контейнер показывает статус Restarting (1) 5 seconds ago, это явный признак Critical Failure. Движок Docker видит, что процесс внутри завершился с ошибкой, и пытается поднять его снова согласно политике restart: always. > > Docker Documentation

    Для получения детальной картины используйте фильтрацию:

    Если вы видите, что контейнер mongodb постоянно перезагружается, а rocketchat находится в статусе Created или Exited, значит, проблема локализована в слое базы данных.

    Глубокий анализ логов через Docker и Journalctl

    Ошибка 22988 коварна тем, что она происходит на этапе инициализации движка хранения. Чтобы подтвердить её наличие, нам нужно извлечь последние записи из стандартного потока вывода контейнера.

  • Просмотр последних логов:
  • docker logs --tail 50 mongodb — покажет последние 50 строк. Ищите строку, содержащую WiredTiger error (-22988).
  • Мониторинг в реальном времени:
  • docker logs -f mongodb — позволит увидеть момент падения при следующей попытке перезапуска.

    В некоторых случаях, если демон Docker сам испытывает трудности с записью логов, стоит обратиться к системному журналу:

    Здесь можно обнаружить ошибки монтирования томов или нехватку прав доступа на уровне хостовой операционной системы, что также может косвенно влиять на работу WiredTiger.

    Инспекция томов: где физически лежат данные?

    Поскольку ошибка 22988 связана с файлами внутри БД, нам нужно точно знать, где Docker хранит эти данные на диске сервера. Контейнеры эфемерны, но Docker Volume — это конкретная директория на вашей файловой системе.

    Чтобы найти путь к данным, используйте команду inspect:

    В выводе вы увидите структуру:

    | Ключ | Значение | Описание | | :--- | :--- | :--- | | Source | /var/lib/docker/volumes/db_data/_data | Путь на хостовой машине (где лежат файлы) | | Destination | /data/db | Путь внутри контейнера | | Type | volume или bind | Способ проброса данных |

    Сравнение этих путей жизненно важно. Если Source указывает на несуществующую директорию или на раздел с заполненным дисковым пространством (), MongoDB не сможет корректно обновить файлы метаданных WiredTiger, что и провоцирует ошибки несовместимости.

    Проверка целостности структуры тома

    Прежде чем переходить к исправлению файлов (что мы сделаем в следующих главах), нужно убедиться, что файлы вообще доступны для чтения. Перейдите в директорию, указанную в Source, и проверьте наличие ключевых объектов:

  • WiredTiger.turtle — файл метаданных (главный подозреваемый).
  • WiredTiger — основной файл состояния движка.
  • storage.bson — конфигурация параметров хранения.
  • Если эти файлы имеют нулевой размер или принадлежат пользователю root (в то время как MongoDB в контейнере часто запускается от пользователя с UID 999), это подтверждает необходимость вмешательства в структуру прав доступа и конфигурацию, к чему мы подготовимся на следующем этапе.

    3. Методы обеспечения прямого доступа к данным внутри изолированного Docker-контейнера

    Методы обеспечения прямого доступа к данным внутри изолированного Docker-контейнера

    Представьте ситуацию: ваш контейнер с MongoDB находится в бесконечном цикле перезагрузки из-за ошибки 22988, и у вас есть всего несколько секунд, чтобы «запрыгнуть» внутрь через docker exec, прежде чем он снова упадет. Это классическая ловушка изоляции Docker — как починить деталь внутри запертого сейфа, который постоянно взрывается?

    Стратегия «Хирургического вмешательства»

    Когда стандартный метод docker exec не работает из-за нестабильности процесса, у системного администратора остаются два пути: работа с данными напрямую через хост-систему или запуск временного «контейнера-спасателя».

    > Изоляция Docker — это не физическая преграда, а логическое ограничение пространства имен (namespaces). Данные всегда лежат на диске хоста, если только вы не используете экзотические драйверы хранилища.

    Способ 1: Прямой доступ через файловую систему хоста

    Если вы используете именованные тома (Named Volumes), Docker хранит их содержимое в стандартной директории. Это самый быстрый способ получить доступ к файлам WiredTiger без запуска каких-либо контейнеров.

  • Остановка инфраструктуры. Перед любыми манипуляциями с файлами БД необходимо полностью остановить сервис, чтобы избежать повреждения таблиц: docker-compose stop mongodb.
  • Переход в директорию данных. Используя путь, найденный нами в прошлой главе через docker inspect, мы переходим в корень данных.
  • * Типовой путь: /var/lib/docker/volumes/rocket_chat_db_data/_data/
  • Работа с правами. Главная сложность здесь — разница в пользователях. Внутри контейнера MongoDB часто работает от пользователя с UID 999, которого может не существовать на вашей основной машине.
  • Способ 2: Контейнер-посредник (Sidecar Container)

    Если прямой доступ к /var/lib/docker ограничен (например, в управляемых средах или из соображений безопасности), используется метод запуска легкого вспомогательного контейнера, который монтирует тот же том.

    | Характеристика | Прямой доступ (Хост) | Контейнер-посредник (Alpine/BusyBox) | | :--- | :--- | :--- | | Сложность | Низкая (нужны root-права) | Средняя (нужна команда запуска) | | Безопасность | Риск изменения прав файлов | Изолированная среда прав внутри Docker | | Инструментарий | Весь софт хоста (nano, vim, sed) | Только то, что есть в образе (обычно vi) |

    Пример команды для запуска «спасателя»: docker run --rm -it -v rocket_chat_db_data:/data alpine sh

    Здесь ключ -v подключает ваш проблемный том в папку /data внутри временного контейнера Alpine. Флаг --rm автоматически удалит этот контейнер после того, как вы закончите работу.

    Проблема «Мертвых» путей

    Часто новички пытаются использовать docker cp для исправления конфигурации. Однако в случае ошибки 22988 нам нужно не просто заменить файл, а убедиться в его корректном считывании движком WiredTiger.

    Где: * — итоговая доступность данных (Permission); * — физическая связь тома (Source/Destination); * — права доступа (Access/UID).

    Если (права доступа) настроены неверно, даже при наличии физического доступа () база данных не запустится, выдав ошибку доступа к WiredTiger.lock. Поэтому метод контейнера-посредника предпочтительнее: он позволяет видеть файлы именно так, как их видит основная служба MongoDB.

    Подготовка к редактированию

    Для исправления ошибки 22988 нам потребуется доступ к двум критическим файлам в корне данных:

  • WiredTiger.turtle — текстовый файл метаданных.
  • storage.bson — бинарный файл параметров хранилища.
  • Доступ обеспечен, если вы можете выполнить команду ls -l внутри тома и увидеть список файлов, начинающихся на WiredTiger.... Если список пуст — вы примонтировали не тот том или ошиблись в пути Source.

    4. Исправление конфигурации хранилища и параметров инициализации движка базы данных

    Исправление конфигурации хранилища и параметров инициализации движка базы данных

    Представьте, что вы пытаетесь завести двигатель автомобиля, но бортовой компьютер блокирует запуск, потому что «помнит» старые настройки впрыска, не подходящие для нового топлива. Ошибка 22988 в MongoDB — это именно такой программный ступор: движок WiredTiger видит несоответствие между метаданными на диске и параметрами, с которыми запускается контейнер. Чтобы «разблокировать» систему, нам придется вручную вмешаться в файлы конфигурации хранилища.

    Почему нельзя просто сбросить конфиг?

    В Docker-инфраструктуре Rocket.Chat параметры MongoDB часто передаются через переменные окружения или аргументы командной строки в docker-compose.yml. Однако WiredTiger при первом запуске создает «слепок» этих настроек в файлах метаданных.

    > Если вы изменили версию образа или параметры репликации, но оставили старый Volume, возникает конфликт: параметры в файлах данных на диске имеют приоритет над новыми настройками запуска, что и вызывает сбой.

    Основная сложность заключается в том, что эти файлы бинарные или жестко структурированные. Мы сосредоточимся на двух критических точках: WiredTiger.turtle и storage.bson.

    Редактирование параметров через временный контейнер

    Поскольку основной контейнер MongoDB находится в цикле перезагрузки, мы используем метод Sidecar-контейнера, изученный в предыдущей главе. Нам нужно получить доступ к текстовым метаданным WiredTiger.

    Шаг 1: Подготовка конфигурации

    Запустите временный контейнер, примонтировав к нему том с данными MongoDB (например, mongodb_data):

    Шаг 2: Работа с WiredTiger.turtle

    Этот файл содержит версию движка и базовые параметры инициализации. Ошибка 22988 часто лечится приведением версии или параметров конфигурации в соответствие с текущим бинарным файлом MongoDB.

  • Перейдите в директорию данных: cd /data/db.
  • Просмотрите содержимое: cat WiredTiger.turtle.
  • Найдите строку конфигурации, которая обычно начинается с content0=....
  • Если вы откатывали версию MongoDB или, наоборот, обновляли её, параметры в этой строке могут содержать несовместимые флаги (например, специфические настройки сжатия zstd против snappy).

    Шаг 3: Очистка кэша метаданных

    В некоторых случаях радикальным, но действенным методом является удаление файла WiredTiger.lock, который может блокировать доступ, и проверка файла storage.bson.

    | Файл | Роль в ошибке 22988 | Действие | | :--- | :--- | :--- | | WiredTiger.turtle | Хранит метаданные о версии и параметрах движка. | Проверка на соответствие версии образа. | | storage.bson | Бинарный файл с настройками хранилища MongoDB. | Удаление (с осторожностью) для пересоздания при запуске. | | WiredTiger.lock | Файл блокировки процесса. | Удаление, если контейнер упал аварийно. |

    Синхронизация с docker-compose.yml

    После того как мы «подчистили» файлы внутри тома, необходимо убедиться, что параметры запуска в вашем YAML-файле не провоцируют конфликт заново.

    Чаще всего ошибка 22988 возникает из-за параметра --oplogSize. Если в старой базе он был равен 1024, а в новом конфиге вы указали 2048, WiredTiger может выдать ошибку несовместимости.

    Где — параметры в WiredTiger.turtle, а — аргументы запуска в Docker.

    Чтобы исправить это:

  • Приведите параметры в docker-compose.yml к тем, что были при создании базы.
  • Либо удалите WiredTiger.turtle (только если у вас есть бэкап!), чтобы MongoDB попыталась пересоздать его на основе новых параметров (это работает не всегда и зависит от версии).
  • Риски и предостережения

    Манипуляции с файлами движка WiredTiger — это «хирургическая» операция.

  • Никогда не редактируйте файлы .wt (индексы и коллекции) напрямую.
  • Перед любым изменением WiredTiger.turtle делайте его копию: cp WiredTiger.turtle WiredTiger.turtle.bak.
  • Если после правки метаданных ошибка сменилась с 22988 на ошибку прав доступа (Permission Denied), значит, мы успешно прошли этап инициализации движка, но столкнулись с системными ограничениями Linux, что мы и разберем в следующей главе.

    5. Восстановление корректных прав доступа и владельцев файлов внутри тома MongoDB

    Восстановление корректных прав доступа и владельцев файлов внутри тома MongoDB

    Вы отредактировали конфигурационные файлы, удалили лишние блокировки и подготовили базу к запуску. Но при попытке старта MongoDB снова «падает» с ошибкой Permission denied. Почему? В Docker-среде файлы внутри тома принадлежат конкретному пользователю с определенным UID, и если вы правили их от лица root через Sidecar-контейнер или напрямую с хоста, права доступа неминуемо сбились. Без их восстановления демон mongod просто не сможет прочитать собственные данные.

    Ловушка UID: почему права доступа ломаются

    В Linux права доступа привязаны не к именам пользователей (например, mongodb), а к их цифровым идентификаторам — UID (User ID). В официальном образе MongoDB процесс базы данных обычно запускается от пользователя с UID 999.

    Когда вы подключаете том к временному контейнеру (например, Alpine) или заходите в директорию /var/lib/docker/volumes/ на хост-системе, любое создание или сохранение файла под учетной записью суперпользователя присваивает файлу UID 0 (root).

    > Если процесс внутри контейнера имеет UID 999, а файл на диске принадлежит UID 0 и имеет права -rw-------, база данных не сможет даже инициализировать движок WiredTiger, что приведет к новой критической ошибке.

    Сравнение состояний прав доступа

    | Состояние | Владелец (UID) | Результат запуска | | :--- | :--- | :--- | | Корректное | 999 (mongodb) | Контейнер успешно считывает WiredTiger.turtle и стартует. | | После правки | 0 (root) | Ошибка EACCES: permission denied в логах Docker. | | Смешанное | 999 и 0 | База запускается, но падает при попытке записи в логи или файлы данных. |

    Исправление владельца через временный контейнер

    Самый надежный способ вернуть права — использовать тот же механизм Sidecar-контейнера, который мы применяли для редактирования файлов. Нам нужно рекурсивно изменить владельца всей директории данных.

    Для этого выполните команду:

    Здесь мы используем утилиту chown с флагом -R (рекурсивно), чтобы применить изменения ко всем вложенным папкам и файлам, включая скрытые метаданные WiredTiger.

    Проверка маски прав (Permissions)

    Помимо владельца, важно убедиться, что файлы имеют корректные биты доступа. Обычно для директорий это 755 (rwxr-xr-x), а для файлов — 644 (rw-r--r--) или 600.

    Если вы подозреваете, что маски прав также были нарушены, можно выполнить комплексную очистку прав в том же временном контейнере:

  • Установка владельца: chown -R 999:999 /data/db
  • Установка прав на папки: find /data/db -type d -exec chmod 755 {} +
  • Установка прав на файлы: find /data/db -type f -exec chmod 644 {} +
  • Нюанс с именованными томами и локальными папками

    Если в вашем docker-compose.yml используется не именованный том (rocket_chat_db_data), а проброс локальной папки (bind mount), например ./data/db:/data/db, вы можете исправить права прямо на хост-машине. Однако помните: на хосте пользователя с UID 999 может не существовать в файле /etc/passwd, поэтому команда будет выглядеть так:

    Не пугайтесь, если после этого в выводе ls -l на хосте вместо имени владельца вы увидите число 999. Это нормально — главное, что внутри контейнера MongoDB распознает «своего» владельца. Теперь, когда файлы конфигурации исправлены, а права доступа восстановлены, инфраструктура готова к безопасному запуску.

    6. Пошаговый алгоритм безопасного перезапуска инфраструктуры Rocket.Chat через Docker Compose

    Пошаговый алгоритм безопасного перезапуска инфраструктуры Rocket.Chat через Docker Compose

    Представьте, что вы успешно отредактировали конфигурационные файлы и восстановили права доступа к данным. Кажется, что достаточно нажать «пуск», но именно на этом этапе 40% администраторов допускают критическую ошибку: они запускают всё одновременно. В результате Rocket.Chat пытается подключиться к MongoDB, которая еще не завершила внутреннюю проверку целостности данных после сбоя 22988, и вся система снова уходит в бесконечную перезагрузку.

    Почему важна последовательность

    Инфраструктура Rocket.Chat — это не просто набор контейнеров, а иерархическая система зависимостей. Rocket.Chat не может работать без активного Replica Set в MongoDB, а MongoDB после ручного вмешательства в файлы WiredTiger требует времени на инициализацию.

    Если запустить сервисы одной командой docker-compose up -d, Docker попытается поднять их параллельно. Rocket.Chat упадет с ошибкой подключения, а MongoDB может заблокировать файлы данных, если предыдущий процесс не был корректно завершен. Наша задача — реализовать «холодный пуск» с проверкой каждого этапа.

    Шаг 1: Полная очистка стека

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

  • Остановите и удалите все контейнеры текущего проекта:
  • Проверьте, что ни один процесс не использует файлы базы данных. Если вы использовали Sidecar-контейнеры для правки файлов, убедитесь, что они завершены:
  • Если вы видите контейнеры в статусе Exited, удалите их вручную, чтобы освободить ресурсы.

    Шаг 2: Изолированный запуск СУБД

    Мы запускаем только базу данных, чтобы дать движку WiredTiger считать исправленные параметры из WiredTiger.turtle и storage.bson.

    Сразу после этого необходимо войти в режим наблюдения за логами. На этом этапе мы ищем подтверждение того, что ошибка 22988 исчезла:

    > Логи должны содержать строку: > WiredTiger message [ ... ] recovery system found 0 crash record(s) > или сообщение о готовности принимать соединения на порту 27017.

    Если контейнер снова упал — значит, в файлах метаданных остались несоответствия или права доступа (UID 999) были восстановлены не для всех вложенных директорий.

    Шаг 3: Верификация Replica Set

    Rocket.Chat требует наличия инициализированной репликации, даже если у вас всего один узел базы. Часто после сбоя статус Replica Set сбрасывается.

    | Состояние | Действие | | :--- | :--- | | MongoDB запущена, логи чисты | Переходите к проверке статуса реплики | | Ошибка NotPrimaryNoSecondary | Необходима повторная инициализация через rs.initiate() | | Доступ разрешен, статус PRIMARY | База готова к приему подключений от приложения |

    Проверить статус можно командой:

    Шаг 4: Запуск прикладного уровня

    Только после того, как MongoDB перешла в стабильное состояние, мы поднимаем Rocket.Chat.

    На этом этапе важно следить за логами приложения. Rocket.Chat начнет миграцию базы данных (если версии обновлялись). Это может занять от 2 до 10 минут в зависимости от объема данных. Не прерывайте этот процесс.

    Сводный чек-лист перезапуска

    Для удобства используйте эту таблицу как алгоритм действий при любом восстановлении после сбоя:

  • Down: docker-compose down (удаление зависших сессий).
  • Start DB: docker-compose up -d mongodb.
  • Logs Check: Проверка отсутствия WiredTiger error (-22988).
  • Health Check: Проверка доступности порта 27017.
  • Start App: docker-compose up -d rocketchat.
  • Final Test: Открытие интерфейса в браузере.
  • Если система поднялась, значит, конфликт версий и параметров WiredTiger успешно разрешен, а цепочка зависимостей Docker Compose отработала корректно.