文章目录
  • 一、前言
  • 二、实际操作
  • 步骤1:编写namespace脚本
  • 步骤2:编写configmap脚本
  • 步骤3:编写secret脚本(用来存放mysql密码)
  • 步骤4:编写initContainer脚本
  • 步骤5:编写StorageClass相关脚本
  • 1)权限设置:编写ServiceAccount、ClusterRole、ClusterRoleBinding、Role、RoleBinding脚本管理NFS
  • 2)每个机器上安装NFS服务,存放目录的机器上新建好 /nfs/data 目录
  • 3)编写StorageClass脚本
  • 4)编写nfs-provisioner的Deployment脚本
  • 步骤6、编写Service脚本
  • 步骤7、编写StatefulSet脚本
  • 步骤8:测试主从同步
  • 三、尾声


一、前言

二、实际操作

问题(六个)

  1. 启动顺序有要求,master节点必须比slave节点先启动 (statefulset)
  2. 节点挂掉了,新的pod启动必须使用原先pod的资源(持久化保证数据不丢失)
  3. master与slave的配置不一样
  4. master启动之后需要设置主从授权账户,slave需要执行change master命令,以及加入主从的命令
  5. 希望客户账户名密码自己配置
  6. slave需要知道master节点的地址

解决方案(六个,按顺序对应问题)

  1. statefulset:使用statefulSet可以使得pod副本按照编号顺序进行启动,只需要把pod-0作为master就可以了
  2. 持久化保证数据不丢失:使用pv和pvc解决,通过pvc与pod的标签进行绑定,一个pod对应一个pvc就可以保证重启后的pod依旧使用原先的资源
  3. 初始化所需的配置信息:使用configmap可以在容器初始化的时候指定需要的配置信息,
  4. 初始化执行的脚步:使用initContainer可以在容器初始化的时候执行需要的脚本
  5. 密码存放:使用secret可以将密码保密
  6. 集群内访问直接podName.serviceName:使用headless service+dns可以让slave节点通过hostname访问master,hostname固定为podName.ServiceName,如:serviceName为mysql,则master的hostname为mysql-0.mysql

八个文件,按顺序来,每个都有分步测试

Kubernetes部署_使用kubernetes部署Mysql主从结构(Kubernetes工作实践类)_数据库

部署思路

  1. 编写namespace脚本,创建专门的namespace
  2. 编写configmap,将mysql的配置文件配置到里面
  3. 编写secret脚本,将需要的密码配置在里面
  4. 编写initContainer脚本(备用),根据hostname判断是master还是slave,进而执行对应的命令
  5. 编写pv和pvc脚本,申请磁盘资源(通过storageClass自动进行pv/pvc的创建)
  6. 编写headless service脚本,配置mysql之间的网络关系
  7. 编写StatefulSet脚本,初始化容器

本文所有的yaml文件

Kubernetes部署_使用kubernetes部署Mysql主从结构(Kubernetes工作实践类)_数据库_02

步骤1:编写namespace脚本

01-mysql-namespace.yaml

apiVersion: v1
#创建Namespace类型资源
kind: Namespace
metadata:
  #资源名称
  name: mysql
  #标签为app:mysql
  labels:
    app: mysql
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

测试:

#执行命令
kubectl apply -f 01-mysql-namespace.yaml
#查看命名空间
kubectl get ns
  • 1.
  • 2.
  • 3.
  • 4.

步骤2:编写configmap脚本

02-mysql-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql
  namespace: mysql
  labels:
    app: mysql
data:
  #这里定义了多个数据信息
  master.cnf: |
    # Master配置
    [mysqld]
    datadir=/var/lib/mysql
    pid-file=/var/run/mysqld/mysqld.pid
    socket=/var/run/mysql/mysql.sock
    log-error=/var/log/mysql/error.log
    log-bin=mysqllog
    skip-name-resolve
    lower-case-table-names=1
    log_bin_trust_function_creators=1
  slave.cnf: |
    # Slave配置
    [mysqld]
    datadir=/var/lib/mysql
    pid-file=/var/run/mysqld/mysqld.pid
    socket=/var/run/mysql/mysql.sock
    log-error=/var/log/mysql/error.log
    super-read-only
    skip-name-resolve
    log-bin=mysql-bin
    lower-case-table-names=1
    log_bin_trust_function_creators=1
  • 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.

相关命令测试

