StorageClass

创建名叫mysql-sc的存储类

ConfigMap

新建文件: configmap.yml ,内容如下:

  1. apiVersion: v1
  2. data:
  3. master.cnf: |
  4. # Apply this config only on the master.
  5. [client]
  6. default-character-set=utf8mb4
  7. [mysql]
  8. default-character-set=utf8mb4
  9. [mysqld]
  10. log-bin
  11. binlog_expire_logs_seconds=2592000
  12. max_connections=10000
  13. default-time-zone='+8:00'
  14. character-set-client-handshake=FALSE
  15. character-set-server=utf8mb4
  16. collation-server=utf8mb4_unicode_ci
  17. init_connect='SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci'
  18. slave.cnf: |
  19. # Apply this config only on slaves.
  20. [client]
  21. default-character-set=utf8mb4
  22. [mysql]
  23. default-character-set=utf8mb4
  24. [mysqld]
  25. super-read-only
  26. max_connections=10000
  27. default-time-zone='+8:00'
  28. character-set-client-handshake=FALSE
  29. character-set-server=utf8mb4
  30. collation-server=utf8mb4_unicode_ci
  31. init_connect='SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci'
  32. kind: ConfigMap
  33. metadata:
  34. labels:
  35. app: mysql
  36. name: mysql

Headless Service

Headless Service 是有状态服务都需要,让其服务下的Pod能够彼此发现
新建文件: service.yml ,内容如下:

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: mysql-svc-master
  5. labels:
  6. app: mysql
  7. spec:
  8. selector:
  9. app: mysql
  10. ports:
  11. - port: 3306
  12. name: mysql
  13. clusterIP: None

SatefulSet

