Как сохранить подкаталог mysql в локальной системе из контейнера docker

#mysql #docker

Вопрос:

Мне нужно сохранить свою базу данных из контейнера docker mysql, чтобы другие члены команды также могли работать над ней. До сих пор мы использовали это, и это работало просто отлично:

     volumes:
      - ./db/:/var/lib/mysql/
 

Однако папка /db была действительно грязной, потому что папка /mysql содержит все файлы mysql, а не только базу данных. Поэтому я попытался сохранить только папку базы данных:

     volumes:
      - ./db/:/var/lib/mysql/database/
 

Но, к сожалению, я продолжаю получать эту ошибку:

 [ERROR] --initialize specified but the data directory has files in it. Aborting.
[ERROR] Aborting
 

Однако, несмотря на то, что говорится в ошибке, папка /db пуста (также нет скрытых файлов), поэтому я понятия не имею, в чем на самом деле заключается ошибка.

Я также попробовал другие подкаталоги внутри /mysql и получил тот же результат. Когда я возвращаю изменения обратно - ./db/:/var/lib/mysql/ , ошибка исчезает.

Полный докер-compose.yml:

   mysql:
    image: mysql:${MYSQL_VERSION:-latest}
    restart: always
    ports:
      - "3306:3306"
    volumes:
      - ./db/:/var/lib/mysql/${DB_NAME}
    networks:
      - backend
    environment:
      MYSQL_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}"
      MYSQL_DATABASE: "${DB_NAME}"
      MYSQL_USER: "${DB_USERNAME}"
      MYSQL_PASSWORD: "${DB_PASSWORD}"
    container_name: ${PROJECT_PREFIX}_mysql
 

Ответ №1:

Есть несколько вещей, которые следует отметить в примере, которым вы поделились:

  • Образ MySQL, который вы используете, фактически не «инициализирует» сервер базы данных до тех пор, пока он не будет впервые доставлен up (обычная практика, поскольку размер изображения остается относительно небольшим).
  • Контейнеры Docker не сохраняют никаких данных, если вы явно не смонтируете их с помощью volumes . Поэтому каждый раз, когда вы переключаетесь с down / up , вы возвращаете контейнер в исходное состояние изображения.
  • Когда вы просматриваете down / up , порядок операций выглядит следующим образом:
    1. используется исходное состояние изображения
    2. крепления тома монтируются в следующем
    3. сценарии точки входа запускаются для вызова контейнера.
  • В данном случае сценарии точки 3 входа MySQL «инициализируют» сервер базы данных , если /var/lib/mysql каталог пуст, в противном случае он просто загрузит его из существующих файлов.
  • Когда вы монтируете /var/lib/mysql , это работает, потому что:
    • если каталог пуст, то он инициализируется
    • если каталог не пуст, то он загружает состояние.
  • Однако при подключении монтируется /var/lib/mysql/database только этот каталог, а другие важные данные не включаются в /var/lib/mysql него , поскольку они не существуют в исходном образе. Оказывается, другие важные данные, которых не хватает, — это то, что проверяет MySQL, чтобы проверить, нужно ли ему «инициализировать» сервер базы данных или нет. Наконец, он пытается инициализироваться из-за отсутствующих данных, но если /var/lib/mysql они не пусты, он выдает ошибку (вашу ошибку). В этом случае он не пуст, потому что вы смонтировали database его в каталоге /var/lib/mysql .

Ваши варианты в основном:

  • Живите с подключением /var/lib/mysql и резервным копированием всего каталога (убедитесь, что вы делаете резервные копии только тогда, когда у вас есть docker-compose down !)
  • Создайте свой собственный файл Dockerfile с дополнительными RUN шагами для инициализации MySQL и уменьшите его, чтобы сервер базы данных был «инициализирован» и сохранен в образе. Однако я бы не рекомендовал это делать, так как: 1) размер вашего изображения docker будет намного больше, и 2) этот параметр подвержен проблемам с повреждением.