2.5.6.2 使用 Docker 部署 MySQL 服务器的更多主题

注意

当必须指定 mysql/mysql-server 作为 Docker 镜像存储时, 下面的大多数命令都会使用它(像是 docker pulldocker run 命令); 如果你的镜像来自另一个库, 那就去修改—例如, 替换为 store/oracle/mysql-enterprise-server 是 Docker 商店的 MySQL 企业版镜像, 或者 container-registry.oracle.com/mysql/enterprise-server 是 Oracle 容器库的 MySQL 企业版镜像.

优化过的 Docker 版 MySQL 安装

Docker 版 MySQL 镜像进行了代码优化, 这意味着他们只包含大多数在 Docker 容器中运行 MySQL 实例的与用户相关的关键组件. MySQL Docker 安装与常见的非 Docker 安装的不同在以下几个方面:

  • 包含的二进制文件仅限于:

    • /usr/bin/my_print_defaults

    • /usr/bin/mysql

    • /usr/bin/mysql_config

    • /usr/bin/mysql_install_db

    • /usr/bin/mysql_tzinfo_to_sql

    • /usr/bin/mysql_upgrade

    • /usr/bin/mysqladmin

    • /usr/bin/mysqlcheck

    • /usr/bin/mysqldump

    • /usr/bin/mysqlpump

    • /usr/bin/mysqlbackup (仅适用于 MySQL 8.0 企业版)

    • /usr/sbin/mysqld

  • 所有的二进制文件都会被删除; 它们不包含调试信息.

配置 MySQL 服务器

当你启动 MySQL Docker 容器时, 你可以通过 docker run 命令将配置选项传递给服务器; 例如:

  1. docker run --name mysql1 -d mysql/mysql-server:tag --character-set-server=utf8mb4 --collation-server=utf8mb4_col

命令使用 utf8mb4 作为默认字符集, 使用 utf8mb4_col 作为数据库的默认排序规则启动 MySQL 服务器.

配置 MySQL 服务器的另外一种方式是准备一个配置文件, 将其挂载到容器内服务器配置文件的位置. 参阅持久化数据和配置更改获取详情.

持久化数据和配置更改

Docker 容器原则上是短暂的, 如果容器被删除或者损坏了, 任何数据或者配置都有可能会丢失(这里查看讨论). Docker volumes, 然而, 提供了一种机制来保护 Docker 容器内创建的数据. 在初始化时, MySQL 服务器容器为服务器数据目录创建一个 Docker volume. 在容器上运行 docker inspect 命令的 JSON 输出中有一个 Mount 键, 其值提供了关于数据目录卷(volume) 的相关信息:

  1. shell> docker inspect mysql1
  2. ...
  3. "Mounts": [
  4. {
  5. "Type": "volume",
  6. "Name": "4f2d463cfc4bdd4baebcb098c97d7da3337195ed2c6572bc0b89f7e845d27652",
  7. "Source": "/var/lib/docker/volumes/4f2d463cfc4bdd4baebcb098c97d7da3337195ed2c6572bc0b89f7e845d27652/_data",
  8. "Destination": "/var/lib/mysql",
  9. "Driver": "local",
  10. "Mode": "",
  11. "RW": true,
  12. "Propagation": ""
  13. }
  14. ],
  15. ...

输出显示源文件夹 /var/lib/docker/volumes/4f2d463cfc4bdd4baebcb098c97d7da3337195ed2c6572bc0b89f7e845d27652/_data, 已经挂载到 /var/lib/mysql, 即容器内的服务器数据目录.

保存数据的另一种方式时在创建容器时使用 —— --mount 选项 bind-mount 主机目录. 可以使用相同的技术来保存服务器的配置. 下面的命令创建一个 MySQL Server 容器并绑定挂载数据目录和服务器配置文件:

  1. docker run --name=mysql1 \
  2. --mount type=bind,src=/path-on-host-machine/my.cnf,dst=/etc/my.cnf \
  3. --mount type=bind,src=/path-on-host-machine/datadir,dst=/var/lib/mysql \
  4. -d mysql/mysql-server:tag

