Статьи

Докер MySQL Persistence

Один из рецептов в 9 рецептах Docker для разработчиков Java использует контейнер MySQL с WildFly. Контейнеры Docker эфемерны, поэтому любое состояние, хранящееся в них, исчезает после их завершения и удаления. Таким образом, несмотря на то, что контейнер MySQL можно использовать, как описано в рецепте, команды DDL / DML можно использовать для сохранения данных, но это состояние теряется или, по крайней мере, недоступно после завершения и удаления контейнера.

Этот блог показывает различные подходы Docker MySQL Persistence — при перезапуске контейнера и доступе из нескольких контейнеров.

Расположение данных по умолчанию MySQL Docker Container

Давайте посмотрим местоположение по умолчанию, где контейнер MySQL Docker хранит данные.

Запустите контейнер MySQL как:

1
docker run --name mysqldb -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -d mysql

И проверять как:

1
docker inspect -f {{.Volumes}} <CONTAINER_ID>

Затем он показывает анонимные тома:

1
map[/var/lib/mysql:/mnt/sda1/var/lib/docker/vfs/dir/78f079dae09bf052cf900951b6d71a611fcf7c72f3460a2013e6f4d941a2b256]

Если вы используете Boot2Docker, то /mnt/sda1 используется для хранения изображений, контейнеров и данных. Этот каталог из файловой системы виртуальной машины Boot2Docker. Это также разъясняется в документации Docker и стоит повторить здесь:

Примечание. Если вы используете Boot2Docker, ваш демон Docker имеет ограниченный доступ только к вашей файловой системе OSX / Windows. Boot2Docker пытается автоматически предоставить общий доступ к вашему каталогу /Users (OSX) или C:\Users (Windows) — и вы можете монтировать файлы или каталоги, используя docker run -v /Users/<path>:/<container path> ... (OSX) или docker run -v /c/Users/<path>:/<container path ... (Windows). Все остальные пути берутся из файловой системы виртуальной машины Boot2Docker.

Вы можете просмотреть этот смонтированный каталог на Boot2Docker, войдя в виртуальную машину как:

1
boot2docker ssh

А затем просмотрите список каталогов как:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
docker@boot2docker:~$ ls -la /mnt/sda1/var/lib/docker/
total 72
drwxr-xr-x   11 root     root          4096 Apr  9 19:45 ./
drwxr-xr-x    4 root     root          4096 Mar 27 13:58 ../
drwxr-xr-x    5 root     root          4096 Mar 27 13:59 aufs/
drwx------   10 root     root          4096 Apr  9 19:45 containers/
drwx------    3 root     root          4096 Mar 27 13:59 execdriver/
drwx------  128 root     root         20480 Apr  9 19:45 graph/
drwx------    2 root     root          4096 Apr  7 23:34 init/
-rw-r--r--    1 root     root          7168 Apr  9 19:45 linkgraph.db
-rw-------    1 root     root          2229 Apr  9 19:45 repositories-aufs
drwx------    2 root     root          4096 Apr  9 19:14 tmp/
drwx------    2 root     root          4096 Mar 27 17:56 trust/
drwx------    3 root     root          4096 Apr  9 19:45 vfs/
drwx------    4 root     root          4096 Apr  9 19:45 volumes/

Перезапуск данных MySQL через контейнер — анонимные тома

Анонимные тома, то есть тома, созданные контейнером и явно не смонтированные, зависят от контейнера. Они остаются без явного удаления с помощью команды docker remove -v . Это означает, что новый анонимный том монтируется для нового контейнера, даже если предыдущий том не может быть удален. Том все еще живет на хосте Docker даже после того, как контейнер завершен и удален. Анонимный том, созданный одним контейнером MySQL, не доступен для другого контейнера MySQL. Это означает, что данные не могут быть разделены между различными контейнерами данных.

Давайте поймем это, используя код.

Запустите контейнер MySQL как:

1
docker run --name mysqldb -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -it -p 3306:3306 mysql

Вход в контейнер:

1
docker exec -it <CONTAINER_ID> bash

Подключитесь к экземпляру MySQL и создайте таблицу следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
root@04c2f54b7fe7:/# mysql --user=mysql --password=mysql
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.6.24 MySQL Community Server (GPL)
 
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
 
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
 
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
 
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| sample             |
+--------------------+
2 rows in set (0.00 sec)
 
