迁移数据mysql5.7到8.4.11

阶段一:从 5.7 导出所有用户数据库

bash
# 1. 获取所有非系统数据库列表
podman exec mysql-master mysql -uroot -proot -N -e "SHOW DATABASES;" \
| grep -Ev "^(information_schema|performance_schema|mysql|sys)$" > /home/wt/mysql57/dbs.txt

# 2. 循环导出每个数据库到宿主机
while read db; do
echo "正在导出:$db"
podman exec mysql-master mysqldump -uroot -proot \
--databases "$db" \
--routines --events --triggers \
--single-transaction \
--default-character-set=utf8mb4 \
--set-gtid-purged=OFF \
> "/home/wt/mysql57/57_${db}.sql"
done < /home/wt/mysql57/dbs.txt
关键参数:--set-gtid-purged=OFF 对于从 5.7 导出的数据很重要,可以避免将旧的 GTID 信息带入新环境。

阶段二:在 8.0 容器中导入并完成第一次升级

创建8.0.46容器


启动 MySQL 8.0 容器:使用 8.0 的最新版本(如 8.0.40)创建一个临时容器。

podman run -d \
--name mysql80 \
--network mysql-net \
-p 3309:3306 \
-v ~/mysql80/conf/my.cnf:/etc/mysql/conf.d/my.cnf:ro \
-v ~/mysql80/data:/var/lib/mysql \
-v /etc/localtime:/etc/localtime:ro \
-e MYSQL_ROOT_PASSWORD=root \
-e TZ=Asia/Shanghai \
mysql:8.0.46
导入数据:将上一步导出的所有 57_*.sql 文件依次导入到 8.0 容器中。

bash
for f in /home/wt/mysql57/57_*.sql; do
podman exec -i mysql80 mysql -uroot -proot < "$f"
done
完成升级:MySQL 8.0 在启动时会自动执行必要的升级任务,你无需手动运行 mysql_upgrade(该工具已在 8.0.16 中弃用,并在 8.4 中移除)。
导入完成后,你的数据在 8.0 环境中就已经完成了第一次升级。

阶段三:从 8.0 导出,并最终导入到 8.4

从 8.0 重新导出:现在数据已经处于 8.0 格式,再次使用 mysqldump 从 8.0 容器中导出所有用户数据库,生成 80_*.sql 文件。
podman exec mysql80 mysql -uroot -proot -N -e "SHOW DATABASES;" \
| grep -Ev "^(information_schema|performance_schema|mysql|sys)$" \
> ~/mysql80/80-dbs.txt

2.3 方式一:所有库导出到一个文件(推荐)
bash
DBS=$(cat ~/mysql80/80-dbs.txt | tr '\n' ' ')

podman exec mysql80 mysqldump -uroot -proot \
--databases $DBS \
--routines --events --triggers \
--single-transaction \
--default-character-set=utf8mb4 \
--set-gtid-purged=OFF \
--column-statistics=0 \
> ~/mysql80/all_user_dbs.sql

注意参数:--column-statistics=0 是 MySQL 8.0 的 mysqldump 新增的选项,如果不加,
在某些情况下会报 Unknown table 'COLUMN_STATISTICS' 错误。
虽然 8.0 到 8.4 一般不会触发,但加上更稳妥。

在 8.4 容器中导入:启动你最终的 MySQL 8.4.11 容器,并将 80_*.sql 文件导入。
四、将 80_*.sql 导入到 8.4
4.1 方式一:导入单个汇总文件
如果你用的是 2.3 的单文件导出:
bash

在mysql8.4.11master安装好执行导入

podman exec -i mysql-master mysql -uroot -proot \
< ~/mysql80/all_user_dbs.sql

安装8.4.11

在 Ubuntu 上使用 Podman 部署 MySQL 8.4.11 社区版,并配置主从复制、时区和中文支持,并添加配置,数据,日志的映射,开机自动启动

一、环境准备

1.1 创建网络与目录
bash
# 创建专用网络
podman network create mysql-net

# 创建主库目录
mkdir -p ~/mysql-repl/master/{conf,data,logs}
# 创建从库目录
mkdir -p ~/mysql-repl/slave/{conf,data,logs}

# 拉取镜像
podman pull docker.io/library/mysql:8.4.11
1.2 Ubuntu 下调整数据与日志目录权限
MySQL 容器内进程 UID 为 999,Rootless Podman 必须用 podman unshare 调整属主:

bash
podman unshare chown -R 999:999 ~/mysql-repl/master/data ~/mysql-repl/master/logs
podman unshare chown -R 999:999 ~/mysql-repl/slave/data ~/mysql-repl/slave/logs
Ubuntu 使用 AppArmor,挂载时不需要 :Z 标签。