#执行命令
kubectl apply -f 02-mysql-configmap.yaml
#查看mysql命名空间下的configmap
kubectl get cm -n mysql
#查看mysql命名空间下名为mysql的configmap详情
kubectl describe configmap mysql -n mysql
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

步骤3:编写secret脚本(用来存放mysql密码)

03-mysql-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: mysql
  labels:
    app: mysql
#Opaque 类型的数据是一个 map 类型,要求value是base64编码。
type: Opaque
data:
  password: YTEyMzQ1NiE= # a123456! 转成base64 echo -n "a123456!" | base64
  #主从用的账号
  replicationUser: Y29weQ== #copy
  replicationPassword: YTEyMzQ1NiE= #a123456!
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

现在有两个账号密码,等一下用来登录主库和从库
root/a123456!
copy/a123456!

相关命令测试

#执行命令
kubectl apply -f 03-mysql-secret.yaml
#查看mysql命名空间下的configmap
kubectl get secret -n mysql
#查看mysql命名空间下名为mysql-secret的secret详情
kubectl describe secret mysql-secret -n mysql
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

步骤4:编写initContainer脚本

ps:编写的脚本,最后会在创建StatefulSet中使用,这里只是为了展示的更清晰

1)将配置文件拷贝到对应的容器中

set -ex
#从pod的hostname中通过正则获取序号,如果没有截取到就退出程序
ordinal=`hostname | awk -F"-" '{print $2}'` || exit 1
#将serverId输入到对应的配置文件中,路径可以随意(与之后的对应上就行),但是文件名不能换
echo [mysqld] > /etc/mysql/conf.d/server-id.cnf
# 由于server-id不能为0,因此给ID加100来避开它
echo server-id=$((100 + $ordinal)) >> /etc/mysql/conf.d/server-id.cnf
if [[ ${ordinal} -eq 0 ]]; then
  # 如果Pod的序号为0,说明它是Master节点,从ConfigMap里把Master的配置文件拷贝到/mnt/conf.d目录下
  cp /mnt/config-map/master.cnf /etc/mysql/conf.d
else
  # 否则,拷贝ConfigMap里的Slave的配置文件
  cp /mnt/config-map/slave.cnf /etc/mysql/conf.d
fi
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

2)初始化mysql集群

set -ex
cd /var/lib/mysql
#查看是否存在名为mysqlInitOk的文件,我们自己生产的标识文件,防止重复初始化集群
if [ ! -f mysqlInitOk ]; then
  echo "Waiting for mysqld to be ready(accepting connections)"
  #执行一条mysql的命令,查看mysql是否初始化完毕,如果没有就反复执行直到可以运行
    until mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "use mysql;SELECT 1;"; do sleep 1; done
    echo "Initialize ready"
    #判断是master还是slave
    pod_seq=`hostname | awk -F"-" '{print $2}'`
    if [ $pod_seq -eq 0 ];then
      #创建主从账户
    mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "create user '${MYSQL_REPLICATION_USER}'@'%' identified by '${MYSQL_REPLICATION_PASSWORD}';"
    #设置权限
    mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "grant replication slave on *.* to '${MYSQL_REPLICATION_USER}'@'%' with grant option;"
    #mysql8使用原生密码
    mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "ALTER USER '${MYSQL_REPLICATION_USER}'@'%' IDENTIFIED WITH mysql_native_password BY '${MYSQL_REPLICATION_PASSWORD}';"
    #刷新配置
    mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "flush privileges;"
    #初始化master
    mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "reset master;"
  else
    #设置slave连接的master
    #mysql-0.mysql.mysql的由来{pod-name}.{service-name}.{namespace}
    mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e \
    "change master to master_host='mysql-0.mysql.mysql',master_port=3306, \
    master_user='${MYSQL_REPLICATION_USER}',master_password='${MYSQL_REPLICATION_PASSWORD}', \
    master_log_file='mysql-bin.000001',master_log_pos=156;"
    #重置slave
    mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "reset slave;"
    #开始同步
    mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "start slave;"
    #改成只读模式
    mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "set global read_only=1;"
  fi
  #运行完毕创建标识文件,防止重复初始化集群
  touch mysqlInitOk
fi
  • 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.

步骤5:编写StorageClass相关脚本

采用StorageClass+NFS方式作为网络存储,使用这种方式会自动生成pvc和pv

所有的k8s节点上都要安装nfs,NFS搭建移步这里查看:nfs,信息如下

IP: 192.168.100.152
Export PATH: /nfs/data

