Один из рецептов в 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/ |
Если вы остановите этот контейнер и запустите другой контейнер, данные будут там доступны.
В простом сценарии сервер приложений, база данных и контейнер только для данных могут находиться на одном хосте. Кроме того, сервер приложений может находиться на отдельном хосте и сервере базы данных, а контейнер только для данных может оставаться на одном хосте.
Надеемся, что это будет более обширным, когда тома Docker могут работать на нескольких хостах.
Было бы хорошо, если бы все это, то есть создание контейнера только для данных и запуск контейнера MySQL, который использует том из контейнера только для данных, можно было легко сделать с помощью Docker Compose. # 1284 должен это исправить.
Обычные команды mysqldump
и mysql
могут использоваться для резервного копирования и восстановления с тома. Это может быть достигнуто путем подключения к MySQL с помощью CLI, как описано здесь .
- Вы также можете посмотреть на Docker-тома для управления томами на вашем хосте.
- Вы также можете прочитать больше о томах, которые могут появиться в будущем на # 6496 .
Наслаждайтесь!
Ссылка: | Docker MySQL Persistance от нашего партнера по JCG Аруна Гупта из Miles to go 2.0… блог. |