K8s-MySQL主从集群

K8s-MySQL主从集群

引言

该案例代码均可从https://github.com/WeiXiao-Hyy/k8s_example 获取,欢迎Star!

需求

  1. 一个"主从复制"的MySQL集群
  2. 有一个主节点Master
  3. 有多个从节点Slave
  4. 从节点需要能水平扩展
  5. 所以写操作只能在主节点上执行
  6. 读操作可以在所有节点上执行

xtrabackup 案例

xtrabackup原理和实战案例参考xtrabackup docker实战

MySQL conf文件配置

由于statefulset生成的pod命名为mysql-0,mysql-1依次递增,则可以取末尾的idx作为MySQL service-id.cnf文件中的mysqld属性。

yaml 复制代码
spec:
  initContainers:
    - name: init-mysql
      image: mysql:5.7
      command:
        - bash
        - "-c"
        - |
          set -ex
          # Generate mysql server-id from pod ordinal index.
          [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
          ordinal=${BASH_REMATCH[1]}
          echo [mysqld] > /mnt/conf.d/server-id.cnf
          # Add an offset to avoid reserved server-id=0 value.
          echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
          # Copy appropriate conf.d files from config-map to emptyDir.
          if [[ $ordinal -eq 0 ]]; then
            cp /mnt/config-map/master.cnf /mnt/conf.d/
          else
            cp /mnt/config-map/slave.cnf /mnt/conf.d/
          fi
      volumeMounts:
        - name: conf
          mountPath: /mnt/conf.d
        - name: config-map
          mountPath: /mnt/config-map

Headless Service创建

yaml 复制代码
# Headless service for stable DNS entries of StatefulSet members.
apiVersion: v1
kind: Service
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  ports:
    - name: mysql
      port: 3306
  clusterIP: None
  selector:
    app: mysql
---
# Client service for connecting to any MySQL instance for reads.
# For writes, you must instead connect to the master: mysql-0.mysql.
apiVersion: v1
kind: Service
metadata:
  name: mysql-read
  labels:
    app: mysql
spec:
  ports:
    - name: mysql
      port: 3306
  selector:
    app: mysql

创建HeadLess-Service,并且保证主节点的DNS为mysql-0.mysql,其他从节点为mysql-read。

从节点复制同步数据

yaml 复制代码
spec:
	initContainers:
		- name: clone-mysql
	    image: gcr.io/google-samples/xtrabackup:1.0
	    command:
	      - bash
	      - "-c"
	      - |
	        set -ex
	        # Skip the clone if data already exists.
	        [[ -d /var/lib/mysql/mysql ]] && exit 0
	        # Skip the clone on master (ordinal index 0).
	        [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
	        ordinal=${BASH_REMATCH[1]}
	        [[ $ordinal -eq 0 ]] && exit 0
	        # Clone data from previous peer.
	        ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
	        # Prepare the backup.
	        xtrabackup --prepare --target-dir=/var/lib/mysql
	    volumeMounts:
	      - name: data
	        mountPath: /var/lib/mysql
	        subPath: mysql
	      - name: conf
	        mountPath: /etc/mysql/conf.d

流程图如下:

从节点启动如何恢复数据

前提

  1. xtrabackup_salve_info文件存在则说明该节点为从节点
  2. xtrabackup_binlog_info 文件存在则说明该节点为主节点
  3. 从节点恢复数据启动主要需要获取两个字段,MASTER_LOG_FILE和MASTER_LOG_POS
yaml 复制代码
- name: xtrabackup
  image: gcr.io/google-samples/xtrabackup:1.0
  ports:
    - name: xtrabackup
      containerPort: 3307
  command:
    - bash
  - "-c"
    - |
      set -ex
      cd /var/lib/mysql
      
      # Determine binlog position of cloned data, if any.
      if [[ -f xtrabackup_slave_info ]]; then
        # XtraBackup already generated a partial "CHANGE MASTER TO" query
        # because we're cloning from an existing slave.
        mv xtrabackup_slave_info change_master_to.sql.in
        # Ignore xtrabackup_binlog_info in this case (it's useless).
        rm -f xtrabackup_binlog_info
      elif [[ -f xtrabackup_binlog_info ]]; then
        # We're cloning directly from master. Parse binlog position.
        [[ `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
      
      # Check if we need to complete a clone by starting replication.
      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"
        # In case of container restart, attempt this at-most-once.
        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',
        MASTER_USER='root',
        MASTER_PASSWORD=$MYSQL_ROOT_PASSWORD,
        MASTER_CONNECT_RETRY=10;
      START SLAVE;
      EOF
      fi
      
      # Start a server to send backups when requested by peers.
      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"
  volumeMounts:
    - name: data
      mountPath: /var/lib/mysql
      subPath: mysql
    - name: conf
      mountPath: /etc/mysql/conf.d
  resources:
    requests:
      cpu: 100m
      memory: 100Mi

流程图如下

等待MySQL服务启动操作:until mysql -h 127.0.0.1 -uroot -pPASSWORD -e "Select 1"; do sleep 1; done

结果测试

K8s执行效果

MySQL客户端执行效果

主节点mysql-0.mysql写入;从节点mysql-read读取。

相关推荐
小兜全糖(xdqt)43 分钟前
mysql数据同步到sql server
mysql·adb
Karoku0661 小时前
【企业级分布式系统】Zabbix监控系统与部署安装
运维·服务器·数据库·redis·mysql·zabbix
周全全1 小时前
MySQL报错解决:The user specified as a definer (‘root‘@‘%‘) does not exist
android·数据库·mysql
白云如幻1 小时前
MySQL的分组函数
数据库·mysql
秋意钟4 小时前
MySQL日期类型选择建议
数据库·mysql
ac-er88885 小时前
MySQL如何实现PHP输入安全
mysql·安全·php
桀桀桀桀桀桀5 小时前
数据库中的用户管理和权限管理
数据库·mysql
景天科技苑5 小时前
【云原生开发】K8S多集群资源管理平台架构设计
云原生·容器·kubernetes·k8s·云原生开发·k8s管理系统
wclass-zhengge6 小时前
K8S篇(基本介绍)
云原生·容器·kubernetes
颜淡慕潇6 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决