目录

基于 Docker Compose 部署 MySQL 8.0 生产实践指南(Kylin V10 / RHEL 系列)| 附完整 yml 与运维命令

环境声明:本文基于以下已完成的环境进行部署操作

  • 操作系统:Kylin V10 / CentOS / RHEL 系列
  • Docker:25.0.0(已安装,systemd 托管)
  • Docker Compose:v2.24.1(插件模式)
  • MySQL 8.0 镜像:已通过 docker load 导入本地
1
2
3
4
5
6
7
8
9
[root@master ~]# docker --version
Docker version 25.0.0, build e758fe5

[root@master ~]# docker compose version
Docker Compose version v2.24.1

[root@master ~]# docker images | grep mysql
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
mysql        8.0       6c55ddbef969   22 months ago   591MB

一、安装 MySQL 客户端

在 Kylin V10 及 RedHat 系列(CentOS、RHEL、Rocky、AlmaLinux)中,MySQL 客户端已集成在 MariaDB 软件包中,无需单独安装 MySQL 官方客户端。

1
2
3
4
5
# Kylin V10 / CentOS / RHEL 系列统一使用以下方式安装
yum install -y mariadb

# 或者(RHEL 8+ / Kylin V10 SP2+)
dnf install -y mariadb

安装完成后验证:

1
2
3
>$ mysql --version
mysql  Ver 8.0.26 for Linux on x86_64 (Source distribution)
# 输出示例:mysql  Ver 15.1 Distrib 10.x.x-MariaDB, for Linux (x86_64)

💡 说明:MariaDB 客户端与 MySQL 8.0 完全兼容,可正常连接和操作 MySQL 8.0 服务。Kylin V10 默认源中已包含该包,离线环境可使用 rpm -ivh 安装。


二、目录规划

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 创建标准目录结构
mkdir -p /opt/docker/mysql/{data,conf,logs,backup}

# 设置 MySQL 容器运行用户权限(UID 999)
chown -R 999:999 /opt/docker/mysql/data
chown -R 999:999 /opt/docker/mysql/logs

# 最终目录结构
/opt/docker/mysql/
├── docker-compose.yml    # 编排文件
├── backup.sh             # 自动备份脚本
├── conf/
│   └── my.cnf            # MySQL 主配置文件
├── data/                 # 数据文件持久化(自动生成)
├── logs/                 # 错误日志 / 慢查询日志
└── backup/               # 备份文件存放
信息
MySQL 官方镜像内部运行用户 UID/GID 为 999

三、MySQL 配置文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
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
41
42
43
44
45
46
47
48
cat > /opt/docker/mysql/conf/my.cnf << 'EOF'
[mysqld]
# ===== 基础 =====
server-id                = 1
port                     = 3306
bind-address             = 0.0.0.0
default-authentication-plugin = mysql_native_password

# ===== 字符集与时区 =====
character-set-server     = utf8mb4
collation-server         = utf8mb4_general_ci
default-time-zone        = '+08:00'

# ===== 连接 =====
max_connections          = 500
max_connect_errors       = 100000
wait_timeout             = 28800
interactive_timeout      = 28800

# ===== InnoDB =====
innodb_buffer_pool_size  = 1G
innodb_log_file_size     = 256M
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table    = 1

# ===== 慢查询 =====
slow_query_log           = 1
slow_query_log_file      = /var/log/mysql/slow.log
long_query_time          = 2

# ===== Binlog(备份 / 主从) =====
log-bin                  = mysql-bin
binlog_format            = ROW
binlog_expire_logs_seconds = 604800
max_binlog_size          = 256M

# ===== 其他 =====
skip-name-resolve
lower_case_table_names   = 1
sql_mode                 = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
explicit_defaults_for_timestamp = 1

[client]
default-character-set    = utf8mb4

[mysql]
default-character-set    = utf8mb4
EOF

⚠️ innodb_buffer_pool_size 调优参考:数据库专用机设为物理内存的 60%~70%,混部场景设为 30%~40%。


四、docker-compose.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
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
cat > /opt/docker/mysql/docker-compose.yml << 'EOF'
services:
  mysql:
    image: mysql:8.0
    container_name: mysql8
    restart: always
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "YourStr0ng!Pass@2026"
      MYSQL_DATABASE: "app_db"
      MYSQL_USER: "app_user"
      MYSQL_PASSWORD: "AppUs3r!Pass@2026"
      TZ: "Asia/Shanghai"
    volumes:
      - ./data:/var/lib/mysql
      - ./conf/my.cnf:/etc/mysql/my.cnf:ro
      - ./logs:/var/log/mysql
      - ./backup:/backup
    command:
      - --default-authentication-plugin=mysql_native_password
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-p$$MYSQL_ROOT_PASSWORD"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    deploy:
      resources:
        limits:
          memory: 2G
          cpus: "2.0"
        reservations:
          memory: 512M
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "3"
EOF

