Kubernetes系列-部署MySQL主从(k8s)
Kubernetes系列-部署MySQL主从
分析需要解决的问题,制定解决思路:
1.启动顺序:Master 的Pod 必须先于 Slave 的 Pod 起来;
2.如果某个Pod挂掉了,应该自动重新启动一个Pod,这个新建的Pod应该沿用原来的数据;
3.Master 与 Slave 的配置文件不同,特别是server_id;
4.Master 与 Slave 在服务启动之后还需要执行一些命令,它们也不一样,具体为:
1)Master需要执行授权命令,授权的用户名和密码希望用户自己来配置,而不是写死;
2)Slave需要执行CHANGE MASTER命令,需要知道Master的地址。
解决以上问题,那么项目就可以成功部署,下面让我们来一个个解决:
- 关于启动顺序问题。这个好说,利用 StatefulSet 轻松就能解决,它的一个特点就是会将所有的Pod副本进行编号,然后按照编号顺序一个一个的启动,Pod命名规则为
statefulsetName-N
其中N为编号,从0开始。例如,StatefulSet名称为mysql
,那么第一个启动的Pod名称必为mysql-0
。 - 关于重建Pod后的数据问题。因为重建的新Pod不一定还在原来的Node上,因此,想用原来的数据必须要使用分布式或共享Volume。我们可以使用NFS或其它的分布式存储来解决此问题。另外,如果几个副本(例如mysql-1,mysql-2,mysql-3)同时重建,必须保证新建立的
mysql-1
仍然沿用原来的mysql-1
的数据。这个问题我们可以使用PV和PVC来解决。 - 配置文件不同的问题。不考虑其他,就server_id不同的问题,我们可以利用容器启动前的initContainer来解决在每个容器启动前插入更改配置文件信息,还可以传入容器启动后执行的脚本文件
- 用户名和密码可以使用 Secret 传递进来。Master地址因为不是固定的,所以不建议使用IP地址,我们可以借助 Headless Service 加上 DNS 来解决。如果我们能传入Service的名称进来,那么就可以使用这种方式来与其它Pod进行通信:
PodName.ServiceName
。例如,如果Service名称为mysqlsvc,那么master的DNS名称为mysql-0.mysqlsvc
,这个名称是不会变化的。当Master完成授权工作后,Slave可通过授权帐号查询到binlog文件名及位置信息(注意授权时要给replication client
权限才可以查询)。 - 此次部署是自己制作的镜像,你也可以通过已有镜像进行部署。
有了解决思路,下面开始部署项目。
构建initContainer镜像
1、编写MySQL配置文件
[root@master cnf]# cat my.cnf [mysqld] log-bin = binlog server-id = 1 gtid_mode = on enforce_gtid_consistency = 1 log_slave_updates = 1 pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock datadir = /var/lib/mysql #log-error = /var/log/mysql/error.log # By default we only accept connections from localhost #bind-address = 127.0.0.1 # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0
2、编写initContainer执行脚本
[root@master cnf]# cat my.sh #!/bin/bash pod_seq=`hostname | awk -F"-" '{print $2}'` conf=/cnf if [ $pod_seq -eq 0 ];then cp $conf/my.cnf /mysql cp $conf/init.sh /mysql else id=$((pod_seq+1)) sed -ri "/server/c server-id = $id" /mysql/my.cnf fi
3、编写postStart执行脚本
[root@master cnf]# cat init.sh #!/bin/bash pod_seq=`echo $POD_NAME |awk -F"-" '{print $2}'` while : ;do if [ $pod_seq -eq 0 ] ; then mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "show databases" && mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "grant replication slave on *.* to '$REPLIC_USER'@'%' identified by '$REPLIC_PASSWORD' && REPLIC_USER sleep 1 else mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "show databases" && mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "change master to master_host='mysql-0.mysqlsvc',master_user='$REPLIC_USER',master_password='$REPLIC_PASSWORD',master_auto_position=1;" && mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "start slave" && break sleep 1 fi done
4、构建镜像及上传镜像
[root@master cnf]# cat Dockerfile FROM alpine COPY my.cnf my.sh init.sh /cnf/ [root@master cnf]# docker build -t registry.cn-shenzhen.aliyuncs.com/jun-lin/my-cnf:[tag] . [root@master cnf]# docker pull registry.cn-shenzhen.aliyuncs.com/jun-lin/my-cnf:[tag]
在Kubernetes中创建MySQL主从集群
- 使用 secret 传入所有的用户名及密码
- 使用 downwardAPI 获取 Pod 名称
编写yaml文件:
vim secret
---
apiVersion: v1
kind: Secret
metadata:
name: mysql
namespace: default
type: Opaque
data:
root_pass: bGVlZG9u # 用base64转码后的字符
rep_user: c2xhdmU=
rep_pass: c2xhdmVwYXNz
vim mysql
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysqlsvc
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
initContainers:
- image: registry.cn-shenzhen.aliyuncs.com/jun-lin/my-cnf:v7
name: cnf
command: ["sh","/cnf/my.sh"]
volumeMounts:
- mountPath: /mysql
name: conf-volume
containers:
- name: mysql
image: mysql:5.7
imagePullPolicy: IfNotPresent
env:
- name: SVC_NAME
value: mysqlsvc
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql
key: root_pass
- name: REPLIC_USER
valueFrom:
secretKeyRef:
name: mysql
key: rep_user
- name: REPLIC_PASSWORD
valueFrom:
secretKeyRef:
name: mysql
key: rep_pass
- name: POD_NAME
valueFrom: