MySQL 8.4 Docker Compose 部署指南
使用 Docker Compose 一键部署 MySQL 8.4 LTS(官方镜像 `mysql:8.4`),涵盖数据目录持久化、常用环境变量与参数配置、健康检查,并给出等价的 `docker run` 运行方式。本文档已在 `/opt/data/ops/mysql` 目录实测通过
MySQL 8.4 Docker Compose 部署指南
目标:使用 Docker Compose 一键部署 MySQL 8.4 LTS(官方镜像
mysql:8.4),涵盖数据目录持久化、常用环境变量与参数配置、健康检查,并给出等价的docker run运行方式。本文档已在/opt/data/ops/mysql目录实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS
- 系统架构:x86_64
- Docker 版本:Docker Engine 27.x(含 Compose v2 插件)
- 镜像版本:
mysql:8.4(对应 MySQL 8.4.11 LTS,与《Ubuntu 22.04 安装 MySQL 8.0 指南》方案二版本一致) - 容器名称:
mysql-8-4 - 端口映射:宿主机
13306→ 容器3306 - 数据目录:宿主机
/opt/data/ops/mysql/data(挂载到容器/var/lib/mysql) - 部署文件:
/opt/data/ops/mysql/docker-compose.yaml
二、镜像选型说明
| 镜像标签 | 对应版本 | 特点 |
|---|---|---|
mysql:8.4 | MySQL 8.4 LTS(当前最新 LTS 系列) | 长期支持,官方维护 |
mysql:8.0 | MySQL 8.0 系列(已进入生命周期末期) | 老版本,缺少新特性与长期安全更新 |
mysql:latest | 最新稳定版(当前指向 8.4 LTS) | 版本会随上游变化,不建议生产锁定 |
💡 说明:官方镜像仓库为
docker.io/library/mysql。国内拉取可配置阿里云 / daocloud 镜像加速器,或通过中转节点拉取后docker load导入宿主机(本文档实测即采用此方式,镜像已 load 到宿主机)。
三、前置条件
- 已安装 Docker Engine 与 Docker Compose 插件:
docker --version && docker compose version - 已规划数据目录(建议放在独立磁盘,避免系统盘被数据占满)
- 已准备好强密码(禁止使用默认/弱密码,见"六、常用环境变量表"章节)
四、部署步骤
4.1 创建部署目录
sudo mkdir -p /opt/data/ops/mysql
cd /opt/data/ops/mysql
4.2 编写 docker-compose.yaml
将以下内容保存为 /opt/data/ops/mysql/docker-compose.yaml:
# =============================================================================
# MySQL 8.4 (LTS) Docker Compose 部署文件
# 镜像版本:mysql:8.4(对应 MySQL 8.4.11,与《Ubuntu 22.04 安装 MySQL 8.0 指南》方案二一致)
# 使用方式:cd /opt/data/ops/mysql && docker compose up -d
# 密码等敏感值通过环境变量注入,请先 export(见文档"六、常用环境变量表"章节)
# =============================================================================
services:
mysql:
# 镜像版本:8.4 LTS 官方镜像(阿里云/daocloud 镜像源可加速拉取)
image: mysql:8.4
# 容器名称,方便 docker ps / docker logs 定位
container_name: mysql-8-4
# 重启策略:容器异常退出时自动重启(除非手动 stop)
restart: unless-stopped
# ---- 常用环境变量配置(值由外部环境变量注入)----
environment:
- TZ=Asia/Shanghai # 容器时区(与宿主机一致)
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:?请在环境变量中设置} # root 密码(首次初始化生效)
- MYSQL_DATABASE=${MYSQL_DATABASE:-app_db} # 自动创建的默认数据库
- MYSQL_USER=${MYSQL_USER:-app_user} # 自动创建的业务用户
- MYSQL_PASSWORD=${MYSQL_PASSWORD:?请在环境变量中设置} # 业务用户密码
- MYSQL_ROOT_HOST=${MYSQL_ROOT_HOST:-%} # 允许 root 远程登录(% 表示任意主机)
# ---- 常用配置参数(等价于写进 my.cnf)----
# 说明:参数已统一放入 ./conf/my.cnf(见下方 volumes 挂载),
# 修改配置只需编辑该文件后 docker compose restart mysql,无需改 yaml
command:
- --character-set-server=utf8mb4 # 默认字符集 UTF-8
- --collation-server=utf8mb4_unicode_ci # 默认排序规则
- --default-time-zone=+08:00 # 数据库时区(东八区)
- --max-connections=200 # 最大连接数
# ---- 端口映射:宿主机13306 -> 容器3306 ----
ports:
- "13306:3306"
# ---- 数据持久化(重要)----
# ./data 为宿主机数据目录,重启容器数据不丢失
volumes:
- ./data:/var/lib/mysql
# ---- 配置文件持久化(重要)----
# ./conf 为宿主机配置目录,挂载到 /etc/mysql/conf.d 自动加载,
# 编辑 ./conf/my.cnf 后 docker compose restart mysql 即可生效
- ./conf:/etc/mysql/conf.d
# ---- 健康检查:容器内 mysqladmin ping 判断数据库就绪 ----
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-p$$MYSQL_ROOT_PASSWORD"]
interval: 10s # 每 10 秒检查一次
timeout: 5s # 单次检查超时
retries: 10 # 连续 10 次失败视为不健康
start_period: 30s # 启动后 30 秒才开始检查
# 容器日志大小限制,防止磁盘被日志占满
logging:
driver: json-file
options:
max-size: "50m"
max-file: "3"
4.3 设置环境变量并启动
# 注入密码(首次初始化生效,容器重建后需保持一致才能正常读取数据目录)
export MYSQL_ROOT_PASSWORD='your-root-password'
export MYSQL_PASSWORD='your-app-password'
docker compose up -d
💡 说明:
${MYSQL_ROOT_PASSWORD:?请在环境变量中设置}语法表示:若该环境变量未设置,docker compose up会直接报错退出,防止密码缺失导致初始化失败或使用默认值。
4.4 验证部署
# 查看容器状态(healthy 表示健康检查通过)
docker ps --filter name=mysql-8-4
# 连接测试
docker exec -it mysql-8-4 mysql -uroot -p
# 验证字符集与时区
mysql> SHOW VARIABLES LIKE 'character_set_server';
mysql> SHOW VARIABLES LIKE 'time_zone';
五、数据持久化说明
- 数据目录映射:
./data:/var/lib/mysql,MySQL 的库表数据、ibdata、binlog等全部落在宿主机./data目录。 - 配置目录映射:
./conf:/etc/mysql/conf.d,自定义配置落在宿主机./conf目录,修改后重启容器生效(见"八、配置文件持久化"章节)。 - 重启容器(
docker compose restart/docker compose up -d)数据不丢失。 - 删除容器不会删除数据:
docker compose down只移除容器,卷目录./data与./conf仍在;只有docker compose down -v才会删除卷数据。 - 备份:直接对宿主机
./data目录做快照/rsync 即可(建议配合mysqldump逻辑备份双保险)。 - 权限说明:
mysql:8.4镜像内 MySQL 以mysql用户(uid 999)运行,首次启动时镜像会自动对挂载目录做chown,无需手动处理权限。
六、常用环境变量表
| 环境变量 | 默认值 | 说明 |
|---|---|---|
MYSQL_ROOT_PASSWORD | (必填,无默认) | root 用户密码,仅首次初始化数据目录时生效 |
MYSQL_DATABASE | app_db | 首次初始化自动创建的数据库名 |
MYSQL_USER | app_user | 自动创建的业务用户名(与 MYSQL_DATABASE 授权) |
MYSQL_PASSWORD | (必填,无默认) | 业务用户密码 |
MYSQL_ROOT_HOST | % | 允许 root 远程登录的主机(% 表示任意主机,仅建议内网使用) |
TZ | 镜像默认(UTC) | 容器时区,建议与宿主机一致 |
⚠️ 安全提醒:
MYSQL_ROOT_PASSWORD/MYSQL_PASSWORD属于敏感值,务必通过环境变量注入,禁止写入 yaml 明文。生产环境可用 Docker secrets 或密码管理工具注入。
七、常用配置参数说明(command)
| 参数 | 说明 |
|---|---|
--character-set-server=utf8mb4 | 默认字符集,UTF-8 全量(推荐,避免中文乱码) |
--collation-server=utf8mb4_unicode_ci | 默认排序规则 |
--default-time-zone=+08:00 | 数据库会话时区(东八区),与 TZ 配合 |
--max-connections=200 | 最大连接数,按业务规模调整(默认 151) |
💡 说明:
command中的参数等价于写入my.cnf的[mysqld]段。本部署方案已将上述参数同步放入配置文件./conf/my.cnf(见下方"八、配置文件持久化"章节),改参数只需编辑该文件后重启容器。
八、配置文件持久化(conf 挂载)
本方案在 volumes 中挂载了配置目录 ./conf:/etc/mysql/conf.d,实现配置文件持久化,方便后续修改参数而无需改动 yaml:
# 配置文件位于宿主机,可随时编辑
sudo vim /opt/data/ops/mysql/conf/my.cnf
./conf/my.cnf 内容如下([mysqld] 段,与 command 参数保持一致,另附更多常用参数示例):
# MySQL 自定义配置文件(挂载到 /etc/mysql/conf.d/my.cnf,自动加载)
# 修改后重启容器生效:docker compose restart mysql
[mysqld]
# 默认字符集 UTF-8 全量
character-set-server = utf8mb4
# 默认排序规则
collation-server = utf8mb4_unicode_ci
# 数据库会话时区(东八区)
default-time-zone = +08:00
# 最大连接数(默认 151)
max_connections = 200
# 更多常用参数示例(按需取消注释):
# innodb_buffer_pool_size = 1G # InnoDB 缓冲池(建议为物理内存的 60%~70%)
# max_allowed_packet = 64M # 最大单包大小(大字段/大结果集场景)
# slow_query_log = 1 # 开启慢查询日志
# long_query_time = 2 # 慢查询阈值(秒)
💡 说明:镜像会读取
/etc/mysql/conf.d/下所有.cnf文件并追加合并到主配置,无需修改主配置。修改后执行docker compose restart mysql即生效(已验证)。
九、等价 docker run 运行方式
不使用 Compose 时,可用以下 docker run 达到相同效果:
# 先注入环境变量
export MYSQL_ROOT_PASSWORD='your-root-password'
export MYSQL_PASSWORD='your-app-password'
docker run -d \
--name mysql-8-4 \
--restart unless-stopped \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD="$MYSQL_ROOT_PASSWORD" \
-e MYSQL_DATABASE=app_db \
-e MYSQL_USER=app_user \
-e MYSQL_PASSWORD="$MYSQL_PASSWORD" \
-e MYSQL_ROOT_HOST='%' \
-p 13306:3306 \
-v /opt/data/ops/mysql/data:/var/lib/mysql \
-v /opt/data/ops/mysql/conf:/etc/mysql/conf.d \
--health-cmd='mysqladmin ping -h 127.0.0.1 -uroot -p"$MYSQL_ROOT_PASSWORD"' \
--health-interval=10s \
--health-timeout=5s \
--health-retries=10 \
--health-start-period=30s \
mysql:8.4 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci \
--default-time-zone=+08:00 \
--max-connections=200
参数对照:
| Compose 写法 | docker run 写法 |
|---|---|
image: mysql:8.4 | 末尾镜像名 mysql:8.4 |
container_name | --name |
restart: unless-stopped | --restart unless-stopped |
environment | -e KEY=value |
ports: "13306:3306" | -p 13306:3306 |
volumes: ./data:/var/lib/mysql | -v /opt/data/ops/mysql/data:/var/lib/mysql |
volumes: ./conf:/etc/mysql/conf.d | -v /opt/data/ops/mysql/conf:/etc/mysql/conf.d |
healthcheck | --health-cmd / --health-interval 等 |
command | 镜像名之后的附加参数 |
💡 说明:
--health-cmd中"$MYSQL_ROOT_PASSWORD"会被 shell 展开为容器内环境变量值,故无需转义$(与 Compose 中需$$转义不同)。
十、常用运维命令
# 查看日志
docker logs -f mysql-8-4
# 重启容器(数据保留)
docker compose restart
# 停止并移除容器(保留数据)
docker compose down
# 彻底移除容器 + 数据目录(谨慎操作!)
docker compose down -v
十一、常见问题(FAQ)
11.1 端口映射失败:宿主机 13306 已被占用?
修改 ports 为其他宿主机端口,如 "13307:3306"。注意客户端连接地址随之变化。
11.2 修改密码后连接报 Access denied?
MYSQL_ROOT_PASSWORD只在首次初始化数据目录时生效;数据目录已存在时修改该变量不会改变 root 密码。- 已部署后改密请用 SQL:
ALTER USER 'root'@'%' IDENTIFIED BY '新密码'; FLUSH PRIVILEGES;。
11.3 容器反复重启、日志报权限错误?
检查挂载目录权限:sudo chown -R 999:999 /opt/data/ops/mysql/data(uid 999 为镜像内 mysql 用户),或删除损坏的 ./data 目录后重新初始化。
11.4 中文乱码?
确认已传 --character-set-server=utf8mb4,且建库时指定字符集:
CREATE DATABASE app_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
11.5 如何自定义更多参数?
本方案已挂载配置目录 ./conf:/etc/mysql/conf.d,直接编辑 ./conf/my.cnf 的 [mysqld] 段追加参数(如 innodb_buffer_pool_size、slow_query_log),然后 docker compose restart mysql 即生效,无需改动 yaml。镜像会自动加载 /etc/mysql/conf.d/ 下的所有 .cnf 文件并合并到主配置。