五、启动服务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
cd /opt/docker/mysql

# 启动
docker compose up -d

# 查看状态(首次初始化约 10~30 秒)
docker compose ps

# 查看初始化日志
docker compose logs -f mysql

等待 docker compose ps 中 STATUS 显示 (healthy) 即表示 MySQL 已就绪:

1
2
NAME      IMAGE       STATUS                   PORTS
mysql8    mysql:8.0   Up 30 seconds (healthy)  0.0.0.0:3306->3306/tcp

六、验证部署

6.1 第一步:进入容器内部验证(无需客户端)

部署完成后,首先通过 docker exec 进入容器确认 MySQL 正常运行:

1
2
# 进入 MySQL 命令行
docker exec -it mysql8 mysql -uroot -p'YourStr0ng!Pass@2026'

在 MySQL 终端中执行验证:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
-- 确认版本
SELECT VERSION();

-- 确认时区
SELECT NOW();

-- 确认字符集
SHOW VARIABLES LIKE 'character_set%';

-- 确认数据库已创建
SHOW DATABASES;

-- 确认用户
SELECT user, host FROM mysql.user;

-- 退出
exit;

6.2 第二步:使用宿主机 MySQL 客户端连接(日常运维)

验证容器内部正常后,后续统一使用宿主机安装的 mysql 客户端进行操作:

1
2
# 注意:必须使用 -h 127.0.0.1,不能省略(否则走 socket 会报错)
mysql -h 127.0.0.1 -uroot -p'YourStr0ng!Pass@2026' -P3306 -e "SELECT VERSION();"

输出:

1
2
3
4
5
+-----------+
| VERSION() |
+-----------+
| 8.0.40    |
+-----------+

⚠️ 重要:Docker 部署的 MySQL,宿主机连接时必须指定 -h 127.0.0.1
直接执行 mysql -uroot -p 会尝试通过 Unix Socket 连接,而 socket 文件在容器内部,宿主机上不存在,将报 ERROR 2002

6.3 设置连接别名(提升效率)

1
2
3
4
5
6
7
8
cat >> /etc/profile.d/mysql-alias.sh << 'EOF'
alias dmysql='mysql -h 127.0.0.1 -P 3306'
EOF

source /etc/profile.d/mysql-alias.sh

# 之后直接使用
mysql -uroot -p'YourStr0ng!Pass@2026' -e "SHOW DATABASES;"

七、运维常用命令

7.1 容器管理

1
2
3
4
5
6
7
8
cd /opt/docker/mysql

docker compose up -d        # 启动
docker compose stop         # 停止
docker compose restart      # 重启
docker compose down         # 停止并删除容器(数据保留)
docker compose logs -f --tail=100 mysql   # 查看日志
docker stats mysql8 --no-stream            # 资源占用

7.2 日常 SQL 操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 执行单条 SQL
mysql -h 127.0.0.1 -uroot -p'YourStr0ng!Pass@2026' -e "SHOW DATABASES;"

# 查看连接数
mysql -h 127.0.0.1 -uroot -p'YourStr0ng!Pass@2026' -e "SHOW STATUS LIKE 'Threads_connected';"

# 查看当前进程
mysql -h 127.0.0.1 -uroot -p'YourStr0ng!Pass@2026' -e "SHOW FULL PROCESSLIST;"

# 查看慢查询数
mysql -h 127.0.0.1 -uroot -p'YourStr0ng!Pass@2026' -e "SHOW GLOBAL STATUS LIKE 'Slow_queries';"

7.3 日志查看

1
2
3
4
5
6
7
8
# 容器日志
docker compose logs --tail=50 mysql

# MySQL 错误日志
tail -f /opt/docker/mysql/logs/error.log

# 慢查询日志
tail -f /opt/docker/mysql/logs/slow.log

7.4 备份与恢复

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 全库备份
mysqldump -h 127.0.0.1 -uroot -p'YourStr0ng!Pass@2026' \
  --all-databases --single-transaction --routines --triggers --events \
  | gzip > /opt/docker/mysql/backup/all_db_$(date +%Y%m%d_%H%M%S).sql.gz

# 单库备份
mysqldump -h 127.0.0.1 -uroot -p'YourStr0ng!Pass@2026' \
  --single-transaction app_db \
  | gzip > /opt/docker/mysql/backup/app_db_$(date +%Y%m%d_%H%M%S).sql.gz

# 恢复
gunzip < /opt/docker/mysql/backup/app_db_20260811.sql.gz \
  | mysql -h 127.0.0.1 -uroot -p'YourStr0ng!Pass@2026' app_db

