掘金 后端 ( ) • 2024-04-23 13:24

Docker 最佳实战:Docker 部署主从复制模式 MySQL 实战

2024 年云原生运维实战文档 99 篇原创计划 第 007 篇 |Docker 最佳实战「2024」系列 第 007 篇

前言

你好,欢迎来到运维有术

今天分享的内容是 Docker 最佳实战「2024」 系列文档中的 Docker 部署主从复制模式 MySQL 实战

内容导图

docker-replica-mysql-mindmap

实战服务器配置 (架构 1:1 复刻小规模生产环境,配置略有不同)

主机名 IP CPU(核) 内存(GB) 系统盘(GB) 数据盘(GB) 用途 docker-node-1 192.168.9.81 4 16 40 100 Docker 节点 1 docker-node-2 192.168.9.82 4 16 40 100 Docker 节点 2 docker-node-3 192.168.9.83 4 16 40 100 Docker 节点 3 合计 3 12 48 120 300

实战环境涉及软件版本信息

  • 操作系统:openEuler 22.03 LTS SP3
  • Docker:24.0.7
  • Containerd:1.6.27
  • MySQL:5.7.44

1. 前提说明

上一期我们完成了单节点 MySQL 部署实战。

本期我们来完成生产环境 MySQL 高可用最常用的解决方案之主从复制 MySQL 部署实战。

主从模式 MySQL 部署流程与单节点 MySQL 基本一致,区别只有两点:

  • 配置文件 : 主从复制相关的配置项不同
  • 同步配置 : 从节点手动执行命令完成主从同步的配置

提示 : 主从复制的英文术语已经变更为 SourceReplica

2. 安装部署主 (Source) 节点

docker-node-1 节点部署 MySQL 主节点服务。

2.1 创建 MySQL 数据目录

mkdir -p /data/containers/mysql/{data,config}
  • data 目录:存储容器持久化数据
  • config 目录: 配置文件目录

2.2 创建 MySQL 自定义配置文件

默认安装的 MySQL 使用的 my.cnf 配置文件,适配的业务场景有限,所以自定义 MySQL 配置文件是必然要做的一项配置。

这里我随机找了一份配置文件,仅仅是为了实现自定义配置的功能。生产环境一定要根据使用场景自定义配置文件。

  • 创建自定义 MySQL 配置文件,vi /data/containers/mysql/config/mysqld.cnf
[mysqld]
# performance settings
lock_wait_timeout = 3600
open_files_limit = 65535
back_log = 1024
max_connections = 2048
max_connect_errors = 1000000
table_open_cache = 1024
table_definition_cache = 1024
thread_stack = 512K
sort_buffer_size = 4M
join_buffer_size = 4M
read_buffer_size = 8M
read_rnd_buffer_size = 4M
bulk_insert_buffer_size = 64M
thread_cache_size = 768
interactive_timeout = 600
wait_timeout = 600
tmp_table_size = 32M
max_heap_table_size = 32M
innodb_open_files = 1024
​
# TLS 配置
tls_version = TLSv1.2
​
# Replication settings
server_id = 1
log_bin = mysql-bin
log_bin_index = mysql-bin.index
binlog_format = row

2.3 创建 docker-compose 文件

  • 编辑文件,vi /data/containers/mysql/docker-compose.yml
name: 'mysql'
services:
  mysql:
    container_name: mysql
    image: mysql:5.7.44
    restart: always
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    environment:
      - TZ=Asia/Shanghai
      - MYSQL_ROOT_PASSWORD=Db@2024!
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/data:/var/lib/mysql
      - ${DOCKER_VOLUME_DIRECTORY:-.}/config:/etc/mysql/conf.d/
    networks:
      - app-tier
    ports:
      - 3306:3306
​
networks:
  app-tier:
    name: app-tier
    driver: bridge
    #ipam:
    #  config:
    #    - subnet: 172.22.1.0/24

