我用bitnamicharts/bitnami/mysql at main · bitnami/charts (github.com) 安装的mysql主从,但是从库会因为各种问题失效,甚至可能pod都无法启动,因为bitnami对mysql容器进行了一些封装加了部分脚本,因此与常规mysql修复步骤有些许差异,这里分享下个人修复步骤。

启动从库实例

如果你的mysql从库还能启动,只是slave 状态异常,那可以跳过这部分直接看备份恢复数据章节。这一段是为了让mysql-secondary pod以及pod中的mysql进程能够正常起来。bitnami的从库会在启动时尝试创建主从,而如果主库中binlog文件有缺失或者别的什么原因,都会启动失败。

修复pod有两种方案,一种是直接拷贝主库的数据,一种是在无数据情况下启动从库,通过修改启动参数方式让mysql进程能起来,第二种方式随bitnami镜像更新可能失效,在docker.io/bitnami/mysql:8.0.32-debian-11-r21下测试成功。

拷贝数据方式修复

这种方式由于没有停止数据库直接拷贝文件,会导致binlog中记录和实际数据库文件中存在偏差,如果可以保证拷贝过程中数据库无操作,可以直接在从库中创建主从关系,如果业务没有停机,那么后面还需要进行一次备份还原操作,不然slave即使启动成功,很可能后面由于数据不一致而停止。

停止mysql-secondary实例

1
kubectl scale statefulset mysql-secondary --replicas=0 -n mysql

拷贝文件

进入主库数据目录,可以在容器内操作也可以在挂载了存储的服务器上操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 直接压缩mysql数据目录
tar -cvf data.tar ./data


# 将data.tar文件拷贝到从库的数据目录中

# 备份从库数据文件,起不来删了也关系不大 呵呵
mv data databack

# 解压文件
tar -xvf data.tar

# 删除auto.cnf文件,因为这个文件记录了server-uuid,从库启动的话如果和主库一致会报错
cd data
rm auto.cnf

如果你跟我一样mysql有大量binlog文件,可以不拷贝这些,从库启动日志会报错,关系不大

1
2
3
find directory -type f -name 'mysql-bin.*' ! -name 'mysql-bin.index' -printf "%T@ %p\n" | sort -k1nr | tail -n +2 | cut -d' ' -f2 > exclude_list.txt

tar -cvf data.tar --exclude-from=exclude_list.txt data

启动从库

1
kubectl scale statefulset mysql-secondary --replicas=0 -n mysql

没啥意外应该从库能够起来,此时数据库中没有主从配置,就是一个孤立运行的mysql节点。

修改参数方式启动

修改mysql的初始化脚本,移除删root用户的代码

1
2
3
4
5
6
7
8
9
10
11
kubectl -n mysql edit sts/mysql-secondary

containers:
- args:
- -c
- |-
sed -i 's/DELETE/SELECT user/' /opt/bitnami/scripts/libmysql.sh;
exec bash /opt/bitnami/scripts/mysql/entrypoint.sh /opt/bitnami/scripts/mysql/run.sh
command:
- /bin/bash

修改startupProbe时间,防止手动操作期间被k8s杀掉

initialDelaySeconds: 15000

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
startupProbe:
exec:
command:
- /bin/bash
- -ec
- |
password_aux="${MYSQL_MASTER_ROOT_PASSWORD:-}"
if [[ -f "${MYSQL_MASTER_ROOT_PASSWORD_FILE:-}" ]]; then
password_aux=$(cat "$MYSQL_MASTER_ROOT_PASSWORD_FILE")
fi
mysqladmin status -uroot -p"${password_aux}"
failureThreshold: 15
initialDelaySeconds: 15000
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1

清空data目录,然后重启pod

1
2
3
4
5
kubectl -n mysql exec -it mysql-secondary-0  -- bash
mv /bitnami/mysql/data /bitnami/mysql/data.bak
exit

kubectl -n mysql delete po mysql-secondary-0

重启后从节点mysql的root密码为空

手动重建主从(仅记录)

