暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Kubernetes 部署 MySQL 集群

原创 Spark 2021-12-11
411

简介: 在有状态应用中,MySQL是我们最常见也是最常用的。本文我们将实战部署一个一组多从的MySQL集群。

116.jpg


镜像下载、域名解析、时间同步请点击 阿里巴巴开源镜像站

一、配置准备

1. configMap


  1. #application/mysql/mysql-configmap.yaml


  2. apiVersion: v1


  3. kind: ConfigMap


  4. metadata:


  5. name: mysql


  6. labels:


  7. app: mysql


  8. data:


  9. master.cnf: |


  10. # Apply this config only on the master.


  11. [mysqld]


  12. log-bin


  13. slave.cnf: |


  14. # Apply this config only on slaves.


  15. [mysqld]


  16. super-read-only

configMap可以将配置文件和镜像解耦开。
上面的配置意思是,创建一个master.cnf文件配置内容为:log-bin,即开启bin-log日志,供主节点使用。
创建一个slave.cnf文件配置内容为:super-read-only,设为该节点只读,供备用节点使用。

2. service


  1. # application/mysql/mysql-services.yaml


  2. # Headless service for stable DNS entries of StatefulSet members.


  3. apiVersion: v1


  4. kind: Service


  5. metadata:


  6. name: mysql


  7. labels:


  8. app: mysql


  9. spec:


  10. ports:


  11. - name: mysql


  12. port: 3306


  13. clusterIP: None


  14. selector:


  15. app: mysql


  16. ---


  17. # Client service for connecting to any MySQL instance for reads.


  18. # For writes, you must instead connect to the master: mysql-0.mysql.


  19. apiVersion: v1


  20. kind: Service


  21. metadata:


  22. name: mysql-read


  23. labels:


  24. app: mysql


  25. spec:


  26. ports:


  27. - name: mysql


  28. port: 3306


  29. selector:


  30. app: mysql

创建一个服务名为mysql的headless类型的service。
创建一个服务名为mysql-read的service