命令挂载 path-on-host-machine/my.cnf/etc/my.cnf (容器内的服务器配置文件), 并且挂载 path-on-host-machine/datadir/var/lib/mysql (容器内的数据目录). 必须满足以下条件, 才能绑定挂载工作:

  • 配置文件 path-on-host-machine/my.cnf 必须总是存在, 它必须包含启动服务器的指定用户 mysql:
  1. [mysqld]
  2. user=mysql

你也可以在文件中加载其他服务器配置项.

  • 数据目录 path-on-host-machine/datadir 必须已存在. 要对服务器进行初始化, 目录必须为空. 可以挂载填充了数据的目录, 并使用它启动服务器; 然而, you must make sure you start the Docker container with the same configuration as the server that created the data, and any host files or directories required are mounted when starting the container.
运行其他初始化脚本

如果在数据库创建后, 有任何 .sh 或者 .sql 脚本希望立即在数据库上运行, 你可以将它们放入到主机目录内, 然后将目录挂载到容器内的 /docker-entrypoint-initdb.d/ 目录. 例如:

  1. docker run --name=mysql1 \
  2. --mount type=bind,src=/path-on-host-machine/scripts/,dst=/docker-entrypoint-initdb.d/ \
  3. -d mysql/mysql-server:tag
从另外一个 Docker 容器中的应用连接到 MySQL

通过设置 Docker 网络, 你可以允许多个 Docker 容器之间互相通信, 因此另外一个 Docker 容器中的客户端应用可以访问服务器容器中的 MySQL Server. 首先, 创建 Docker 网络:

  1. docker network create my-custom-net

然后, 当你创建和启动服务器和客户端容器时, use the --network option to put them on network you created. 例如:

  1. docker run --name=mysql1 --network=my-custom-net -d mysql/mysql-server
  1. docker run --name=myapp1 --network=my-custom-net -d myapp

myapp1 容器可以使用 mysql1 主机名连接到 mysql1容器, 反之亦然, Docker 会自动为给定的容器名称设置 DNS. 在下面的示例中, 我们运行 myapp1 容器中的 mysql 客户端连接到 mysql1 主机所在的容器:

  1. docker exec -it myapp1 mysql --host=mysql1 --user=myuser --password

关于容器的其他网络技术, 参阅 Docker 文档中的 Docker 容器网络.

服务器错误日志

当 MySQL Server 首次使用你的服务器容器启动时, 如果满足以下任何一个条件, 则不会生成服务器错误日志:

  • 主机中已挂载服务器配置文件, 但是文件不包含系统变量 log_error (关于 bind-mounting 服务器配置文件参阅 持久化数据和配置更改).

  • 主机并没有挂载服务器配置文件, 但是 Docker 环境变量 MYSQL_LOG_CONSOLE 为 true (MySQL 8.0 服务器容器的变量默认状态). MySQL Server 的错误日志会重定向到 stderr, 因此错误日志进入到 Docker 容器日志并且可以使用 docker logs mysqld-container 命令查看.

To make MySQL Server generate an error log when either of the two conditions is true, use the --log-error option to configure the server to generate the error log at a specific location inside the container. To persist the error log, mount a host file at the location of the error log inside the container as explained in Persisting Data and Configuration Changes. 然而, you must make sure your MySQL Server inside its container has write access to the mounted host file.

使用 Docker MySQL 企业版备份

MySQL Enterprise Backup is a commercially-licensed backup utility for MySQL Server, available with MySQL Enterprise Edition. MySQL Enterprise Backup is included in the Docker installation of MySQL Enterprise Edition.

在下面的示例中, 我们假设你已经在 Docker 容器中运行了 MySQL Server (关于如何在 Docker 中启动一个 MySQL Server, 参阅 2.5.6.1 使用 Docker 部署 MySQL 服务器的基本步骤”). For MySQL Enterprise Backup to back up the MySQL Server, it must have access to the server’s data directory. 可以通过以下方式实现, 例如, bind-mounting a host directory on the data directory of the MySQL Server when you start the server:

  1. docker run --name=mysqlserver \
  2. --mount type=bind,src=/path-on-host-machine/datadir/,dst=/var/lib/mysql \
  3. -d store/oracle/mysql-enterprise-server:8.0