参数说明:

  • MYSQL_ROOT_PASSWORDD 默认管理员 root 用户密码
  • volumes 将自定义的 MySQL 配置文件挂载到容器中的 /etc/mysql/conf.d/ 目录下
  • ulimits 设置最大的文件打开数,用于提高 MySQL 服务的性能
  • ipam 配置了 app-tier 的网络地址,本文注释了,生产环境建议合理规划配置。

2.4 创建并启动 MySQL 服务

  • 启动服务
cd /data/containers/mysql
docker compose up -d
  • 正确启动的结果如下
[root@docker-node-1 mysql]# docker compose up -d
[+] Running 1/2
 ⠸ Network app-tier  Created                                                                                                                                    0.4s
 ✔ Container mysql   Started 

2.5 验证容器状态

  • 查看 mysql 容器状态
[root@docker-node-1 mysql]# docker compose ps
NAME      IMAGE          COMMAND                  SERVICE   CREATED          STATUS          PORTS
mysql     mysql:5.7.44   "docker-entrypoint.s…"   mysql     36 seconds ago   Up 35 seconds   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp
  • 查看 mysql 服务日志
# 通过日志查看 mysql 是否有异常,结果略
docker compose logs -f

2.6 MySQL 服务可用性测试

为了测试 MySQL 服务的可用性,利用 Docker 创建一个 MySQL 客户端容器实例,并执行几个简单的查询命令。

  • 创建 MySQL 客户端实例
docker run -it --rm --network app-tier mysql:5.7.44 mysql -h192.168.9.81 -uroot -p

说明: 按提示说明输入密码进入 MySQL 控制台。

2.7 验证 MySQL 配置

  • 验证自定义配置是否生效
mysql> show variables like '%max_conn%';
+--------------------+---------+
| Variable_name      | Value   |
+--------------------+---------+
| max_connect_errors | 1000000 |
| max_connections    | 2048    |
+--------------------+---------+
2 rows in set (0.00 sec)

2.8 查询主节点状态

查询当前 MySQL 主节点的状态。

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 |      154 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

3. 安装部署从 (Replica) 节点

docker-node-2 节点部署 MySQL 从节点服务。

3.1 创建 MySQL 数据目录

mkdir -p /data/containers/mysql/{data,config}
  • data 目录:存储容器持久化数据
  • config 目录: 配置文件目录

3.2 创建 MySQL 自定义配置文件

直接复制主节点的自定义配置文件进行修改。生产环境一定要根据使用场景自定义配置文件。

  • 创建自定义 MySQL 配置文件,vi /data/containers/mysql/config/mysqld.cnf
[mysqld]
# performance settings
lock_wait_timeout = 3600
open_files_limit = 65535
back_log = 1024
max_connections = 2048
max_connect_errors = 1000000
table_open_cache = 1024
table_definition_cache = 1024
thread_stack = 512K
sort_buffer_size = 4M
join_buffer_size = 4M
read_buffer_size = 8M
read_rnd_buffer_size = 4M
bulk_insert_buffer_size = 64M
thread_cache_size = 768
interactive_timeout = 600
wait_timeout = 600
tmp_table_size = 32M
max_heap_table_size = 32M
innodb_open_files = 1024
​
# TLS 配置
tls_version = TLSv1.2
​
# Replication settings
server_id = 2
log_bin = mysql-bin
log_bin_index = mysql-bin.index
binlog_format = row
relay-log = mysql-relay-bin
relay-log-index = mysql-relay-bin.index
skip_slave_start = 1
log_slave_updates = 1
read_only = 1

3.3 创建 docker-compose 文件

  • 编辑文件,vi /data/containers/mysql/docker-compose.yml
