2.5.6.2 Docker 部署 MySQL 服务器的更多主题
以下大多数示例命令使用container-registry.oracle.com/mysql/community-server
作为 Docker 镜像(如同使用docker pull和docker run命令);如果您的镜像来自其他存储库,请将其更改为container-registry.oracle.com/mysql/enterprise-server
,用于从 Oracle 容器注册中心(OCR)下载的 MySQL Enterprise Edition 镜像,或者mysql/enterprise-server
,用于从My Oracle Support下载的 MySQL Enterprise Edition 镜像。
MySQL 的 Docker 镜像经过优化,以便减少代码大小,仅包含大多数用户在 Docker 容器中运行 MySQL 实例所需的关键组件。与常见的非 Docker 安装不同的是:
-
只包括有限数量的可执行文件。
-
所有可执行文件都被删除;它们不包含调试信息。
用户对 Docker 容器(包括 MySQL 组件)进行软件更新或安装可能会与优化的 MySQL 安装冲突。Oracle 不提供对在这种已被修改容器中运行的 MySQL 产品或来自已被修改 Docker 镜像的容器提供支持。
当您启动 MySQL Docker 容器时,可以通过 docker run 命令将配置选项传递给服务器。例如:
docker run --name mysql1 -d container-registry.oracle.com/mysql/community-server:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_col
命令启动 MySQL 服务器,以 utf8mb4 作为默认字符集和 utf8mb4_ col 作为默认排序规则。
另一种配置 MySQL 服务器的方法是准备一个配置文件,并将其挂载到容器内的服务器配置文件位置。请参阅 Persisting Data and Configuration Changes以获取详细信息。
Docker 容器本质上是临时的,任何数据或配置都将被删除或损坏(请参阅这里)。Docker 卷提供了一个机制来 persist 数据创建在 Docker 容器内。MySQL 服务器容器在启动时创建了一个 Docker 卷,以便将服务器数据目录挂载到其中。使用docker inspect命令对容器进行 JSON 输出,其中包括一个Mount
关键字,值提供了关于数据目录卷的信息:
$> docker inspect mysql1
...
"Mounts": [
{
"Type": "volume",
"Name": "4f2d463cfc4bdd4baebcb098c97d7da3337195ed2c6572bc0b89f7e845d27652",
"Source": "/var/lib/docker/volumes/4f2d463cfc4bdd4baebcb098c97d7da3337195ed2c6572bc0b89f7e845d27652/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
...
输出结果显示源目录/var/lib/docker/volumes/4f2d463cfc4bdd4baebcb098c97d7da3337195ed2c6572bc0b89f7e845d27652/_data
,在主机上 persist 数据的目录,已经被挂载到容器内的服务器数据目录/var/lib/mysql
中。
另一种方式是使用bind-mount将主机目录绑定到容器中,使用--mount
选项创建容器。同样,可以用于 persist 服务器配置文件。以下命令创建了一个 MySQL Server 容器,并 bind- mounted 数据目录和服务器配置文件:
docker run --name=mysql1 \
--mount type=bind,src=/path-on-host-machine/my.cnf,dst=/etc/my.cnf \
--mount type=bind,src=/path-on-host-machine/datadir,dst=/var/lib/mysql \
-d container-registry.oracle.com/mysql/community-server:tag
该命令将
绑定到容器中的path-on-host-machine/my.cnf
(服务器配置文件),并将/etc/my.cnf
绑定到容器中的path-on-host-machine/datadir
/var/lib/mysql
(数据目录)。以下条件必须满足,以使 bind- mounting 工作:
-
配置文件
必须已经存在,并且它必须包含用户path-on-host-machine/my.cnf
mysql
启动服务器的指定:[mysqld] user=mysql
您还可以在文件中包括其他服务器配置选项。
-
数据目录
必须已经存在。为了服务器初始化,可以将目录设置为空。您也可以将预先填充了数据的目录 mount 到容器中,并使用该目录启动服务器;但是,您必须确保在启动容器时使用与创建数据的服务器相同的配置,并且所有主机文件或目录都被mount 到容器中。path-on-host-machine/datadir
如果您想在数据库创建后立即运行的.sh
或.sql
脚本,可以将它们放置到主机目录中,然后在容器内将目录挂载到/docker-entrypoint-initdb.d/
。例如:
docker run --name=mysql1 \
--mount type=bind,src=/path-on-host-machine/scripts/,dst=/docker-entrypoint-initdb.d/ \
-d container-registry.oracle.com/mysql/community-server:tag
通过设置 Docker 网络,您可以允许多个 Docker 容器之间的通信,使得在另一个 Docker 容器中的客户端应用程序能够访问 MySQL 服务器容器中的 MySQL Server。首先,创建 Docker 网络:
docker network create my-custom-net
然后,在创建和启动服务容器和客户端容器时,使用--network
选项将它们添加到您创建的网络中。例如:
docker run --name=mysql1 --network=my-custom-net -d container-registry.oracle.com/mysql/community-server
docker run --name=myapp1 --network=my-custom-net -d myapp
然后,myapp1
容器可以使用mysql1
主机名连接到mysql1
容器,而反之亦然,因为 Docker 自动设置了给定容器名称的 DNS。在以下示例中,我们从myapp1
容器内部运行mysql客户端,以连接到自己的容器中的主机mysql1
:
docker exec -it myapp1 mysql --host=mysql1 --user=myuser --password
对于其他容器网络技术,请参阅 Docker 文档中的Docker 容器网络部分。
当 MySQL 服务器首次启动时,如果满足以下任何一个条件,server error log将不会生成:
-
主机上的服务器配置文件已经挂载,但是该文件不包含系统变量
log_error
(请参阅 Persisting Data and Configuration Changes关于挂载服务器配置文件的详细信息)。 -
主机上的服务器配置文件没有被挂载,但是 Docker 环境变量
MYSQL_LOG_CONSOLE
为true
(这是 MySQL 8.4 服务器容器的默认状态),MySQL Server 的错误日志将被重定向到stderr
,因此错误日志将出现在 Docker 容器的日志中,可以使用docker logsmysqld-container
命令查看。
要使 MySQL Server 在满足任何一个条件时生成错误日志,请使用--log-error
选项来配置服务器,以便在容器内的特定位置生成错误日志。要 persist 错误日志,挂载主机文件到容器内错误日志的位置,如 Persisting Data and Configuration Changes中所述。然而,您必须确保 MySQL Server 内容器中的写入权限。
MySQL企业备份是MySQL Server的商业许可证备份工具,仅在MySQL Enterprise Edition中提供。 MySQL Enterprise Backup也包含在MySQL Enterprise Edition Docker安装中。
以下示例假设您已经在Docker容器中启动了MySQL Server(请参阅第2.5.6.1节,“基本步骤:使用Docker部署MySQL Server”,了解如何使用Docker启动MySQL Server实例)。为了使MySQL Enterprise Backup能够备份MySQL Server,它必须访问服务器的数据目录。这可以通过,例如在启动服务器时将主机目录绑定到MySQL Server的数据目录来实现:
docker run --name=mysqlserver \
--mount type=bind,src=/path-on-host-machine/datadir/,dst=/var/lib/mysql \
-d mysql/enterprise-server:8.4
使用以下命令,MySQL Server将使用MySQL Enterprise Edition Docker映像启动,并将主机目录/path-on-host-machine/datadir/
挂载到服务器容器中的数据目录(/var/lib/mysql
)内。我们还假设,服务器已经启动后,MySQL Enterprise Backup也已经设置了所需的权限来访问服务器(请参阅Grant MySQL Privileges to Backup Administrator,了解详细信息)。使用以下步骤备份和恢复MySQL Server实例。
使用 Docker 中的 MySQL Enterprise Backup 将 MySQL 服务器实例备份,按照以下步骤操作:
-
在 MySQL 服务器容器运行的同一主机上,启动另一个容器,以使用 MySQL Enterprise Backup 命令
backup-to-image
进行备份。提供对服务器数据目录的访问,使用我们在上一步创建的 bind 挂载。同时,将主机目录(例如:/path-on-host-machine/backups/
)挂载到容器中的存储备份文件夹(例如:/data/backups
)以 persist 创建的备份。以下是一个 sample 命令,使用 Docker 映像从My Oracle Support下载 MySQL Enterprise Backup:$> docker run \ --mount type=bind,src=/path-on-host-machine/datadir/,dst=/var/lib/mysql \ --mount type=bind,src=/path-on-host-machine/backups/,dst=/data/backups \ --rm mysql/enterprise-server:8.4 \ mysqlbackup -umysqlbackup -ppassword --backup-dir=/tmp/backup-tmp --with-timestamp \ --backup-image=/data/backups/db.mbi backup-to-image
重要的是,在mysqlbackup输出的末尾检查,以确保备份已经成功完成。
-
容器在备份作业完成后退出,并且使用
--rm
选项启动它,它将在退出时被删除。一个图像备份已经创建,位于上一步中用于存储备份的主机目录中,如下所示:$> ls /tmp/backups db.mbi
使用 MySQL Enterprise Backup with Docker 将 MySQL 服务器实例恢复到 Docker 容器中,按照以下步骤操作:
-
停止 MySQL 服务器容器,这也将停止运行在其中的 MySQL 服务器:
docker stop mysqlserver
-
在主机上,删除 MySQL 服务器数据目录 bind 挂载中的所有内容:
rm -rf /path-on-host-machine/datadir/*
-
使用 MySQL Enterprise Edition 的图像启动一个容器,使用 MySQL Enterprise Backup 命令
copy-back-and-apply-log
进行恢复。将服务器的数据目录和备份存储文件夹绑定-mount,类似于我们在备份服务器时所做的:$> docker run \ --mount type=bind,src=/path-on-host-machine/datadir/,dst=/var/lib/mysql \ --mount type=bind,src=/path-on-host-machine/backups/,dst=/data/backups \ --rm mysql/enterprise-server:8.4 \ mysqlbackup --backup-dir=/tmp/backup-tmp --with-timestamp \ --datadir=/var/lib/mysql --backup-image=/data/backups/db.mbi copy-back-and-apply-log mysqlbackup completed OK! with 3 warnings
容器退出后显示“
mysqlbackup completed OK!
”消息,一旦备份作业完成,并且使用了--rm
选项启动它,它将在退出后被删除。 -
使用以下命令重启服务器容器,这也将重新启动恢复的服务器:
docker restart mysqlserver
或者,启动一个新的 MySQL 服务器,在恢复的数据目录上,如下所示:
docker run --name=mysqlserver2 \ --mount type=bind,src=/path-on-host-machine/datadir/,dst=/var/lib/mysql \ -d mysql/enterprise-server:8.4
登录到服务器,以检查服务器是否正在使用恢复的数据。
除了使用 MySQL Enterprise Backup 将 MySQL 服务器在 Docker 容器中备份之外,您还可以使用mysqldump实用工具在 Docker 容器中执行逻辑备份。
以下步骤假设您已经在 Docker 容器中运行了 MySQL 服务器,并且在容器启动时,将主机目录/path-on-host-machine/datadir/
挂载到服务器的数据目录/var/lib/mysql
中(请参阅在 MySQL 服务器上 bind-mount 主机目录的详细信息),该目录包含 Unix 套接字文件,用于mysqldump
和mysql
连接到服务器。我们还假设,在服务器启动后,一名拥有合适权限(在本例中为admin
)的用户已经被创建,以便mysqldump
可以访问服务器。使用以下步骤备份和恢复 MySQL 服务器数据:
使用 Docker 将 MySQL 服务器数据备份到mysqldump
:
-
在 MySQL Server 容器运行的同一主机上,启动另一个容器,以使用mysqldump实用工具(见实用工具的文档、选项和限制)进行备份。将服务器的数据目录提供给容器,通过 bind 挂载
/path-on-host-machine/datadir/
。同时,将主机目录(/path-on-host-machine/backups/
在本例中)挂载到容器中的备份存储文件夹(/data/backups
在本例中),以 persistently 保存您创建的备份。以下是一个使用该设置备份所有服务器数据库的示例命令:$> docker run --entrypoint "/bin/sh" \ --mount type=bind,src=/path-on-host-machine/datadir/,dst=/var/lib/mysql \ --mount type=bind,src=/path-on-host-machine/backups/,dst=/data/backups \ --rm container-registry.oracle.com/mysql/community-server:8.4 \ -c "mysqldump -uadmin --password='password' --all-databases > /data/backups/all-databases.sql"
在命令中,使用
--entrypoint
选项,以便在容器启动后invoke系统shell,并使用-c
选项指定mysqldump命令在shell中运行,输出重定向到文件all-databases.sql
在备份目录中。 -
容器退出后,备份作业完成,并且使用
--rm
选项启动它,它将被删除。一个逻辑备份已经创建,可以在存储备份的主机目录中找到,如下所示:$> ls /path-on-host-machine/backups/ all-databases.sql
使用mysqldump Docker 进行 MySQL Server 数据恢复:
-
确保您已经启动了一个MySQL Server容器,用于将备份数据恢复到其中。
-
使用mysql客户端启动一个容器,用于执行恢复操作。将服务器的数据目录和包含备份的存储文件夹绑定到容器中:
$> docker run \ --mount type=bind,src=/path-on-host-machine/datadir/,dst=/var/lib/mysql \ --mount type=bind,src=/path-on-host-machine/backups/,dst=/data/backups \ --rm container-registry.oracle.com/mysql/community-server:8.4 \ mysql -uadmin --password='password' -e "source /data/backups/all-databases.sql"
容器在备份任务完成后退出,并且使用
--rm
选项启动时,它将在退出后被删除。 -
登录服务器以检查恢复后的数据现在是否已经在服务器上。
-
使用服务器系统变量
audit_log_file
配置审核日志文件名时,使用loose
选项修饰符;否则,Docker无法启动服务器。
Docker 环境变量
当您创建一个MySQL Server容器时,可以使用--env
选项(简写为-e
)和指定一个或多个环境变量来配置MySQL实例。如果已mounted的数据目录不为空,服务器将不会初始化,在这种情况下设置这些变量没有效果(请参阅 Persisting Data and Configuration Changes),并且在容器启动时不会修改目录中的任何内容,包括服务器设置。
可以用于配置MySQL实例的环境变量列表如下:
-
包括
MYSQL_RANDOM_ROOT_PASSWORD
、MYSQL_ONETIME_PASSWORD
、MYSQL_ALLOW_EMPTY_PASSWORD
和MYSQL_LOG_CONSOLE
的布尔变量可以通过将它们设置为任何非零长度字符串来使其为真。因此,例如,将它们设置为“0”、“false”或“no”实际上不会使它们为假,而是将它们设置为真。这是一个已知的问题。 -
MYSQL_RANDOM_ROOT_PASSWORD
:当这个变量为真(除非MYSQL_ROOT_PASSWORD
被设置或MYSQL_ALLOW_EMPTY_PASSWORD
被设置为真)时,Docker容器启动时将生成服务器的root用户随机密码。密码将被打印到容器的stdout
中,可以在容器的日志中找到(见Starting a MySQL Server Instance)。 -
MYSQL_ONETIME_PASSWORD
: 当变量为真(除非MYSQL_ROOT_PASSWORD
或MYSQL_ALLOW_EMPTY_PASSWORD
设置为true)时,root用户的密码将被设置为过期,并且必须在MySQL正常使用前更改。 -
MYSQL_DATABASE
: 这个变量允许您在图像启动时指定一个数据库的名称。如果使用MYSQL_USER
和MYSQL_PASSWORD
提供用户名和密码,用户将被创建,并且授予超级用户访问权限到这个数据库(对应于GRANT ALL
)。指定的数据库由一个CREATE DATABASE IF NOT EXIST语句创建,因此变量在数据库已经存在时无效。 -
MYSQL_USER
,MYSQL_PASSWORD
:这两个变量一起使用,创建用户并设置该用户的密码,并将该用户授予指定数据库(由MYSQL_DATABASE
变量指定)的超级用户权限。同时,MYSQL_USER
和MYSQL_PASSWORD
都需要设置,以创建用户—if任何一个变量未设置,另一个将被忽略。如果两个变量都设置,但MYSQL_DATABASE
未设置,则用户将被创建无权限。Note不需要使用这个机制来创建root超级用户,因为root超级用户默认情况下由一个或多个机制(如
MYSQL_ROOT_PASSWORD
和MYSQL_RANDOM_ROOT_PASSWORD
)创建,除非MYSQL_ALLOW_EMPTY_PASSWORD
为true。 -
MYSQL_ROOT_HOST
: 默认情况下,MySQL 创建了'root'@'localhost'
帐户。这个帐户只能从容器内部连接,如Connecting to MySQL Server from within the Container中所述。要允许来自其他主机的 root 连接,设置这个环境变量。例如,值172.17.0.1
允许来自运行容器的主机的连接。该选项只接受一个入口,但允许使用通配符(例如MYSQL_ROOT_HOST=172.*.*.*
或MYSQL_ROOT_HOST=%
)。 -
MYSQL_LOG_CONSOLE
: 当变量为 true(MySQL 8.4 服务器容器的默认状态)时,MySQL Server 的错误日志将被重定向到stderr
,因此错误日志将出现在 Docker 容器的日志中,可以使用docker logsmysqld-container
命令查看。Note如果从主机挂载了服务器配置文件(见Persisting Data and Configuration Changes关于 bind-mounting 配置文件),那么变量将无效。
-
MYSQL_ROOT_PASSWORD
: 设置 MySQL root 账户的密码。Warning在命令行中设置 MySQL root 用户密码不安全。相反,您可以将变量设置为容器文件路径,以便存储密码文件,然后在容器文件路径下挂载主机上的文件,该文件包含密码。这仍然不是很安全,因为密码文件的位置仍然暴露出来。更好的选择是使用默认设置,
MYSQL_RANDOM_ROOT_PASSWORD
和MYSQL_ONETIME_PASSWORD
都设置为 true。 -
MYSQL_ALLOW_EMPTY_PASSWORD
. 将其设置为 true,以允许容器以空密码启动 root 用户。Warning将变量设置为 true 是不安全的,因为这将使您的 MySQL 实例完全无保护,任何人都可以获得超级用户访问权限。更好的选择是使用默认设置,
MYSQL_RANDOM_ROOT_PASSWORD
和MYSQL_ONETIME_PASSWORD
都设置为 true。