mysql> connect sample;
Connection id:    3
Current database: sample
 
mysql> show tables;
Empty set (0.00 sec)
 
mysql> create table user(name varchar(50));
Query OK, 0 rows affected (0.00 sec)
 
mysql> show tables;
+------------------+
| Tables_in_sample |
+------------------+
| user             |
+------------------+
1 row in set (0.00 sec)

Остановить контейнер:

1
docker stop <CONTAINER_ID>

Перезапустите контейнер:

1
docker start <CONTAINER_ID>

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

Осмотрите контейнер:

1
2
~> docker inspect -f {{.Volumes}} ea7b1eff9714
map[/var/lib/mysql:/mnt/sda1/var/lib/docker/vfs/dir/78f079dae09bf052cf900951b6d71a611fcf7c72f3460a2013e6f4d941a2b256]

И он правильно показывает тот же анонимный том из каталога /mnt/sda1 .

Теперь давайте удалим контейнер и запустим новый контейнер MySQL. Сначала удалите контейнер:

1
docker rm -f <CONTAINER_ID>

И запустите новый контейнер, используя ту же команду, что и ранее:

1
docker run --name mysqldb -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -it -p 3306:3306 mysql

Теперь, когда вы пытаетесь увидеть список таблиц, он отображается как пустой:

1
2
3
4
5
6
mysql> connect sample;
Connection id:    3
Current database: sample
 
mysql> show tables;
Empty set (0.00 sec)

Это связано с тем, что анонимные тома видны при перезапуске контейнера, но не видны другим контейнерам. Новый том монтируется для нового запуска контейнера. Это также подтверждается повторной проверкой контейнера:

1
2
~> docker inspect -f {{.Volumes}} bde73c930275
map[/var/lib/mysql:/mnt/sda1/var/lib/docker/vfs/dir/4d0ab6d1412bfbe79541b2d87d632cf12e70044201665f859a6a678132fb323f]

Другой каталог используется для монтирования анонимного тома.

Таким образом, любые данные, хранящиеся в базе данных MySQL одним контейнером, недоступны другому контейнеру MySQL.

Том Docker для хранения данных MySQL

Один из вариантов обмена данными между различными контейнерами MySQL — это монтировать каталоги на хосте Docker как том в контейнерах, используя ключ -v при запуске образа Docker. Если вы используете Boot2Docker, то есть два варианта:

  • Смонтируйте каталог из файловой системы VM Boot2Docker. Этот каталог, если он еще не существует, должен быть создан.
  • Смонтируйте каталог с вашего хоста Mac. Для удобства это должно существовать в /Users/arungupta или в любом /Users/arungupta каталоге.

Первый подход связан с конкретным образом виртуальной машины Boot2Docker, а второй — с конкретным хостом Mac. Мы посмотрим, как это можно исправить позже.

Мы обсудим первый подход только здесь. Запустите контейнер MySQL как:

1
docker run --name mysqldb -v /mnt/sda1/var/mysql_data:/var/lib/mysql -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -it -p 3306:3306 mysql

/var/lib/mysql — это каталог по умолчанию, куда контейнер MySQL записывает свои файлы. Этот каталог не сохраняется после перезагрузки Boot2Docker. Поэтому рекомендуемый вариант — создать каталог в /mnt/sda1 и отобразить его вместо этого. Убедитесь, что вы создали каталог /mnt/sda1/var/mysql_data , как в случае выше.

Теперь осматриваем контейнер как:

1
2
~> docker inspect -f {{.Volumes}} cd7deacc9d18
map[/var/lib/mysql:/mnt/sda1/var/mysql_data]

Теперь любые дополнительные запуски контейнера могут монтировать тот же том и будут иметь доступ к данным.

Помните, несколько контейнеров MySQL не могут получить доступ к этому общему монтированию и вместо этого выдают ошибку:

1
2
3
2015-04-10 02:35:58 1 [ERROR] InnoDB: Unable to lock ./ibdata1, error: 11
2015-04-10 02:35:58 1 [Note] InnoDB: Check that you do not already have another mysqld process using the same InnoDB data or log files.
2015-04-10 02:35:58 1 [Note] InnoDB: Retrying to lock the first data file