name: 'mysql'
services:
  mysql:
    container_name: mysql
    image: mysql:5.7.44
    restart: always
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    environment:
      - TZ=Asia/Shanghai
      - MYSQL_ROOT_PASSWORD=Db@2024!
    volumes:
      - ${DOCKER_VOLUME_DIRECTORY:-.}/data:/var/lib/mysql
      - ${DOCKER_VOLUME_DIRECTORY:-.}/config:/etc/mysql/conf.d/
    networks:
      - app-tier
    ports:
      - 3306:3306
​
networks:
  app-tier:
    name: app-tier
    driver: bridge
    #ipam:
    #  config:
    #    - subnet: 172.22.1.0/24

3.4 创建并启动 MySQL 服务

  • 启动服务
cd /data/containers/mysql
docker compose up -d

3.5 验证容器状态

  • 查看 mysql 容器状态
[root@docker-node-2 mysql]# docker compose ps
NAME      IMAGE          COMMAND                  SERVICE   CREATED          STATUS          PORTS
mysql     mysql:5.7.44   "docker-entrypoint.s…"   mysql     20 seconds ago   Up 19 seconds   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp
  • 查看 mysql 服务日志
# 通过日志查看 mysql 是否有异常,结果略
docker compose logs -f

3.6 MySQL 服务可用性测试

  • 创建 MySQL 客户端实例
docker run -it --rm --network app-tier mysql:5.7.44 mysql -h192.168.9.82 -uroot -p

说明: MySQL 主机 IP 要使用从节点的 IP

3.7 验证 MySQL 配置

  • 验证自定义配置是否生效
mysql> show variables like '%max_conn%';
+--------------------+---------+
| Variable_name      | Value   |
+--------------------+---------+
| max_connect_errors | 1000000 |
| max_connections    | 2048    |
+--------------------+---------+
2 rows in set (0.01 sec)

3.8 查询从节点状态

查询当前 MySQL 从节点的状态。

mysql> show slave status;
Empty set (0.00 sec)

说明 : 因为还没有配置主从同步,所以现在的状态是正确的。

4. 配置主从同步

4.1 创建主从同步用户

在主服务器上创建同步使用的用户并赋予指定的权限。

-- 创建用户
CREATE USER 'repuser'@'192.168.9.82' IDENTIFIED BY 'password';
​
-- 赋予权限
GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'repuser'@'192.168.9.82';
​
-- 刷新权限
FLUSH PRIVILEGES;

说明:

  • repuser: 同步用户,实际使用中请替换
  • password: 同步用户的密码,实际使用中请替换
  • 192.168.9.82: 从节点服务器 IP,实际使用中请替换

4.2 查询 Master 当前状态

在主服务器上执行

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 |      787 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

注意 : 记录 mysql-bin.000003 和 787,下面会用到

4.3 配置主从同步

在从服务器上,执行下面的主从同步配置命令。

请注意,MySQL 语句的执行,需要先连接到从节点的 MySQL 管理控制台,具体命令参考上文。

  • 配置主从同步
mysql> change master to master_host='192.168.9.81',master_user='repuser',master_password='password',MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=787;

说明:

  • master_host 主节点 IP
  • master_user 同步用户
  • master_password 同步用户密码
  • MASTER_LOG_FILE 对应主服务器上查询 Master 状态的 File 值
  • MASTER_LOG_POS 对应主服务器上查询 Master 状态的 Position 值
  • 正确的执行结果如下:
# 执行同步语句
mysql> change master to master_host='192.168.9.81',master_user='repuser',master_password='password',MASTER_LOG_FILE='mysql-bin.000003',MASTER_LOG_POS=787;
Query OK, 0 rows affected, 1 warning (0.03 sec)
  • 开启同步
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

4.4 验证主从同步状态

  • 查看同步状态
mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.9.81
                  Master_User: repuser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 787
               Relay_Log_File: mysql-relay-bin.000002
                Relay_Log_Pos: 320
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 787
              Relay_Log_Space: 527
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
                  Master_UUID: c7f31912-010c-11ef-8dd0-0242ac130002
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
1 row in set (0.00 sec)
​
ERROR:
No query specified

