Theme NexT works best with JavaScript enabled

Hexo-ytliangc

愿有岁月可回首,且以深情共白头

0%

kubernetes安装MySql 5.7主从复制集群

部署原理

使用 statefulset控制器部署mysql主从集群的原理如下图所示:

Snipaste_2020-07-06_21-35-04.png

官方地址: Run a Replicated Stateful

参考博客:CSDN博客 阿里云博客

使用 statefulset控制器部署mysql主从集群

首先从资源清单创建ConfigMap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@master-dev mysql_cluster]# cat mysql-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql
labels:
app: mysql
data:
master.cnf: |
# Apply this config only on the master.
[mysqld]
log-bin
slave.cnf: |
# Apply this config only on slaves.
[mysqld]
super-read-only

创建Service,提供服务的访问和负载均衡

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
# Headless service for stable DNS entries of StatefulSet members.
apiVersion: v1
kind: Service
metadata:
name: mysql
labels:
app: mysql
spec:
ports:
- name: mysql
port: 3306
clusterIP: None
selector:
app: mysql
---
# Client service for connecting to any MySQL instance for reads.
# For writes, you must instead connect to the master: mysql-0.mysql.
apiVersion: v1
kind: Service
metadata:
name: mysql-read
labels:
app: mysql
spec:
ports:
- name: mysql
port: 3306
selector:
app: mysql


[root@master-dev mysql_cluster]# kubectl apply -f mysql-services.yaml
service/mysql created
service/mysql-read created
[root@master-dev mysql_cluster]# kubectl get svc | grep mysql
mysql ClusterIP None <none> 3306/TCP 1s
mysql-read ClusterIP 10.111.232.160 <none> 3306/TCP 1s

部署statefulset控制器创建Pod

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
serviceName: mysql
replicas: 3
template:
metadata:
labels:
app: mysql
spec:
initContainers:
- name: init-mysql
image: registry.cn-hangzhou.aliyuncs.com/public_ns/mysql:5.7
command:
- bash
- "-c"
- |
set -ex
# Generate mysql server-id from pod ordinal index.
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
echo [mysqld] > /mnt/conf.d/server-id.cnf
# Add an offset to avoid reserved server-id=0 value.
echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
# Copy appropriate conf.d files from config-map to emptyDir.
if [[ $ordinal -eq 0 ]]; then
cp /mnt/config-map/master.cnf /mnt/conf.d/
else
cp /mnt/config-map/slave.cnf /mnt/conf.d/
fi
volumeMounts:
- name: conf
mountPath: /mnt/conf.d
- name: config-map
mountPath: /mnt/config-map
- name: clone-mysql
image: registry.cn-hangzhou.aliyuncs.com/hxpdocker/xtrabackup:1.0
command:
- bash
- "-c"
- |
set -ex
# Skip the clone if data already exists.
[[ -d /var/lib/mysql/mysql ]] && exit 0
# Skip the clone on master (ordinal index 0).
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
[[ $ordinal -eq 0 ]] && exit 0
# Clone data from previous peer.
ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
# Prepare the backup.
xtrabackup --prepare --target-dir=/var/lib/mysql
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
containers:
- name: mysql
image: registry.cn-hangzhou.aliyuncs.com/public_ns/mysql:5.7
env:
- name: MYSQL_ALLOW_EMPTY_PASSWORD
value: "1"
ports:
- name: mysql
containerPort: 3306
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
resources:
requests:
cpu: 500m
memory: 1Gi
livenessProbe:
exec:
command: ["mysqladmin", "ping"]
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
exec:
# Check we can execute queries over TCP (skip-networking is off).
command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
initialDelaySeconds: 5
periodSeconds: 2
timeoutSeconds: 1
- name: xtrabackup
image: registry.cn-hangzhou.aliyuncs.com/hxpdocker/xtrabackup:1.0
ports:
- name: xtrabackup
containerPort: 3307
command:
- bash
- "-c"
- |
set -ex
cd /var/lib/mysql