1)权限设置:编写ServiceAccount、ClusterRole、ClusterRoleBinding、Role、RoleBinding脚本管理NFS

04-mysql-rbac.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  namespace: mysql
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["watch", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["get"]
  - apiGroups: ["extensions"]
    resources: ["podsecuritypolicies"]
    resourceNames: ["nfs-provisioner"]
    verbs: ["use"]
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: mysql
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: mysql
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: mysql
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
  • 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.

相关命令测试

#执行命令
kubectl apply -f 04-mysql-rbac.yaml
  • 1.
  • 2.
2)每个机器上安装NFS服务,存放目录的机器上新建好 /nfs/data 目录

01 选择master节点作为nfs的server,所以在master节点上,执行以下命令

# 第一步,启动nfs和rpcbind
# 启动nfs
systemctl status nfs (如果存在就开启 systmctl start nfs ,不过不存在就安装 yum -y install nfs-utils 并 systemctl start nfs)
systemctl start nfs (启动后再次查看状态,状态成功就是表示启动成功了)
systemctl enable nfs  (设置为为开机自启动)

# 启动rpcbind
systemctl restart rpcbind   (重启)
systemctl enable rpcbind    (设置为开机自启动)
systemctl status rpcbind  (查看状态,验证重启成功)


# 第二步,创建nfs目录并授予权限  /nfs/data/     这个目录就是nfs ip那个目录
# 创建nfs目录
mkdir -p /nfs/data/
# 授予权限
chmod -R 777 /nfs/data

# 第三步,编辑export文件并保存
# 编辑export文件   对于/nfs/data目录,授予可读可写权限、根目录权限、同步数据权限
vi /etc/exports
  /nfs/data *(rw,no_root_squash,sync)
  /nfs/data *(rw,no_root_squash,sync,no_subtree_check)  # 新版nfs
# 使得配置生效
exportfs -r
# 查看生效
exportfs

# 第四步,验证rpcbind、nfs
# 查看rpc服务的注册情况
rpcinfo -p localhost
# showmount测试     
# showmount命令用于查询NFS服务器的相关信息     -e或--exports  显示NFS服务器的输出清单。
showmount -e master-ip  
showmount -e 192.168.100.152
  • 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.

02 所有node上安装客户端 ps -ef|grep nfs

# 启动nfs
systemctl status nfs (如果存在就开启 systmctl start nfs ,不过不存在就安装 yum -y install nfs-utils 并 systemctl start nfs)
systemctl start nfs (启动后再次查看状态,状态成功就是表示启动成功了)
systemctl enable nfs  (设置为为开机自启动)

# 启动rpcbind
systemctl restart rpcbind   (重启)
systemctl enable rpcbind    (设置为开机自启动)
systemctl status rpcbind  (查看状态,验证重启成功)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

Kubernetes部署_使用kubernetes部署Mysql主从结构(Kubernetes工作实践类)_mysql_03

linux运维关于服务
service could not found 是没有安装服务,需要 yum -y install nfs-utils
inactive 是安装了服务,但是没有启动,需要 systemctl start nfs

3)编写StorageClass脚本

05-mysql-nfs-storageclass.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: mysql-nfs-storage #这里的名称要和provisioner配置文件中的环境变量PROVISIONER_NAME保持一致
volumeBindingMode: WaitForFirstConsumer
parameters:
  archiveOnDelete: "true" #pvc被删除了也需要进行存档
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

相关命令测试

#执行命令
kubectl apply -f 05-mysql-nfs-storageclass.yaml
#查看StorageClass信息
kubectl get sc
  • 1.
  • 2.
  • 3.
  • 4.
4)编写nfs-provisioner的Deployment脚本

所有的k8s节点上都要安装nfs,不然这段就会出问题无法运行

06-mysql-nfs-provisioner-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  namespace: mysql  #与RBAC文件中的namespace保持一致
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-client-provisioner
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: mysql-nfs-storage  #provisioner名称,请确保该名称与 nfs-StorageClass.yaml文件中的provisioner名称保持一致
            - name: NFS_SERVER
              value: 192.168.100.152   #NFS Server IP地址
            - name: NFS_PATH  
              value: /nfs/data    #NFS挂载卷
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.100.152  #NFS Server IP地址
            path: /nfs/data     #NFS 挂载卷
  • 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.

相关命令测试

#执行命令
kubectl apply -f 06-mysql-nfs-provisioner-deployment.yaml
  • 1.
  • 2.