Поэтому вам нужно обязательно остановить существующий контейнер MySQL, запустить новый контейнер MySQL, используя тот же том, и данные по-прежнему будут доступны.

Это может быть настроено с использованием конфигурации master / slave, где master и slave имеют доступ к одному и тому же тому. Было бы здорово, если бы кто-то, кто попробовал эту конфигурацию, мог поделиться этим рецептом.

Но, как уже упоминалось ранее, этот подход ориентирован на хост. Он ограничивает MySQL определенным образом виртуальной машины Boot2Docker. Это означает, что вы снова теряете большое преимущество портативности, предлагаемое Docker.

Познакомьтесь с контейнерами только для данных Docker!

Контейнеры только для данных Docker

Докер очень хорошо следует принципу единой ответственности (SRP). Docker Контейнеры только для данных — это контейнеры NoOp, которые выполняют действительно не релевантную команду и вместо этого монтируют тома, которые используются для хранения данных. Эти контейнеры даже не нужно запускать или запускать, и поэтому команда на самом деле не имеет значения, достаточно просто создать их.

Создайте контейнер как:

1
docker create --name mysql_data -v /var/lib/mysql mysql

Если вы планируете использовать контейнер MySQL позже, рекомендуется использовать образ mysql чтобы сэкономить пропускную способность и пространство от загрузки другого случайного изображения. Вы можете настроить эту команду для любого контейнера базы данных, который вы используете.

Если вы намереваетесь использовать MySQL, то этот контейнер только для данных может быть создан как:

1
docker create --name mysql_data arungupta/mysql-data-container

Dockerfile для этого контейнера довольно прост и может быть адаптирован для любого сервера базы данных.

Так как этот контейнер не запущен, он не будет виден только с помощью docker ps . Вместо этого вам нужно использовать docker ps -a для просмотра контейнера:

1
2
~> docker ps -a | grep mysql
ec48ddda196e        mysql:5                      "/entrypoint.sh mysq   2 days ago                                                        mysql_data

Docker позволяет монтировать или извлекать тома из других контейнеров, используя --volumes-from указанный при запуске контейнера.

Давайте запустим наш контейнер MySQL, чтобы использовать этот контейнер только для данных как:

1
docker run --name mysqldb --volumes-from mysql_data -v /var/lib/mysql:/var/lib/mysql -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_DATABASE=sample -e MYSQL_ROOT_PASSWORD=supersecret -it -p 3306:3306 mysql

Виртуальная машина Boot2Docker теперь имеет каталог /var/lib/mysql :

01
02
03
04
05
06
07
08
09
10
total 110596
drwxrwxrwx    5 999      999            180 Apr 10 05:05 ./
drwxrwxr-x    4 root     staff          120 Apr  9 21:11 ../
-rw-rw----    1 999      999             56 Apr 10 00:57 auto.cnf
-rw-rw----    1 999      999       50331648 Apr 10 05:05 ib_logfile0
-rw-rw----    1 999      999       50331648 Apr 10 00:57 ib_logfile1
-rw-rw----    1 999      999       12582912 Apr 10 05:05 ibdata1
drwx------    2 999      999           1620 Apr 10 00:57 mysql/
drwx------    2 999      999           1100 Apr 10 00:57 performance_schema/
drwx------    2 999      999            100 Apr 10 01:18 sample/

Если вы остановите этот контейнер и запустите другой контейнер, данные будут там доступны.

techtip83-докер-MySQL-живучесть

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

Надеемся, что это будет более обширным, когда тома Docker могут работать на нескольких хостах.

Было бы хорошо, если бы все это, то есть создание контейнера только для данных и запуск контейнера MySQL, который использует том из контейнера только для данных, можно было легко сделать с помощью Docker Compose. # 1284 должен это исправить.

Обычные команды mysqldump и mysql могут использоваться для резервного копирования и восстановления с тома. Это может быть достигнуто путем подключения к MySQL с помощью CLI, как описано здесь .

  • Вы также можете посмотреть на Docker-тома для управления томами на вашем хосте.
  • Вы также можете прочитать больше о томах, которые могут появиться в будущем на # 6496 .

Наслаждайтесь!

Ссылка: Docker MySQL Persistance от нашего партнера по JCG Аруна Гупта из Miles to go 2.0… блог.