注意!!!
手动重建主从这里仅仅是给通过拷贝文件方式启动的从库,并且拷贝期间数据库无操作的情况下使用,为了偷个懒不进行后面备份还原动作记录下操作方式而已,保险起见不推荐进行该步骤。

查看mysql主库replicator账号密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@master192 ~]# kubectl describe secret mysql -n mysql
Name: mysql
Namespace: mysql
Labels: app.kubernetes.io/instance=mysql
app.kubernetes.io/managed-by=Helm
app.kubernetes.io/name=mysql
helm.sh/chart=mysql-9.7.1
Annotations: meta.helm.sh/release-name: mysql
meta.helm.sh/release-namespace: mysql

Type: Opaque

Data
====
mysql-password: 6 bytes
mysql-replication-password: 6 bytes
mysql-root-password: 8 bytes
[root@master192 ~]# kubectl get secret mysql -n mysql -o jsonpath="{.data['mysql-replication-password']}" | base64 --decode
sylink[root@master192 ~]#

查看主库binlog文件位置

1
2
3
# 连接mysql primary
mysql -h <ip> -P <port> -u <user> -p
show master status\G
1
2
3
4
5
6
7
8
9
10
# 连接mysql secondary
mysql -h <ip> -P <port> -u <user> -p

# 配置主库连接信息,填写信息获取方式见上
CHANGE MASTER TO MASTER_HOST='mysql-primary', MASTER_USER='replicator', MASTER_PASSWORD='sylink', MASTER_LOG_FILE='mysql-bin.003030', MASTER_LOG_POS=48595838;


# 启动从库
start slave;
show slave status\G

备份恢复数据

从主库中备份数据并进行恢复,之所以要这么搞一下主要是为了数据和binlog记录能对的上。所以不建议用上面手动重建主从的方式进行恢复。

以下操作均在mysql-secondary容器中,当然能用mysql连接也一样的。

备份主库数据

1
2
3
4
kubectl exec -it mysql-secondary-0 -n mysql bash
cd /bitnami/mysql/data/

mysqldump -h mysql-primary -P 3306 --all-databases --master-data -u root -p'ZAQ!2wsx' --compress --single-transaction --verbose > dbdump.db

查看备份文件中的binlog位置,后续从库会从这个位置开始同步数据,如果直接拷贝文件就会容易对不上。

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
head -n 30 dbdump.db 
-- MySQL dump 10.13 Distrib 8.0.32, for Linux (x86_64)
--
-- Host: 192.168.20.22 Database:
-- ------------------------------------------------------
-- Server version 8.0.32

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES UTF8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!50606 SET @OLD_INNODB_STATS_AUTO_RECALC=@@INNODB_STATS_AUTO_RECALC */;
/*!50606 SET GLOBAL INNODB_STATS_AUTO_RECALC=OFF */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Position to start replication or point-in-time recovery from
--

CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.001923', MASTER_LOG_POS=538145901;

--
-- Current Database: `mysql`
--

数据导入从库

1
2
3
4
5
# 导入数据
mysql -uroot -p< dbdump.db

# 查看slave状态
mysql -uroot mysql> SHOW SLAVE STATUS\G; 注意查看下binlog文件位置和文件名,应该和备份文件中一致 Master_Log_File: mysql-bin.001923 Read_Master_Log_Pos: 538145901 Relay_Log_File: mysql-relay-bin.000002

重启slave

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
mysql> START SLAVE;
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> SHOW SLAVE STATUS\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: mysql-primary
Master_User: replicator
Master_Port: 3306
Connect_Retry: 10
Master_Log_File: mysql-bin.001923
Read_Master_Log_Pos: 541551185
Relay_Log_File: mysql-relay-bin.000004
Relay_Log_Pos: 493578
Relay_Master_Log_File: mysql-bin.001923
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: 538639153
Relay_Log_Space: 3406000
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: 484
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: 773
Master_UUID: f5d03e7f-0e80-11ee-a6e1-2aca9d01614a
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Waiting for dependent transaction to commit
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:
Master_public_key_path:
Get_master_public_key: 0
Network_Namespace:
1 row in set, 1 warning (0.00 sec)

验证

主库中新建个测试库或者别的什么操作,从库中查看下,是否也同步创建了。