StatefulSet[实例]-Mysql集群

Introduce

基于StatefulSet搭建K8s集群中的Mysql集群

  1. —个‘主从复制”(MaserˉSlaveReplicatjon)的MySQL集群;

  2. 有一个主节点(Master);

  3. 有多个从节点(Slave);

  4. 从节点需要能水平扩展;

  5. 所有写操作只能在主节点上执行;

  6. 读操作可以在所有节点上执行

How to work

  1. 通过XtraBackup实现MySql备份

  2. 配置从节点,复制到/var/lib/mysql,执行

    CHANGE MASTER TO
    MASTER_HOST='$masterip';
    MASTER_USER='xxx';
    MATSER_PASSWORK='xxx';
    # 这个文件来资源第一个创建的xtrabackup_binlog_info
    MASTER_LOG_FILE='TheMaster-bin.00001';
    MASTER_LOG_POS=481;
  3. 启动节点备份:

    START SLAVE;
  4. 添加节点

Deploy

  1. ConfigMap-MySql

    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: mysql
    labels:
    app: mysql
    data:
    master-conf: |
    # 主节点配置文件
    [mysqld]
    log-bin
    slave.conf: |
    # 从节点配置文件
    super-read-only
  2. svc

    apiVersion: v1
    kind: Service
    metadata:
    name: mysql-headless
    labels:
    app: mysql
    spec:
    clusterIP: None
    selector:
    app: mysql
    ports:
    - port: 3306
    name: mysql
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: mysql-read
    labels:
    app: mysql
    spec:
    selector:
    app: mysql
    ports:
    - port: 3306
    name: mysql
  3. StatefulSet

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
    name: mysql-statefulset
    spec:
    selector:
    matchLabels:
    app: mysql # 必须匹配 .spec.template.metadata.labels
    serviceName: "mysql-headless"
    replicas: 1 # 默认值是 1
    minReadySeconds: 10 # 默认值是 0
    template:
    metadata:
    labels:
    app: mysql # 必须匹配 .spec.selector.matchLabels
    spec:
    terminationGracePeriodSeconds: 10
    initContainers:
    - name: init-mysql
    image: mysql:8.0.
    command:
    - bash
    - "-c"
    - |
    set -ex
    # 从Pod的序号生成server-id
    [[ `hostname` =~ -([0-9]+) $ ]] exit ]
    ordinal=${BASH_REMATCH[1]}
    echo [mysqld] > /mnt/conf.d/server-id.cnf
    #由于server-1d=0有特殊含义, 因此给ID加一个100避开它
    echo server-id=$(100+$ordinal)) >> /mnt/conf.d/server-id.crd

    if [[ $ordinal -eq 0 ]] ; then
    cp /mnt/config-map/master.conf /mnt/conf.d/
    else
    cp /mnt/config-map/slave.conf /mnt/conf.d/
    fi
    volumeMounts:
    - name: conf
    mountPath: /mnt/conf.d
    - name: config-map
    mountPath: /mnt/config-map
    - name: clone-mysql
    image: grc.io/google-samples/xtrabackup:1.0
    command:
    - bash
    - "-c"
    - |
    set -ex
    # 复制操作只要在第一次启动运行,数据存在就pass
    [ [ -d /var/lib/mysql/mysql ] ] && exit 0
    # 主节点(序号为0)不需要进行该操作
    [[ `hostname` =~ -([0-9+)$ ]] && exit 1
    ordinal=${BASH_REMATCH[1]}
    # 使用nact 远程从一个节点复制数据到本地
    nact --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/mysql/conf.d
    containers:
    - name: xtrabackup
    image: grc.io/google-samples/xtrabackup:1.0
    ports:
    - name: xtrabackup
    containerPort: 3007
    command:
    - bash
    - "-c"
    - |
    set -ex
    cd /var/lib/mysql

    # 从备份文件里面读取MASTER_LOG_FILEM 和 MASTER_LOG_POS 这俩个字段的值
    if [[ -f xtrabackup_slave_info ]] ; then
    # 如果xtrabackup_slave_info 存在,说明备份数据来自另外一个节点
    mv xtrabackup_slave_info change change_master_to.sql.in
    rm -f xtrabackup_slave_info
    elifi [[ -f xtrabackup_binlog_info ]]; then
    # 如果只存在 xtrabackup_binlog_info 文件,说明备份来自主节点
    [[ `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

    # 如果change_master_to.sql.in 存在吗,进行集群初始化
    if [[ -f change_master_to.sql.in ]];then
    echo "Waiting ofr mysqld to be ready (Accepting connections)"
    until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done

    echo "Initializing replication from clone position"
    # 把change_master_to.sql.in文件重命名,防止重复初始化
    mv change_master_to.sql.in change_master_to.sql.in.orig
    mysql -h 127.0.0.1 <<EOF
    $(<change_master_to.sql.in.orig),
    MASTER_HOST='myslq-0.mysql'
    MASTER_USER='root',
    MASTER_PASSWORD='',
    MASTER_CONNECT_RETRY=10;
    START SLAVE;
    EOF
    fi

    # ncat 监听3307,收到传输请求执行 xtrabackup --backup
    exec ncat --listen --keep-one --send-only --max-conns=1 3308 -c \
    " xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root "
    volumeMounts:
    - mountPath: /var/lib/mysql
    name: data
    subPath: mysql
    - mountPath: conf
    name: conf
    subPath: /etc/mysql/conf.d
    - name: mysql
    image: mysql:8.0.26
    env:
    - name: MYSQL_ALLOW_EMPTY_PASSWORD
    value: "1"
    - name: MYSQL_ROOT_PASSWORD
    value: root
    - name: MYSQL_USER_HOST
    value: '%'
    - name: MYSQL_ROOT_HOST
    value: '%'
    - name: MYSQL_PORT
    value: "3306"
    - name: TZ
    value: Asia/Shanghai
    - name: LANG
    value: en_US.UTF-8
    ports:
    - containerPort: 3306
    name: mysql
    volumeMounts:
    - mountPath: /var/lib/mysql
    name: data
    - mountPath: /etc/mysql/conf.d
    name: conf
    resources:
    requests:
    cpu: 500m
    memory: 1Gi
    livenessProbe:
    exec:
    command: [mysqladmin,"ping"]
    initialDelaySeconds: 30
    periodSeconds: 10
    timeoutSeconds: 5
    readinessProbe:
    exec:
    command: ["mysql","-h","127.0.0.1","-e","SELECT 1"]
    initialDelaySeconds: 5
    periodSeconds: 2
    timeoutSeconds: 1
    volumes:
    - name: conf
    emptyDir: { }
    - name: config-map
    configMap:
    name: mysql