本文将介绍如何在k8s上搭建一个主从的mysql集群,该集群满足如下要求
搭建一个主从复制(Master-Slave)的MySQL集群
从节点可以水平扩展
所有的写操作只能在主节点上执行
读操作可以在主从节点上执行
从节点能同步主节点的数据
创建主从的configmap 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 apiVersion : v1 kind : ConfigMap metadata : name : mysql namespace : weixnie labels : app : mysql data : master.cnf : | [mysqld] log-bin skip-grant-tables slave.cnf : | [mysqld] super-read-only skip-grant-tables
创建主从实例的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 apiVersion: v1 kind: Service metadata: name: mysql namespace: weixnie labels: app: mysql spec: ports: - name: mysql port: 3306 clusterIP: None selector: app: mysql --- apiVersion: v1 kind: Service metadata: name: mysql-read namespace: weixnie labels: app: mysql spec: ports: - name: mysql port: 3306 selector: app: mysql
这个无头服务给 StatefulSet 控制器为集合中每个 Pod 创建的 DNS 条目提供了一个宿主。 因为服务名为 mysql,所以可以通过在同一 Kubernetes 集群和名字中的任何其他 Pod 内解析 <Pod 名称>.mysql 来访问 Pod。
客户端服务称为 mysql-read,是一种常规服务,具有其自己的集群 IP。 该集群 IP 在报告就绪的所有MySQL Pod 之间分配连接。 可能的端点集合包括 MySQL 主节点和所有副本节点。
请注意,只有读查询才能使用负载平衡的客户端服务。 因为只有一个 MySQL 主服务器,所以客户端应直接连接到 MySQL 主服务器 Pod (通过其在无头服务中的 DNS 条目)以执行写入操作。
为mysql创建密码 1 2 3 4 5 6 7 8 9 10 apiVersion: v1kind: Secretmetadata: name: mysql-secret namespace: weixnie labels: app: mysqltype: Opaquedata: password: MTIzNDU2 # echo -n "123456" | base64
部署mysql的StatefulSet负载 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 190 191 apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql namespace: weixnie labels: app: mysql spec: selector: matchLabels: app: mysql serviceName: mysql replicas: 2 template: metadata: labels: app: mysql spec: initContainers: - name: init-mysql image: mysql:5.7 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: password command: - bash - "-c" - | set -ex [[ $(hostname) =~ -([0 -9 ]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} echo [mysqld] > /mnt/ conf.d/server-id.cnf echo server-id=$((100 + $ordinal )) >> /mnt/ conf.d/server-id.cnf if [[ ${ordinal} -eq 0 ]]; then cp /mnt/ config-map/master.cnf /m nt/conf.d else cp /mnt/ config-map/slave.cnf /m nt/conf.d fi volumeMounts: - name: conf mountPath: /mnt/ conf.d - name: config-map mountPath: /mnt/ config-map - name: clone-mysql image: ist0ne/xtrabackup:1.0 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: password command: - bash - "-c" - | set -ex [[ -d /var/ lib/mysql/my sql ]] && exit 0 [[ $(hostname) =~ -([0 -9 ]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} [[ $ordinal == 0 ]] && exit 0 ncat --recv-only mysql-$(($ordinal -1 )).mysql 3307 | xbstream -x -C /var/ lib/mysql xtrabackup --prepare --target-dir=/var/ lib/mysql volumeMounts: - name: data mountPath: /var/ lib/mysql subPath: mysql - name: conf mountPath: /etc/my sql/conf.d containers: - name: mysql image: mysql:5.7 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: password ports: - name: mysql containerPort: 3306 volumeMounts: - name: data mountPath: /var/ lib/mysql subPath: mysql - name: conf mountPath: /etc/my sql/conf.d resources: requests: cpu: 500 m memory: 1 Gi 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 - name: xtrabackup image: ist0ne/xtrabackup:1.0 ports: - name: xtrabackup containerPort: 3307 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: password command: - bash - "-c" - | set -ex cd /var/ lib/mysql if [[ -f xtrabackup_slave_info ]]; then mv xtrabackup_slave_info change_master_to.sql.in rm -f xtrabackup_binlog_info elif [[ -f xtrabackup_binlog_info ]]; then [[ $(cat xtrabackup_binlog_info) =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1 rm xtrabackup_binlog_info echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\ MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in fi if [[ -f change_master_to.sql.in ]]; then echo "Waiting for mysqld to be ready(accepting connections)" until mysql -h 127.0 .0.1 -uroot -p${MYSQL_ROOT_PASSWORD} -e "SELECT 1" ; do sleep 1 ; done echo "Initializing replication from clone position" mv change_master_to.sql.in change_master_to.sql.orig mysql -h 127.0 .0.1 -uroot -p${MYSQL_ROOT_PASSWORD} << EOF $(< change_master_to.sql.orig), MASTER_HOST='mysql-0.mysql.weixnie' , MASTER_USER='root' , MASTER_PASSWORD='${MYSQL_ROOT_PASSWORD}' , MASTER_CONNECT_RETRY=10 ; START SLAVE; EOF fi 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 --password=${MYSQL_ROOT_PASSWORD}" volumeMounts: - name: data mountPath: /var/ lib/mysql subPath: mysql - name: conf mountPath: /etc/my sql/conf.d volumes: - name: conf emptyDir: {} - name: config-map configMap: name: mysql volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce" ] resources: requests: storage: 10 Gi
测试 同命名空间下起了一个mysql客户端的工具进行测试,我们对主实例进行写,然后可以直接从从实例读取数据,说明主从数据复制成功。
1 2 3 4 5 6 7 8 9 10 11 12 bash-4.4# mysql -h mysql-0.mysql <<EOF CREATE DATABASE test; CREATE TABLE test.messages (message VARCHAR(250)); INSERT INTO test.messages VALUES ('hello' ); EOFbash-4.4# mysql -h mysql-read -e "SELECT * FROM test.messages" +---------+ | message | +---------+ | hello | +---------+
扩展副本数 使用MySQL复制,你可以通过添加副本节点来扩展读取查询的能力。 使用 StatefulSet,你可以使用单个命令执行此操作
1 kubectl scale statefulset mysql --replicas =5 -n weixnie