# Determine binlog position of cloned data, if any.
if [[ -f xtrabackup_slave_info && "x$(<xtrabackup_slave_info)" != "x" ]]; then
# XtraBackup already generated a partial "CHANGE MASTER TO" query
# because we're cloning from an existing slave. (Need to remove the tailing semicolon!)
cat xtrabackup_slave_info | sed -E 's/;$//g' > change_master_to.sql.in
# Ignore xtrabackup_binlog_info in this case (it's useless).
rm -f xtrabackup_slave_info xtrabackup_binlog_info
elif [[ -f xtrabackup_binlog_info ]]; then
# We're cloning directly from master. Parse binlog position.
[[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1
rm -f xtrabackup_binlog_info xtrabackup_slave_info
echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\
MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
fi

# Check if we need to complete a clone by starting replication.
if [[ -f change_master_to.sql.in ]]; then
echo "Waiting for mysqld to be ready (accepting connections)"
until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done

echo "Initializing replication from clone position"
mysql -h 127.0.0.1 \
-e "$(<change_master_to.sql.in), \
MASTER_HOST='mysql-0.mysql', \
MASTER_USER='root', \
MASTER_PASSWORD='', \
MASTER_CONNECT_RETRY=10; \
START SLAVE;" || exit 1
# In case of container restart, attempt this at-most-once.
mv change_master_to.sql.in change_master_to.sql.orig
fi

# Start a server to send backups when requested by peers.
exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \
"xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"
volumeMounts:
- name: data
mountPath: /var/lib/mysql
subPath: mysql
- name: conf
mountPath: /etc/mysql/conf.d
resources:
requests:
cpu: 100m
memory: 100Mi
volumes:
- name: conf
emptyDir: {}
- name: config-map
configMap:
name: mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "nfs-client" #!!!这里需要提前创建好storageClass,或者对应的PVC
resources:
requests:
storage: 10Gi
1
2
3
4
5
6
7
kubectl apply -f https://k8s.io/examples/application/mysql/mysql-statefulset.yaml

kubectl get pods -l app=mysql --watch
NAME READY STATUS RESTARTS AGE
mysql-0 2/2 Running 0 2m
mysql-1 2/2 Running 0 1m
mysql-2 2/2 Running 0 1m

如若没有storageClass,需要创建一下pv和pvc

1
kubectl apply -f cat data_pv.yaml
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
apiVersion: v1
kind: PersistentVolume
metadata:
name: data
labels:
release: "stable"
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
storageClassName: mynfs
persistentVolumeReclaimPolicy: Recycle
nfs:
path: "/eastorage"
server: 10.19.86.144
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: data1
labels:
release: "stable"
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
storageClassName: mynfs1
persistentVolumeReclaimPolicy: Recycle
nfs:
path: "/emptydir"
server: 10.19.86.144
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: data2
labels:
release: "stable"
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
storageClassName: mynfs2
persistentVolumeReclaimPolicy: Recycle
nfs:
path: "/docker"
server: 10.19.86.144
1
kubectl apply -f cat data_pvc.yaml
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
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: data-mysql-0
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: mynfs
selector:
matchLabels:
release: "stable"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: data-mysql-1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: mynfs1
selector:
matchLabels:
release: "stable"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: data-mysql-2
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: mynfs2
selector:
matchLabels:
release: "stable"

主从测试

可以通过运行带有 mysql:5.7 镜像的临时容器并运行 mysql 客户端二进制文件,将测试查询发送到 MySQL 主服务器(主机名 mysql-0.mysql )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@master-dev mysql]# kubectl run test --image=mysql:5.7 -it -- bash

root@test:/# mysql -h mysql-0.mysql

mysql> create database redhat;
Query OK, 1 row affected (0.11 sec)

mysql> show databases;
+------------------------+
| Database |
+------------------------+
| information_schema |
| mysql |
| performance_schema |
| redhat |
| sys |
| xtrabackup_backupfiles |
+------------------------+
6 rows in set (0.04 sec)

通过访问mysql-read来查看创建的数据库是否在从库创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@master-dev mysql_cluster]# kubectl get svc | grep mysql
mysql ClusterIP None <none> 3306/TCP 11m
mysql-read ClusterIP 10.111.232.160 <none> 3306/TCP 11m

[root@master-dev mysql]# kubectl attach test -it

root@test:/# mysql -h 10.111.232.160

mysql> show databases;
+------------------------+
| Database |
+------------------------+
| information_schema |
| mysql |
| performance_schema |
| redhat |
| sys |
| xtrabackup_backupfiles |
+------------------------+
6 rows in set (0.05 sec)

可以看出从库复制了主库的操作,也可以直接访问从库进行验证,本文记录的重点就是在部署statefulset时处理存储问题,需要提前准备好nfs服务,或者有动态的storageClass,否则会处于pengding状态。

-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!
ytlaingc 微信支付

微信支付

ytlaingc 支付宝

支付宝