7.5 自动备份脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
cat > /opt/docker/mysql/backup.sh << 'EOF'
#!/bin/bash
BACKUP_DIR="/opt/docker/mysql/backup"
DATE=$(date +%Y%m%d_%H%M%S)
KEEP_DAYS=7

mysqldump -h 127.0.0.1 -uroot -p'YourStr0ng!Pass@2026' \
  --all-databases --single-transaction --routines --triggers --events \
  | gzip > ${BACKUP_DIR}/all_db_${DATE}.sql.gz

# 清理过期备份
find ${BACKUP_DIR} -name "*.sql.gz" -mtime +${KEEP_DAYS} -delete

echo "[$(date)] Backup completed: all_db_${DATE}.sql.gz" >> ${BACKUP_DIR}/backup.log
EOF

chmod +x /opt/docker/mysql/backup.sh

# 添加定时任务:每天凌晨 2 点执行
echo "0 2 * * * /opt/docker/mysql/backup.sh" | crontab -

7.6 配置变更

1
2
3
4
5
6
7
8
9
# 修改配置
vim /opt/docker/mysql/conf/my.cnf

# 重启生效
docker compose restart mysql

# 部分参数可动态修改(无需重启)
mysql -h 127.0.0.1 -uroot -p'YourStr0ng!Pass@2026' \
  -e "SET GLOBAL max_connections = 1000;"

八、生产环境使用建议

8.1 资源与性能

建议项说明
innodb_buffer_pool_size根据实际内存调整,专用机 60%~70%,混部 30%~40%
deploy.resources.limits必须设置内存上限,防止 OOM 影响宿主机其他服务
数据目录磁盘建议使用独立磁盘或 SSD 挂载到 /opt/docker/mysql/data
日志轮转logging.max-size + max-file 已配置,防止磁盘打满

8.2 数据安全

建议项说明
备份策略全量备份(每日)+ Binlog 增量(实时),保留 7 天
备份验证每周至少恢复一次备份到测试环境验证完整性
密码管理不要明文写在脚本中,使用 .env 文件或 Vault
Binlog已开启 ROW 模式,支持基于时间点恢复(PITR)

8.3 高可用与容灾

建议项说明
restart: always已配置,宿主机重启后自动拉起
主从复制生产环境建议至少一主一从,Binlog 已就绪
监控告警接入 Prometheus + mysqld_exporter,监控连接数、慢查询、复制延迟
异地备份备份文件定期同步至对象存储或异地服务器

8.4 运维规范

建议项说明
禁止 docker compose down -v会删除数据卷,导致数据永久丢失
变更走流程修改 my.cnfdocker-compose.yml 前先备份原文件
版本锁定镜像使用 mysql:8.0 固定大版本,避免意外升级到 8.4
定期巡检每周检查磁盘用量、备份完整性、慢查询 TOP 10

8.5 密码管理(.env 方式)

1
2
3
4
5
6
7
8
9
# 创建环境变量文件
cat > /opt/docker/mysql/.env << 'EOF'
MYSQL_ROOT_PASSWORD=YourStr0ng!Pass@2026
MYSQL_DATABASE=app_db
MYSQL_USER=app_user
MYSQL_PASSWORD=AppUs3r!Pass@2026
EOF

chmod 600 /opt/docker/mysql/.env

docker-compose.yml 中引用:

1
2
3
4
5
environment:
  MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
  MYSQL_DATABASE: ${MYSQL_DATABASE}
  MYSQL_USER: ${MYSQL_USER}
  MYSQL_PASSWORD: ${MYSQL_PASSWORD}

好处:密码不进入 Git 仓库,.env 文件加入 .gitignore


九、故障排查速查

症状排查命令常见原因
容器启动失败docker compose logs mysql配置语法错误 / 端口占用
ERROR 2002确认使用 -h 127.0.0.1未指定 host,走了 socket
Permission deniedls -la /opt/docker/mysql/data目录属主非 999:999
端口冲突ss -tlnp | grep 3306宿主机已有服务占用
容器反复重启docker inspect mysql8 查看 StateOOM / 配置错误
初始化超时检查 start_period 是否 ≥ 30s首次初始化 data 目录慢

十、最终文件清单

1
2
3
4
5
6
7
8
9
/opt/docker/mysql/
├── docker-compose.yml      # 编排定义
├── .env                    # 密码等敏感信息
├── backup.sh               # 自动备份脚本
├── conf/
│   └── my.cnf              # MySQL 配置
├── data/                   # 数据(自动产生)
├── logs/                   # 日志(自动产生)
└── backup/                 # 备份文件

部署完成后,您即拥有一套数据持久化、自动拉起、定时备份、日志可追溯的生产级 MySQL 8.0 容器化实例。