步骤6、编写Service脚本

07-mysql-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: mysql
  labels:
    app: mysql
spec:
  selector:
  	#匹配带有app: mysql标签的pod
    app: mysql
  clusterIP: None
  ports:
  - name: mysql
    port: 3306
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

相关命令测试

#执行命令
kubectl apply -f 07-mysql-service.yaml
#查看mysql命名空间下service信息
kubectl get svc -n mysql
  • 1.
  • 2.
  • 3.
  • 4.

步骤7、编写StatefulSet脚本

08-mysql-statefulset.yaml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: mysql
  labels:
    app: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  #与mysql-service.yaml中的保持一致
  serviceName: mysql
  replicas: 3
  template:
    metadata:
      labels:
        app: mysql
    spec:
      initContainers:
      - name: init-mysql
        image: mysql:8.0.21
        command: 
        - bash
        - "-c"
        - |
          set -ex
          #从pod的hostname中通过正则获取序号,如果没有截取到就退出程序
          ordinal=`hostname | awk -F"-" '{print $2}'` || exit 1
          #将serverId输入到对应的配置文件中,路径可以随意(与之后的对应上就行),但是文件名不能换
          echo [mysqld] > /etc/mysql/conf.d/server-id.cnf
          # 由于server-id不能为0,因此给ID加100来避开它
          echo server-id=$((100 + $ordinal)) >> /etc/mysql/conf.d/server-id.cnf
          if [[ ${ordinal} -eq 0 ]]; then
            # 如果Pod的序号为0,说明它是Master节点,从ConfigMap里把Master的配置文件拷贝到/mnt/conf.d目录下
            cp /mnt/config-map/master.cnf /etc/mysql/conf.d
          else
            # 否则,拷贝ConfigMap里的Slave的配置文件
            cp /mnt/config-map/slave.cnf /etc/mysql/conf.d
          fi
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        - name: MYSQL_REPLICATION_USER
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: replicationUser
        - name: MYSQL_REPLICATION_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: replicationPassword
        volumeMounts:
        - name: conf
          mountPath: /etc/mysql/conf.d
        - name: config-map
          mountPath: /mnt/config-map
      containers:
      - name: mysql
        image: mysql:8.0.21
        lifecycle:
         postStart:
          exec:
            command:
            - bash
            - "-c"
            - |
              set -ex
              cd /var/lib/mysql
              #查看是否存在名为mysqlInitOk的文件,我们自己生产的标识文件,防止重复初始化集群
              if [ ! -f mysqlInitOk ]; then
                echo "Waiting for mysqld to be ready(accepting connections)"
                #执行一条mysql的命令,查看mysql是否初始化完毕,如果没有就反复执行直到可以运行
                  until mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "use mysql;SELECT 1;"; do sleep 1; done
                  echo "Initialize ready"
                  #判断是master还是slave
                  pod_seq=`hostname | awk -F"-" '{print $2}'`
                  if [ $pod_seq -eq 0 ];then
                    #创建主从账户
                  mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "create user '${MYSQL_REPLICATION_USER}'@'%' identified by '${MYSQL_REPLICATION_PASSWORD}';"
                  #设置权限
                  mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "grant replication slave on *.* to '${MYSQL_REPLICATION_USER}'@'%' with grant option;"
                  #mysql8使用原生密码
                  mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "ALTER USER '${MYSQL_REPLICATION_USER}'@'%' IDENTIFIED WITH mysql_native_password BY '${MYSQL_REPLICATION_PASSWORD}';"
                  #刷新配置
                  mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "flush privileges;"
                  #初始化master
                  mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "reset master;"
                else
                  #设置slave连接的master
                  #mysql-0.mysql.mysql的由来{pod-name}.{service-name}.{namespace}
                  mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e \
                  "change master to master_host='mysql-0.mysql.mysql',master_port=3306, \
                  master_user='${MYSQL_REPLICATION_USER}',master_password='${MYSQL_REPLICATION_PASSWORD}', \
                  master_log_file='mysql-bin.000001',master_log_pos=156;"
                  #重置slave
                  mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "reset slave;"
                  #开始同步
                  mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "start slave;"
                  #改成只读模式
                  mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "set global read_only=1;"
                fi
                #运行完毕创建标识文件,防止重复初始化集群
                touch mysqlInitOk
              fi
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        - name: MYSQL_REPLICATION_USER
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: replicationUser
        - name: MYSQL_REPLICATION_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: replicationPassword
        ports:
        - name: mysql
          containerPort: 3306
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
        - name: conf
          mountPath: /etc/mysql/conf.d
        - name: run-mysql
          mountPath: /var/run/mysql
        resources:
          requests:
            cpu: 500m
            memory: 2Gi
        #设置存活探针
        livenessProbe:
          exec:
            command: ["mysqladmin", "ping", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"]
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
        #设置就绪探针
        readinessProbe:
          exec:
            command: ["mysqladmin", "ping", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"]
          initialDelaySeconds: 5
          periodSeconds: 2
          timeoutSeconds: 1
      volumes:
      - name: config-map
        #这个卷挂载到configMap上
        configMap:
          name: mysql
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes:
      - ReadWriteOnce
      #与nfs-StorageClass.yaml metadata.name保持一致
      storageClassName: managed-nfs-storage
      resources:
        requests:
          storage: 5Gi
  - metadata: 
      name: conf
    spec:
      accessModes:
      - ReadWriteOnce
      #与nfs-StorageClass.yaml metadata.name保持一致
      storageClassName: managed-nfs-storage
      resources:
        requests:
          storage: 100Mi
  - metadata: 
      name: run-mysql
    spec:
      accessModes:
      - ReadWriteOnce
      #与nfs-StorageClass.yaml metadata.name保持一致
      storageClassName: managed-nfs-storage
      resources:
        requests:
          storage: 100Mi
  • 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.
  • 168.
  • 169.
  • 170.
  • 171.
  • 172.
  • 173.
  • 174.
  • 175.
  • 176.
  • 177.
  • 178.
  • 179.
  • 180.
  • 181.
  • 182.
  • 183.
  • 184.
  • 185.
  • 186.
  • 187.
  • 188.
  • 189.

相关命令测试

#执行命令
kubectl apply -f 08-mysql-statefulset.yaml
#查看mysql命名空间下pvc信息
kubectl get pvc -n mysql
kubectl describe pvc data-mysql-0  -n mysql
#查看mysql命名空间下pv信息
kubectl get pv -n mysql
#查看mysql命名空间下pod节点信息
kubectl get pod -n mysql
#查看mysql命名空间下名为mysql-1节点的mysql从节点状态
kubectl -n mysql exec mysql-1 -c mysql -- bash -c "mysql -uroot -pa123456! -e 'show slave status \G'"
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

如果使用kubectl get pvc -n mysql查看状态一直是Pending,大概率是使用了k8s1.20以上版本,需要修改 apiserver 的配置文件,重新启用 SelfLink 功能。

vim /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
  containers:
  - command:
    - kube-apiserver
    ...
    - --feature-gates=RemoveSelfLink=false # 增加这行
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

如果依旧不行,用命令查看nfs-client-provisioner有没有报错

#查看pod名称
kubectl get pods -n mysql
#找到对应的pod查看日志
kubectl logs -f nfs-client-provisioner-xxxxx -n mysql
  • 1.
  • 2.
  • 3.
  • 4.

如果看到类似 unable to create directory to provision new pv: mkdir /persistentvolumes/mysql-data-mysql-0-pvc-1bb47,就在nfs服务器端给挂载的那个文件夹开通权限

chmod -R 777 /nfs/data

步骤8:测试主从同步

主库操作如下:

Kubernetes部署_使用kubernetes部署Mysql主从结构(Kubernetes工作实践类)_kubernetes_04

从库操作如下:

Kubernetes部署_使用kubernetes部署Mysql主从结构(Kubernetes工作实践类)_云原生_05


另外注意,show slave status\G; 只在主库上执行,不能在从库上执行

Kubernetes部署_使用kubernetes部署Mysql主从结构(Kubernetes工作实践类)_kubernetes_06

三、尾声

小结四点:

mysql搭建主从结构的目的是为了应对高并发
只有主库能 insert/update/delete 操作,从库执行这个不会报错,但是引起从库与主库不一致,后面的 主库的东西都同步不到从库
只有从库能 show slave status\G 操作,查询主从同步当前进度offset,主库执行这个会报错
如果这里 statefulset replicas 是 2 ,mysql-0 是主,mysql-1 是从,如果 replicas 是 3,则mysql-0 是主,mysql-1 和 mysql-2 是从

Kubernetes部署_使用kubernetes部署Mysql主从结构(Kubernetes工作实践类)

完!