With this command, the MySQL Server is started with a Docker image of the MySQL Enterprise Edition, and the host directory /path-on-host-machine/datadir/ has been mounted onto the server’s data directory (/var/lib/mysql) inside the server container. We also assume that, after the server has been started, the required privileges have also been set up for MySQL Enterprise Backup to access the server (see Grant MySQL Privileges to Backup Administrator for details). Use the following steps then to backup and restore a MySQL Server instance.

To backup a MySQL Server instance running in a Docker container using MySQL Enterprise Backup with Docker:

  1. On the same host where the MySQL Server container is running, start another container with an image of MySQL Enterprise Edition to perform a back up with the MySQL Enterprise Backup command backup-to-image. Provide access to the server’s data directory using the bind mount we created in the last step. Also, mount a host directory (/path-on-host-machine/backups/ in this example) onto the storage folder for backups in the container (/data/backups in the example) to persist the backups we are creating. 下面是这个步骤的示例命令:
  1. shell> docker run \
  2. --mount type=bind,src=/path-on-host-machine/datadir/,dst=/var/lib/mysql \
  3. --mount type=bind,src=/path-on-host-machine/backups/,dst=/data/backups \
  4. --rm store/oracle/mysql-enterprise-server:8.0 \
  5. mysqlbackup -umysqlbackup -ppassword --backup-dir=/tmp/backup-tmp --with-timestamp \
  6. --backup-image=/data/backups/db.mbi backup-to-image
  7. [Entrypoint] MySQL Docker Image 8.0.11-1.1.5
  8. MySQL Enterprise Backup version 8.0.11 Linux-4.1.12-61.1.16.el7uek.x86_64-x86_64 [2018-04-08 07:06:45]
  9. Copyright (c) 2003, 2018, Oracle and/or its affiliates. All Rights Reserved.
  10. 180921 17:27:25 MAIN INFO: A thread created with Id '140594390935680'
  11. 180921 17:27:25 MAIN INFO: Starting with following command line ...
  12. ...
  13. -------------------------------------------------------------
  14. Parameters Summary
  15. -------------------------------------------------------------
  16. Start LSN : 29615616
  17. End LSN : 29651854
  18. -------------------------------------------------------------
  19. mysqlbackup completed OK!

It is important to check the end of the output by mysqlbackup to make sure the backup has been completed successfully.

  1. The container exits once the backup job is finished and, with the --rm option used to start it, it is removed after it exits. An image backup has been created, and can be found in the host directory mounted in the last step for storing backups:
  1. shell> ls /tmp/backups
  2. db.mbi