配置文件

  1. apiVersion: apps/v1
  2. kind: StatefulSet
  3. metadata:
  4. name: mysql-ss
  5. spec:
  6. selector:
  7. matchLabels:
  8. app: mysql
  9. serviceName: mysql-svc-master
  10. replicas: 3
  11. template:
  12. metadata:
  13. labels:
  14. app: mysql
  15. spec:
  16. initContainers:
  17. - name: init-mysql
  18. image: mysql:8.0.19
  19. command:
  20. - bash
  21. - "-c"
  22. - |
  23. set ex
  24. # 从hostname中获取索引,比如(mysql-1)会获取(1)
  25. [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
  26. ordinal=${BASH_REMATCH[1]}
  27. echo [mysqld] > /mnt/conf.d/server-id.cnf
  28. # 为了不让server-id=0而增加偏移量
  29. echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
  30. # 拷贝对应的文件到/mnt/conf.d/文件夹中
  31. if [[ $ordinal -eq 0 ]]; then
  32. cp /mnt/config-map/master.cnf /mnt/conf.d/
  33. else
  34. cp /mnt/config-map/slave.cnf /mnt/conf.d/
  35. fi
  36. volumeMounts:
  37. - name: conf
  38. mountPath: /mnt/conf.d
  39. - name: config-map
  40. mountPath: /mnt/config-map
  41. - name: clone-mysql
  42. image: mzmuer/xtrabackup:1.0
  43. command:
  44. - bash
  45. - "-c"
  46. - |
  47. set -ex
  48. # 整体意思:
  49. # 1.如果是主mysql中的xtrabackup,就不需要克隆自己了,直接退出
  50. # 2.如果是从mysql中的xtrabackup,先判断是否是第一次创建,因为第二次重启本地就有数据库,无需克隆。若是第一次创建(通过/var/lib/mysql/mysql文件是否存在判断),就需要克隆数据库到本地。
  51. # 如果有数据不必克隆数据,直接退出()
  52. [[ -d /var/lib/mysql/mysql ]] && exit 0
  53. # 如果是master数据也不必克隆
  54. [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
  55. ordinal=${BASH_REMATCH[1]}
  56. [[ $ordinal -eq 0 ]] && exit 0
  57. # 从序列号比自己小一的数据库克隆数据,比如mysql-2会从mysql-1处克隆数据
  58. ncat --recv-only mysql-ss-$(($ordinal-1)).mysql-svc-master 3307 | xbstream -x -C /var/lib/mysql
  59. # 比较数据
  60. xtrabackup --prepare --target-dir=/var/lib/mysql
  61. volumeMounts:
  62. - name: data
  63. mountPath: /var/lib/mysql
  64. subPath: mysql
  65. - name: conf
  66. mountPath: /etc/mysql/conf.d
  67. containers:
  68. - name: mysql
  69. image: mysql:8.0.19
  70. args: ["--default-authentication-plugin=mysql_native_password"]
  71. env:
  72. - name: MYSQL_ALLOW_EMPTY_PASSWORD
  73. value: "1"
  74. ports:
  75. - name: mysql
  76. containerPort: 3306
  77. volumeMounts:
  78. - name: data
  79. mountPath: /var/lib/mysql
  80. subPath: mysql
  81. - name: conf
  82. mountPath: /etc/mysql/conf.d
  83. resources:
  84. requests:
  85. cpu: 250m
  86. memory: 256Mi
  87. limits:
  88. cpu: 500m
  89. memory: 512Mi
  90. livenessProbe:
  91. exec:
  92. command: ["mysqladmin", "ping"]
  93. initialDelaySeconds: 30
  94. periodSeconds: 10
  95. timeoutSeconds: 5
  96. readinessProbe:
  97. exec:
  98. command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
  99. initialDelaySeconds: 5
  100. periodSeconds: 2
  101. timeoutSeconds: 1
  102. - name: xtrabackup
  103. image: mzmuer/xtrabackup:1.0
  104. ports:
  105. - name: xtrabackup
  106. containerPort: 3307
  107. command:
  108. - bash
  109. - "-c"
  110. - |
  111. set -ex
  112. # 确定binlog 克隆数据位置(如果binlog存在的话).
  113. cd /var/lib/mysql
  114. # 如果存在该文件,则该xrabackup是从现有的从节点克隆出来的。
  115. if [[ -s xtrabackup_slave_info ]]; then
  116. mv xtrabackup_slave_info change_master_to.sql.in
  117. rm -f xtrabackup_binlog_info
  118. elif [[ -f xtrabackup_binlog_info ]]; then
  119. [[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1
  120. rm xtrabackup_binlog_info
  121. echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\
  122. MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
  123. fi
  124. if [[ -f change_master_to.sql.in ]]; then
  125. echo "Waiting for mysqld to be ready (accepting connections)"
  126. until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done
  127. echo "Initializing replication from clone position"
  128. mv change_master_to.sql.in change_master_to.sql.orig
  129. mysql -h 127.0.0.1 <<EOF
  130. $(<change_master_to.sql.orig),
  131. MASTER_HOST='mysql-ss-0.mysql-svc-master',
  132. MASTER_USER='root',
  133. MASTER_PASSWORD='',
  134. MASTER_CONNECT_RETRY=10;
  135. START SLAVE;
  136. EOF
  137. fi
  138. exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \
  139. "xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"
  140. volumeMounts:
  141. - name: data
  142. mountPath: /var/lib/mysql
  143. subPath: mysql
  144. - name: conf
  145. mountPath: /etc/mysql/conf.d
  146. resources:
  147. requests:
  148. cpu: 100m
  149. memory: 100Mi
  150. limits:
  151. cpu: 200m
  152. memory: 200Mi
  153. volumes:
  154. - name: conf
  155. emptyDir: {}
  156. - name: config-map
  157. configMap:
  158. name: mysql
  159. volumeClaimTemplates:
  160. - metadata:
  161. name: data
  162. spec:
  163. storageClassName: mysql-sc
  164. accessModes:
  165. - ReadWriteOnce
  166. resources:
  167. requests:
  168. storage: 10Gi

1.initContainers作用:

  • 主数据库无需同步自己数据,从数据库需要被同步数据
  • 判断当前启动的容器是主还是slave,并向pod的conf卷写入如下数据

    1. cat /mnt/conf.d/server-id.cnf
    2. [mysqld]
    3. server-id=10?
    4. ls /mnt/conf.d/
    5. master[?salve].cnf # 从configmap处拷贝而来
  • 当执行完command命令后生命终止,但是pod的conf卷的数据依然存在,因为初始容器和接下来的container容器使用共同的volumes卷,不同的是conf被initContainer挂载到/mnt/conf.d,而在container被挂载在/etc/mysql/conf.d/

    2.Container作用:

  • 提供mysql服务

  • 运行xtrabakup应用容器提供数据同步

mysql-svc-read 服务

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: mysql-svc-read
  5. labels:
  6. app: mysql
  7. spec:
  8. ports:
  9. - name: mysql
  10. port: 3306
  11. selector:
  12. app: mysql

测试 mysql-svc-read 服务

  1. kubectl run mysql-client-loop --image=mysql:8.0.19 -i -t -n test --rm --restart=Never --\
  2. bash -ic "while sleep 1; do mysql -h mysql-svc-read -e 'SELECT @@server_id,NOW()'; done"

每秒查询一次数据库,可以观察到,调度到不同的 server_id,即 pod 节点
image.png

删除部署

  1. kubectl delete statefulset mysql-ss -n test
  2. kubectl delete configmap,service,pvc -l app=mysql -n test

Kubernetes部署MySQL8集群- - 图2

Kubernetes部署MySQL8集群- - 图3

参考资料

按照K8s官方文档部署Mysql高可用+读写分离的坑
【深入分析】K8s部署Mysql主从复制+读写分离
【全网最全最详细】Kubernetes部署Mysql主从复制+读写分离
kubernetes中 mysql集群出现Access denied for user ‘root’@’localhost’ (using password: NO)
Kubernetes-部署高可用的MySQL