注意: 以下返回值的内容

  • Slave_IO_Running Yes
  • Slave_SQL_Running Yes
  • Slave_SQL_Running_State Slave has read all relay log; waiting for the slave I/O thread to update it
  • 主数据库创建测试数据库,从库查看是否创建成功
--- 主库执行创建
mysql> create database opsxlab;
Query OK, 1 row affected (0.01 sec)
​
--- 从库执行查询
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| opsxlab            |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
​
--- 从库查看同步后的 slave 状态
mysql> show slave status\G;
... 此处有删减,重点看 Running State
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates

5. 自动化 Shell 脚本

文章中所有步骤,已全部编排为自动化脚本,因篇幅限制,不在此文档中展示。

星球会员请到专属代码仓库下载(价值内容,仅星球会员专享)。

6. 常见问题

6.1 问题 1

  • 问题现象

MySQL 日志里有如下告警信息 :

[Warning] A deprecated TLS version TLSv1 is enabled. Please use TLSv1.2 or higher.
[Warning] A deprecated TLS version TLSv1.1 is enabled. Please use TLSv1.2 or higher.
  • 解决方案

这个信息只是 TLS 配置的告警信息,不影响实际使用。从 MySQL 5.7.35 开始,TLSv1 和 TLSv1.1 连接协议已弃用,使用 TLS 1.2 几更高版本加密客户端与 MySQL 数据库实例的连接,并且在未来的 MySQL 版本中将删除对它们的支持。

MySQL 进行 SSL/TLS 连接的更多信息,请参阅 MySQL 文档中的MySQL使用加密连接

# 在 my.cnf 配置文件中添加配置项,设置仅允许 tls 1.2, 可通过逗号设置多个 tls 版本
echo "tls_version = TLSv1.2" >> /etc/my.cnf 

6.2 问题 2

  • 问题现象

MySQL 日志里有如下告警信息 :

[Warning] Could not increase number of max_open_files to more than 64 (request: 65535)
  • 解决方案

由于容器启动时没有使用 ulimit 设置文件资源限制,因此受默认的文件描述符限制, mysql 配置文件中的 open_files_limit 配置项不生效。需要在启动容器时增加 ulimits 配置项。

# 默认的 ulimit 配置,看着很大实际没生效。
bash-4.2# ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 29604
max locked memory       (kbytes, -l) 65536
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1073741816
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
​
# 在 docker-compose.yml 文件中加入以下内容
ulimits:
      nofile:
        soft: 65536
        hard: 65536

7. 总结

本文分享了基于 Docker 官方提供的 MySQL 镜像部署 MySQL 主从服务的详细流程及注意事项。主要内容概括如下:

  • 主节点 MySQL 服务部署
  • 从节点 MySQL 服务部署
  • MySQL 主从复制配置及验证测试
  • 自定义 MySQL 配置文件的实现方案
  • MySQL 服务可用性验证测试

免责声明:

  • 笔者水平有限,尽管经过多次验证和检查,尽力确保内容的准确性,但仍可能存在疏漏之处。敬请业界专家大佬不吝指教。
  • 本文所述内容仅通过实战环境验证测试,读者可学习、借鉴,但严禁直接用于生产环境由此引发的任何问题,作者概不负责

Get 本文实战视频(请注意,文档视频异步发行,请先关注)

结束语

如果你喜欢本文,请分享、收藏、点赞、评论! 请持续关注 @运维有术,及时收看更多好文!

欢迎加入 「运维有术·云原生实战训练营」 ,获取更多的 KubeSphere、Kubernetes、云原生运维、自动化运维、AI 大模型等实战技能。未来运维生涯始终有我坐在你的副驾

版权声明

  • 所有内容均属于原创,感谢阅读、收藏,转载请联系授权,未经授权不得转载