二、主库(Master)配置与启动

2.1 主库配置文件 vim ~/mysql-repl/master/conf/master.cnf
ini
[mysqld]
# ===== 主从复制核心配置 =====
server-id = 1
log-bin = mysql-bin
binlog-ignore-db = mysql
gtid_mode = ON
enforce_gtid_consistency = ON
log_replica_updates = ON
binlog_expire_logs_seconds = 604800
replica_skip_errors = 1062

# ===== 时区配置 =====
default-time-zone = '+08:00'

# ===== 字符集配置(8.4 默认已是 utf8mb4,显式声明更清晰) =====
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

# ===== 日志配置 =====
log-error = /var/log/mysql/error.log
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

#修改日志时间戳时区
log_timestamps = SYSTEM

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4
2.2 启动主库容器
bash
podman run -d \
--name mysql-master \
--network mysql-net \
-p 3307:3306 \
-v ~/mysql-repl/master/conf/master.cnf:/etc/mysql/conf.d/master.cnf:ro \
-v ~/mysql-repl/master/data:/var/lib/mysql \
-v ~/mysql-repl/master/logs:/var/log/mysql \
-v /etc/localtime:/etc/localtime:ro \
-e MYSQL_ROOT_PASSWORD=root \
-e TZ=Asia/Shanghai \
mysql:8.4.11
2.3 创建复制用户
bash
podman exec -it mysql-master mysql -uroot -proot
执行 SQL:

sql
CREATE USER 'repl'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;

-- 验证 GTID 与 server-id
SHOW VARIABLES LIKE 'gtid_mode';
SHOW VARIABLES LIKE 'server_id';
SHOW VARIABLES LIKE 'log_bin';

三、从库(Slave)配置与启动

3.1 从库配置文件 vim ~/mysql-repl/slave/conf/slave.cnf
ini
[mysqld]
# ===== 主从复制核心配置 =====
server-id = 2
relay-log = mysql-relay-bin
gtid_mode = ON
enforce_gtid_consistency = ON
read_only = ON
log_replica_updates = ON
replica_skip_errors = 1062

# ===== 时区配置 =====
default-time-zone = '+08:00'

# ===== 字符集配置 =====
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

# ===== 日志配置 =====
log-error = /var/log/mysql/error.log
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

#修改日志时间戳时区
log_timestamps = SYSTEM

[client]
default-character-set = utf8mb4

[mysql]
default-character-set = utf8mb4
3.2 启动从库容器
bash
podman run -d \
--name mysql-slave \
--network mysql-net \
-p 3308:3306 \
-v ~/mysql-repl/slave/conf/slave.cnf:/etc/mysql/conf.d/slave.cnf:ro \
-v ~/mysql-repl/slave/data:/var/lib/mysql \
-v ~/mysql-repl/slave/logs:/var/log/mysql \
-v /etc/localtime:/etc/localtime:ro \
-e MYSQL_ROOT_PASSWORD=root \
-e TZ=Asia/Shanghai \
mysql:8.4.11


四、同步初始数据(如果主库已有数据)


在从库启动复制前执行:

bash
# 从主库导出(包含 GTID 信息)
podman exec mysql-master mysqldump -uroot -proot \
--all-databases --source-data=2 --set-gtid-purged=ON \
> ~/mysql-repl/dump.sql

# 导入从库
podman exec -i mysql-slave mysql -uroot -proot < ~/mysql-repl/dump.sql
若主库为空库,可跳过此步。

 

五、建立主从复制链路


5.1 在从库配置复制源
bash
podman exec -it mysql-slave mysql -uroot -proot
执行 SQL:

sql
STOP REPLICA;

CHANGE REPLICATION SOURCE TO
SOURCE_HOST = 'mysql-master',
SOURCE_PORT = 3306,
SOURCE_USER = 'repl',
SOURCE_PASSWORD = '123456',
SOURCE_AUTO_POSITION = 1,
GET_SOURCE_PUBLIC_KEY = 1;

START REPLICA;
5.2 验证复制状态
sql
SHOW REPLICA STATUS\G
确保:

Replica_IO_Running: Yes

Replica_SQL_Running: Yes

Seconds_Behind_Source: 0

Last_Error: 为空

Auto_Position: 1

 

六、验证时区与中文


6.1 时区验证
sql
SELECT @@global.time_zone, @@session.time_zone, @@system_time_zone;
SELECT NOW(), CURDATE(), UTC_TIMESTAMP();
期望 @@global.time_zone 为 +08:00,NOW() 返回东八区时间。