To restore a MySQL Server instance in a Docker container using MySQL Enterprise Backup with Docker:

  1. 停止 MySQL 服务器容器, 这也会停止在内部运行的 MySQL 服务器:
  1. docker stop mysqlserver
  1. On the host, delete all contents in the bind mount for the MySQL Server data directory:
  1. rm -rf /path-on-host-machine/datadir/*
  1. Start a container with an image of MySQL Enterprise Edition to perform the restore with the MySQL Enterprise Backup command copy-back-and-apply-log. Bind-mount the server’s data directory and the storage folder for the backups, like what we did when we backed up the server:
  1. shell> docker run \
  2. --mount type=bind,src=/path-on-host-machine/datadir/,dst=/var/lib/mysql \
  3. --mount type=bind,src=/path-on-host-machine/backups/,dst=/data/backups \
  4. --rm store/oracle/mysql-enterprise-server:8.0 \
  5. mysqlbackup --backup-dir=/tmp/backup-tmp --with-timestamp \
  6. --datadir=/var/lib/mysql --backup-image=/data/backups/db.mbi copy-back-and-apply-log
  7. [Entrypoint] MySQL Docker Image 8.0.11-1.1.5
  8. MySQL Enterprise Backup version 8.0.11 Linux-4.1.12-61.1.16.el7uek.x86_64-x86_64 [2018-04-08 07:06:45]
  9. Copyright (c) 2003, 2018, Oracle and/or its affiliates. All Rights Reserved.
  10. 180921 22:06:52 MAIN INFO: A thread created with Id '139768047519872'
  11. 180921 22:06:52 MAIN INFO: Starting with following command line ...
  12. ...
  13. 180921 22:06:52 PCR1 INFO: We were able to parse ibbackup_logfile up to
  14. lsn 29680612.
  15. 180921 22:06:52 PCR1 INFO: Last MySQL binlog file position 0 155, file name binlog.000003
  16. 180921 22:06:52 PCR1 INFO: The first data file is '/var/lib/mysql/ibdata1'
  17. and the new created log files are at '/var/lib/mysql'
  18. 180921 22:06:52 MAIN INFO: No Keyring file to process.
  19. 180921 22:06:52 MAIN INFO: Apply-log operation completed successfully.
  20. 180921 22:06:52 MAIN INFO: Full Backup has been restored successfully.
  21. mysqlbackup completed OK! with 3 warnings

The container exits once the backup job is finished and, with the --rm option used when starting it, it is removed after it exits.

  1. Restart the server container, which also restarts the restored server:
  1. docker restart mysqlserver

Or, start a new MySQL Server on the restored data directory:

  1. docker run --name=mysqlserver2 \
  2. --mount type=bind,src=/path-on-host-machine/datadir/,dst=/var/lib/mysql \
  3. -d store/oracle/mysql-enterprise-server:8.0

Log on to the server to check that the server is running with the restored data.

Docker 环境变量

当你创建 MySQL 服务器容器时, 你可以使用 --env 选项 (-e) 并指定一个或者多个下列的环境变量来配置 MySQL 实例.

注意

  • 如果你挂载的数据目录不是空的, 那么下列的变量都不会有效果, 因为服务器没有尝试初始化它们(参阅持久化数据和配置更改获取详情). 在容器启动时, 文件夹中任何预先存在的内容, 包括任何旧的服务器配置, 都不会被修改.

MYSQL_USER, MYSQL_PASSWORD: 这些变量用户创建用户并设置密码, 授予通过 MYSQL_DATABASE 变量指定数据库的超级用户权限. 在创建用户时同时需要 MYSQL_USERMYSQL_PASSWORD—如果未设置两个变量中的任何一个, 则忽略零一个变量. 如果同时设置了这两个变量, 但是没有设置 MYSQL_DATABASE, 那么创建的用户没有任何权限.

注意

不需要使用这个机制来创建 root 超级用户, which is created by default with the password set by either one of the mechanisms discussed in the descriptions for MYSQL_ROOT_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD, 除非 MYSQL_ALLOW_EMPTY_PASSWORD 为 true.

  • MYSQL_ROOT_HOST: 默认情况下, MySQL 创建 'root'@'localhost' 账号. This account can only be connected to from inside the container as described in Connecting to MySQL Server from within the Container. 允许其它主机进行 root 连接, 设置此环境变量. 例如, 172.17.0.1, 这是默认的 Docker 网关 IP, 允许运行容器的主机连接. 该选项只接受一个入口, 但是允许通配符(例如, MYSQL_ROOT_HOST=172.*.*.* 或者 MYSQL_ROOT_HOST=%).

  • MYSQL_LOG_CONSOLE: 当变量为 true (这是 MySQL 8.0 服务器容器默认的状态), MySQL 服务器的错误日志被重定向到 stderr, 所以错误日志就进入到 Docker 容器的日志并且可以使用 docker logs mysqld-container 命令查看.

注意

如果服务器配置文件是从主机中挂载的, 则该变量不起作用 (参阅 持久化数据和配置更改 中的 bind-mounting 配置文件).

警告

在命令上设置 root 用户密码是不安全的. 作为显式指定密码的替代方法, you can set the variable with a container file path for a password file, and then mount a file from your host that contains the password at the container file path. 这仍然不是很安全, 密码文件的位置仍然处于公开状态. 最好使用 MYSQL_RANDOM_ROOT_PASSWORDMYSQL_ONETIME_PASSWORD 的默认设置都为 true.

警告

设置此变量为 true 是不安全的, 因为它将使你的 MySQL 实例完全不受保护, 允许任何人获得完整的 root 用户访问权限. 最好使用 MYSQL_RANDOM_ROOT_PASSWORDMYSQL_ONETIME_PASSWORD 的默认设置都为 true.