3. StatefulSet


  1. #application/mysql/mysql-statefulset.yaml


  2. apiVersion: apps/v1


  3. kind: StatefulSet


  4. metadata:


  5. name: mysql


  6. spec:


  7. selector:


  8. matchLabels:


  9. app: mysql


  10. serviceName: mysql


  11. replicas: 3


  12. template:


  13. metadata:


  14. labels:


  15. app: mysql


  16. spec:


  17. # 设置初始化容器,进行一些准备工作


  18. initContainers:


  19. - name: init-mysql


  20. image: mysql:5.7


  21. # 为每个MySQL节点配置service-id


  22. # 如果节点序号是0,则使用master的配置, 其余节点使用slave的配置


  23. command:


  24. - bash


  25. - "-c"


  26. - |


  27. set -ex


  28. # Generate mysql server-id from pod ordinal index.


  29. [[ `hostname` =~ -([0-9]+)$ ]] || exit 1


  30. ordinal=${BASH_REMATCH[1]}


  31. echo [mysqld] > /mnt/conf.d/server-id.cnf


  32. # Add an offset to avoid reserved server-id=0 value.


  33. echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf


  34. # Copy appropriate conf.d files from config-map to emptyDir.


  35. if [[ $ordinal -eq 0 ]]; then


  36. cp /mnt/config-map/master.cnf /mnt/conf.d/


  37. else


  38. cp /mnt/config-map/slave.cnf /mnt/conf.d/


  39. fi


  40. volumeMounts:


  41. - name: conf


  42. mountPath: /mnt/conf.d


  43. - name: config-map


  44. mountPath: /mnt/config-map


  45. - name: clone-mysql


  46. image: gcr.io/google-samples/xtrabackup:1.0


  47. # 为除了节点序号为0的主节点外的其它节点,备份前一个节点的数据


  48. command:


  49. - bash


  50. - "-c"


  51. - |


  52. set -ex


  53. # Skip the clone if data already exists.


  54. [[ -d /var/lib/mysql/mysql ]] && exit 0


  55. # Skip the clone on master (ordinal index 0).


  56. [[ `hostname` =~ -([0-9]+)$ ]] || exit 1


  57. ordinal=${BASH_REMATCH[1]}


  58. [[ $ordinal -eq 0 ]] && exit 0


  59. # Clone data from previous peer.


  60. ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql


  61. # Prepare the backup.


  62. xtrabackup --prepare --target-dir=/var/lib/mysql


  63. volumeMounts:


  64. - name: data


  65. mountPath: /var/lib/mysql


  66. subPath: mysql


  67. - name: conf


  68. mountPath: /etc/mysql/conf.d


  69. containers:


  70. - name: mysql


  71. image: mysql:5.7


  72. # 设置支持免密登录


  73. env:


  74. - name: MYSQL_ALLOW_EMPTY_PASSWORD


  75. value: "1"


  76. ports:


  77. - name: mysql


  78. containerPort: 3306


  79. volumeMounts:


  80. - name: data


  81. mountPath: /var/lib/mysql


  82. subPath: mysql


  83. - name: conf


  84. mountPath: /etc/mysql/conf.d


  85. resources:


  86. # 设置启动pod需要的资源,官方文档上需要500m cpu,1Gi memory。


  87. # 我本地测试的时候,会因为资源不足,报1 Insufficient cpu, 1 Insufficient memory错误,所以我改小了点


  88. requests:


  89. # m是千分之一的意思,100m表示需要0.1个cpu


  90. cpu: 100m


  91. # Mi是兆的意思,需要100M 内存


  92. memory: 100Mi


  93. livenessProbe:


  94. # 使用mysqladmin ping命令,对MySQL节点进行探活检测


  95. # 在节点部署完30秒后开始,每10秒检测一次,超时时间为5秒


  96. exec:


  97. command: ["mysqladmin", "ping"]


  98. initialDelaySeconds: 30


  99. periodSeconds: 10


  100. timeoutSeconds: 5


  101. readinessProbe:


  102. # 对节点服务可用性进行检测, 启动5秒后开始,每2秒检测一次,超时时间1秒


  103. exec:


  104. # Check we can execute queries over TCP (skip-networking is off).


  105. command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]


  106. initialDelaySeconds: 5


  107. periodSeconds: 2


  108. timeoutSeconds: 1


  109. - name: xtrabackup


  110. image: gcr.io/google-samples/xtrabackup:1.0


  111. ports:


  112. - name: xtrabackup


  113. containerPort: 3307


  114. # 开始进行备份文件校验、解析和开始同步


  115. command:


  116. - bash


  117. - "-c"


  118. - |


  119. set -ex


  120. cd /var/lib/mysql


  121. # Determine binlog position of cloned data, if any.


  122. if [[ -f xtrabackup_slave_info && "x$(<xtrabackup_slave_info)" != "x" ]]; then


  123. # XtraBackup already generated a partial "CHANGE MASTER TO" query


  124. # because we're cloning from an existing slave. (Need to remove the tailing semicolon!)


  125. cat xtrabackup_slave_info | sed -E 's/;$//g' > change_master_to.sql.in


  126. # Ignore xtrabackup_binlog_info in this case (it's useless).


  127. rm -f xtrabackup_slave_info xtrabackup_binlog_info


  128. elif [[ -f xtrabackup_binlog_info ]]; then


  129. # We're cloning directly from master. Parse binlog position.


  130. [[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1


  131. rm -f xtrabackup_binlog_info xtrabackup_slave_info


  132. echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\


  133. MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in


  134. fi


  135. # Check if we need to complete a clone by starting replication.


  136. if [[ -f change_master_to.sql.in ]]; then


  137. echo "Waiting for mysqld to be ready (accepting connections)"


  138. until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done


  139. echo "Initializing replication from clone position"


  140. mysql -h 127.0.0.1 \


  141. -e "$(<change_master_to.sql.in), \


  142. MASTER_HOST='mysql-0.mysql', \


  143. MASTER_USER='root', \


  144. MASTER_PASSWORD='', \


  145. MASTER_CONNECT_RETRY=10; \


  146. START SLAVE;" || exit 1


  147. # In case of container restart, attempt this at-most-once.


  148. mv change_master_to.sql.in change_master_to.sql.orig


  149. fi


  150. # Start a server to send backups when requested by peers.


  151. exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \


  152. "xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"


  153. volumeMounts:


  154. - name: data


  155. mountPath: /var/lib/mysql


  156. subPath: mysql


  157. - name: conf


  158. mountPath: /etc/mysql/conf.d


  159. resources:


  160. requests:


  161. cpu: 100m


  162. memory: 100Mi


  163. volumes:


  164. - name: conf


  165. emptyDir: {}


  166. - name: config-map


  167. configMap:


  168. name: mysql


  169. # 设置PVC


  170. volumeClaimTemplates:


  171. - metadata:


  172. name: data


  173. spec:


  174. accessModes: ["ReadWriteOnce"]


  175. resources:


  176. requests:


  177. storage: 1Gi

主从节点的配置和启动都在上面的yaml文件中定义好了,接下来需要逐个创建即可。

二、创建所需资源


  1. //创建configMap


  2. kubectl apply -f configMap.yaml


  3. //创建service


  4. kubectl apply -f service.yaml


  5. //创建statefulSet


  6. kubectl apply -f statefulSet.yaml

4.jpg


执行完毕后可以使用以下命令监测创建情况。

kubectl get pods --watch

5.jpg


三、测试主库

1. 进入pod进行操作

进入到pod mysql-0中,进行测试

kubectl exec -it mysql-0 bash

2. 用mysql-client链接mysql-0

mysql -h mysql-0

3. 创建库、表


  1. //创建数据库test


  2. create database test;


  3. //使用test库


  4. use test;


  5. //创建message表


  6. create table message (message varchar(50));


  7. //查看message表结构


  8. show create table message;

4. 插入数据


  1. //插入


  2. insert into message value("hello aloofjr");


  3. //查看


  4. select * from message;

6.jpg


四、测试备库

1. 连接mysql-1

mysql -h mysql-1.mysql

2. 查看库、表结构


  1. //查看数据库列表


  2. show databases;


  3. //使用test库


  4. use test;


  5. //查看表列表


  6. show tables;


  7. //查看message表结构


  8. show create table message;

3. 读取数据


  1. //查看


  2. select * from message;

4. 写入数据

insert into message values("hello world");

此时会报错 ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
这是因为mysql-1是一个只读备库,无法进行写操作。

7.jpg


五、测试mysql-read服务


  1. kubectl run mysql-client-loop --image=mysql:5.7 -i -t --rm --restart=Never --\


  2. bash -ic "while sleep 1; do mysql -h mysql-read -e 'SELECT @@server_id,NOW()'; done"

每秒查询一次数据库,可以观察到,调度到不同的server-id,即pod节点

8.jpg


六、扩缩容


  1. //扩容至5副本


  2. kubectl scale statefulset mysql --replicas=5


  3. //缩容只2副本


  4. kubectl scale statefulset mysql --replicas=2

七、清理


  1. kubectl delete statefulset mysql


  2. kubectl delete configmap,service,pvc -l app=mysql

八、总结

上面就是通过k8s部署一个一主多从mysql集群的过程,其中有几个重要知识点:

  • 通过configMap可以将配置和镜像解耦
  • 通过initContainers在pod启动前,做一些初始化工作
  • 通过requests设置pod所需的cpu和memory
  • 通过livenessProbe进行pod节点探活
  • 通过readnessProbe进行pod可用性检测

本文中用到的yaml文件见我的GitHub仓库AloofJr

本文转自: Kubernetes 部署 MySQL 集群-阿里云开发者社区

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论