6.2 中文验证
sql
CREATE DATABASE IF NOT EXISTS charset_test
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE charset_test;
CREATE TABLE test_chinese (id INT PRIMARY KEY AUTO_INCREMENT, content VARCHAR(255));
INSERT INTO test_chinese (content) VALUES ('中文测试 🎉');
SELECT * FROM test_chinese;
在从库查询相同表,确认数据同步且无乱码。

 

七、主从复制测试


bash
# 主库写入
podman exec -it mysql-master mysql -uroot -proot -e "
CREATE DATABASE IF NOT EXISTS repl_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE repl_test;
CREATE TABLE demo (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
INSERT INTO demo (name) VALUES ('主库写入测试');
"

# 从库验证
podman exec -it mysql-slave mysql -uroot -proot -e "
SELECT * FROM repl_test.demo;
"
若从库能查到数据且 created_at 为东八区时间,则全部配置成功。

 

八、日志查看


错误日志:sudo tail -f ~/mysql-repl/master/logs/error.log 或 ~/mysql-repl/slave/logs/error.log

慢查询日志:tail -f ~/mysql-repl/master/logs/slow.log

容器日志:podman logs mysql-master

 

九、常见问题


问题 原因 解决
容器启动报 Permission denied Ubuntu 下数据/日志目录属主非 999 podman unshare chown -R 999:999 ~/mysql-repl/.../data ~/mysql-repl/.../logs
Replica_IO_Running = Connecting 网络不通或复制用户密码错误 检查容器是否同网络、复制用户是否存在
GTID 不一致导致复制中断 主从 GTID 执行集不匹配 重新导出主库数据并导入从库,确保 --set-gtid-purged=ON
中文乱码 客户端字符集非 utf8mb4 检查 character_set_client/connection/results
时间差 8 小时 时区未生效 检查 default-time-zone、/etc/localtime 挂载、TZ 变量
错误日志未写入文件 8.4 默认输出到 stderr 配置中已指定 log-error,日志会写入映射目录


十、完整目录结构


text
~/mysql-repl/
├── master/
│ ├── conf/master.cnf
│ ├── data/ # MySQL 数据文件
│ └── logs/ # error.log, slow.log
├── slave/
│ ├── conf/slave.cnf
│ ├── data/
│ └── logs/
└── dump.sql # 初始同步用(可选)
所有配置、数据、日志均已映射到宿主机,方便备份、迁移与排查。

本回答由 AI 生成,内容仅供参考,请仔细甄别

 

十一、开机自启:使用 Quadlet(推荐)


Quadlet 是 Podman 官方推荐的现代化方式,通过声明式 .container 文件定义容器,由 systemd 原生接管。

8.1 开启 linger(Rootless 模式必做)
bash
sudo loginctl enable-linger $USER
没有 linger,用户服务会在你登出时停止,也不会在开机时启动。

8.2 创建 Quadlet 目录
bash
mkdir -p ~/.config/containers/systemd/
8.3 定义 Podman 网络(Quadlet 网络单元)
创建 vim ~/.config/containers/systemd/mysql-net.network:

ini
[Network]
NetworkName=mysql-net
.network 文件由 Quadlet 生成 podman network create 命令。如果 .container 文件中引用了 .network 名称,对应的 .network 文件必须存在。

8.4 主库 Quadlet 文件
创建 vim ~/.config/containers/systemd/mysql-master.container:

ini
[Unit]
Description=MySQL 8.4.11 Master Container
After=network-online.target

[Container]
ContainerName=mysql-master
Image=docker.io/library/mysql:8.4.11
PublishPort=3307:3306
Network=mysql-net.network

Volume=%h/mysql-repl/master/conf/master.cnf:/etc/mysql/conf.d/master.cnf:ro
Volume=%h/mysql-repl/master/data:/var/lib/mysql
Volume=%h/mysql-repl/master/logs:/var/log/mysql
Volume=/etc/localtime:/etc/localtime:ro

Environment=MYSQL_ROOT_PASSWORD=root
Environment=TZ=Asia/Shanghai

[Service]
Restart=always

[Install]
WantedBy=default.target
%h 代表当前用户家目录。Volume= 指令等价于 podman run 的 --volume 选项,格式为 宿主机路径:容器路径[:选项]。

8.5 从库 Quadlet 文件
创建 vim ~/.config/containers/systemd/mysql-slave.container:

ini
[Unit]
Description=MySQL 8.4.11 Slave Container
After=network-online.target mysql-master.service
Wants=mysql-master.service

[Container]
ContainerName=mysql-slave
Image=docker.io/library/mysql:8.4.11
PublishPort=3308:3306
Network=mysql-net.network

Volume=%h/mysql-repl/slave/conf/slave.cnf:/etc/mysql/conf.d/slave.cnf:ro
Volume=%h/mysql-repl/slave/data:/var/lib/mysql
Volume=%h/mysql-repl/slave/logs:/var/log/mysql
Volume=/etc/localtime:/etc/localtime:ro

Environment=MYSQL_ROOT_PASSWORD=root
Environment=TZ=Asia/Shanghai

[Service]
Restart=always

[Install]
WantedBy=default.target
启动顺序:After=mysql-master.service 确保从库在主库之后启动,Wants= 建立软依赖。Quadlet 容器依赖通过标准 systemd 指令管理,After= 用于排序,Requires= 用于硬依赖,Wants= 用于软依赖。

8.6 重载 systemd 并启用服务
bash
# 重载用户 systemd 配置,让 Quadlet 生成服务
systemctl --user daemon-reload

# 启用并启动服务
systemctl --user enable mysql-master.service
systemctl --user enable mysql-slave.service
systemctl --user start mysql-master.service
systemctl --user start mysql-slave.service

# 查看状态
systemctl --user status mysql-master.service
systemctl --user status mysql-slave.service
启用后,服务会自动在开机时启动,无需登录。

8.7 清理临时容器(如果之前用 podman run 启动过)
在启用 Quadlet 之前,需要先停止并删除用 podman run 创建的临时容器,避免名称冲突:

bash
podman stop mysql-master mysql-slave
podman rm mysql-master mysql-slave
数据和配置在宿主机目录中,删除容器不会丢失数据。Quadlet 服务启动时会使用相同的数据目录,复制链路配置也保留在数据目录中。

 

十二、完整目录结构


text
~/mysql-repl/
├── master/
│ ├── conf/master.cnf
│ ├── data/ # MySQL 数据文件
│ └── logs/ # error.log, slow.log
├── slave/
│ ├── conf/slave.cnf
│ ├── data/
│ └── logs/
└── dump.sql # 初始同步用(可选)

~/.config/containers/systemd/
├── mysql-repl-net.network
├── mysql-master.container
└── mysql-slave.container


十三、日常运维命令


操作 命令
启动主库 systemctl --user start mysql-master
停止主库 systemctl --user stop mysql-master
查看主库状态 systemctl --user status mysql-master
查看主库日志 journalctl --user -u mysql-master -f
查看 MySQL 错误日志 tail -f ~/mysql-repl/master/logs/error.log
查看 MySQL 慢查询日志 tail -f ~/mysql-repl/master/logs/slow.log
禁用开机自启 systemctl --user disable mysql-master mysql-slave


十四、常见问题排查


问题 原因 解决
容器启动报 Permission denied Ubuntu 下数据/日志目录属主非 999 podman unshare chown -R 999:999 ~/mysql-repl/.../data ~/mysql-repl/.../logs
Replica_IO_Running = Connecting 网络不通或复制用户密码错误 检查容器是否同网络、复制用户是否存在
GTID 不一致导致复制中断 主从 GTID 执行集不匹配 重新导出主库数据并导入从库,确保 --set-gtid-purged=ON
中文乱码 客户端字符集非 utf8mb4 检查 character_set_client/connection/results
时间差 8 小时 时区未生效 检查 default-time-zone、/etc/localtime 挂载、TZ 变量
Quadlet 服务未生成 .container 文件语法错误 systemctl --user daemon-reload 后查看 journalctl --user -xe 的错误信息
从库复制链路断开 主库重建后 binlog 文件变化 重新执行 CHANGE REPLICATION SOURCE TO 并 START REPLICA
开机后服务未启动 linger 未启用 sudo loginctl enable-linger $USER


十五、从库启动依赖说明


Quadlet 的 After= 和 Wants= 只保证 systemd 单元的启动顺序,不保证主库完全就绪后再启动从库。如果开机时主库启动较慢,从库可能在主库完全就绪前就尝试连接复制。应对措施:

从库配置 Restart=always:从库复制线程在连接失败后会自动重试。

在从库中设置 SOURCE_CONNECT_RETRY:可在 CHANGE REPLICATION SOURCE TO 中增加 SOURCE_CONNECT_RETRY=10 和 SOURCE_RETRY_COUNT=86400,让从库持续重试连接。

验证方式:开机后执行 podman exec -it mysql-slave mysql -uroot -pRoot@123456 -e "SHOW REPLICA STATUS\G",确认 Replica_IO_Running 和 Replica_SQL_Running 均为 Yes。

本回答由 AI 生成,内容仅供参考,请仔细甄别

 

posted on 2026-10-09 00:07  wtsgtc  阅读(6)  评论(0)    收藏  举报