zoukankan      html  css  js  c++  java
  • Kubernetes:使用StatefulSet搭建MySQL集群(一主多从)

    背景介绍

    当我们用K8s管理MySql容器集群时,由于MySql的集群机制是每个实例有自己的存储空间,通过网络进行数据同步,并且数据库应用属于有状态的应用,故采用Deployment方式会很麻烦。

    K8s从1.5版本开始使用StatefulSet来编排有状态应用:

    • Pod会被顺序部署和顺序终结:StatefulSet中的各个 Pod会被顺序地创建出来,每个Pod都有一个唯一的ID,在创建后续 Pod 之前,首先要等前面的 Pod 运行成功并进入到就绪状态。删除会销毁StatefulSet 中的每个 Pod,并且按照创建顺序的反序来执行,只有在成功终结后面一个之后,才会继续下一个删除操作。

    • Pod具有唯一网络名称:Pod具有唯一的名称,而且在重启后会保持不变。通过Headless服务,基于主机名,每个 Pod 都有独立的网络地址,这个网域由一个Headless 服务所控制。这样每个Pod会保持稳定的唯一的域名,使得集群就不会将重新创建出的Pod作为新成员。

    • Pod能有稳定的持久存储:StatefulSet中的每个Pod可以有其自己独立的PersistentVolumeClaim对象。即使Pod被重新调度到其它节点上以后,原有的持久磁盘也会被挂载到该Pod。

    • Pod能被通过Headless服务访问到:客户端可以通过服务的域名连接到任意Pod。

    使用StatefulSet部署MySql

    •  configmap.yaml

    ConfigMap 提供 my.cnf 覆盖,独立控制 MySQL 主服务器和从服务器的配置。主服务器能够将复制日志提供给从服务器,从服务器拒绝任何不是通过复制进行的写操作。

     1 apiVersion: v1
     2 kind: ConfigMap
     3 metadata:
     4   name: mysql
     5   labels:
     6     app: mysql
     7 data:
     8   master.cnf: |
     9     # Apply this config only on the master.
    10     [mysqld]
    11     log-bin  # 主mysql激活二进制日志
    12     #设置时区和字符集
    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     [mysqld]
    21     super-read-only  # 从mysql上面设置为只读
    22     #设置时区和字符集
    23     default-time-zone='+8:00'
    24     character-set-client-handshake=FALSE
    25     character-set-server=utf8mb4
    26     collation-server=utf8mb4_unicode_ci
    27     init_connect='SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci'
    [root@localhost k8s_mysql]# kubectl apply -f configmap.yaml 
    configmap/mysql created
    [root@localhost k8s_mysql]# kubectl get cm
    NAME    DATA   AGE
    mysql   2      107s
    • services.yaml

    Headless Service 给 StatefulSet 控制器为集合中每个 Pod 创建的 DNS 条目提供了一个宿主。因为 Headless Service 名为 mysql,所以可以通过在同一 Kubernetes 集群和 namespace 中的任何其他 Pod 内解析 <pod-name>.mysql 来访问 Pod。

    请注意,只有读取查询才能使用负载平衡的客户端 Service。因为只有一个 MySQL 主服务器,所以客户端应直接连接到 MySQL 主服务器 Pod (通过其在 Headless Service 中的 DNS 条目)以执行写入操作。

     1 # Headless service for stable DNS entries of StatefulSet members.
     2 apiVersion: v1
     3 kind: Service
     4 metadata:
     5   name: mysql
     6   labels:
     7     app: mysql
     8 spec:
     9   ports:
    10   - name: mysql
    11     port: 3306
    12   clusterIP: None
    13   selector:
    14     app: mysql
    15 ---
    16 # Client service for connecting to any MySQL instance for reads.
    17 # For writes, you must instead connect to the master: mysql-0.mysql.
    18 apiVersion: v1
    19 kind: Service
    20 metadata:
    21   name: mysql-read
    22   labels:
    23     app: mysql
    24 spec:
    25   ports:
    26   - name: mysql
    27     port: 3306
    28   selector:
    29     app: mysql
    [root@localhost k8s_mysql]# kubectl apply -f services.yaml
    service/mysql created
    service/mysql-read created
    [root@localhost k8s_mysql]# kubectl get service
    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    kubernetes   ClusterIP   10.43.0.1       <none>        443/TCP    7d17h
    mysql        ClusterIP   None            <none>        3306/TCP   20s
    mysql-read   ClusterIP   10.43.118.155   <none>        3306/TCP   20s
    • statefulset.yaml
      1 apiVersion: apps/v1
      2 kind: StatefulSet
      3 metadata:
      4   name: mysql
      5 spec:
      6   selector:
      7     matchLabels:
      8       app: mysql
      9   serviceName: mysql
     10   replicas: 3
     11   template:
     12     metadata:
     13       labels:
     14         app: mysql
     15     spec:
     16       initContainers:
     17       - name: init-mysql
     18         image: mysql:5.7
     19         command:
     20         - bash
     21         - "-c"
     22         - |
     23           set -ex
     24           # Generate mysql server-id from pod ordinal index.
     25           [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
     26           ordinal=${BASH_REMATCH[1]}
     27           echo [mysqld] > /mnt/conf.d/server-id.cnf
     28           # Add an offset to avoid reserved server-id=0 value.
     29           echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
     30           # Copy appropriate conf.d files from config-map to emptyDir.
     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: gcr.io/google-samples/xtrabackup:1.0
     43         command:
     44         - bash
     45         - "-c"
     46         - |
     47           set -ex
     48           # Skip the clone if data already exists.
     49           [[ -d /var/lib/mysql/mysql ]] && exit 0
     50           # Skip the clone on master (ordinal index 0).
     51           [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
     52           ordinal=${BASH_REMATCH[1]}
     53           [[ $ordinal -eq 0 ]] && exit 0
     54           # Clone data from previous peer.
     55           ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
     56           # Prepare the backup.
     57           xtrabackup --prepare --target-dir=/var/lib/mysql
     58         volumeMounts:
     59         - name: data
     60           mountPath: /var/lib/mysql
     61           subPath: mysql
     62         - name: conf
     63           mountPath: /etc/mysql/conf.d
     64       containers:
     65       - name: mysql
     66         image: mysql:5.7
     67         env:
     68         - name: MYSQL_ALLOW_EMPTY_PASSWORD
     69           value: "1"
     70         ports:
     71         - name: mysql
     72           containerPort: 3306
     73         volumeMounts:
     74         - name: data
     75           mountPath: /var/lib/mysql
     76           subPath: mysql
     77         - name: conf
     78           mountPath: /etc/mysql/conf.d
     79         resources:
     80           requests:
     81             cpu: 500m
     82             memory: 1Gi
     83         livenessProbe:
     84           exec:
     85             command: ["mysqladmin", "ping"]
     86           initialDelaySeconds: 30
     87           periodSeconds: 10
     88           timeoutSeconds: 5
     89         readinessProbe:
     90           exec:
     91             # Check we can execute queries over TCP (skip-networking is off).
     92             command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
     93           initialDelaySeconds: 5
     94           periodSeconds: 2
     95           timeoutSeconds: 1
     96       - name: xtrabackup
     97         image: gcr.io/google-samples/xtrabackup:1.0
     98         ports:
     99         - name: xtrabackup
    100           containerPort: 3307
    101         command:
    102         - bash
    103         - "-c"
    104         - |
    105           set -ex
    106           cd /var/lib/mysql
    107 
    108           # Determine binlog position of cloned data, if any.
    109           if [[ -f xtrabackup_slave_info && "x$(<xtrabackup_slave_info)" != "x" ]]; then
    110             # XtraBackup already generated a partial "CHANGE MASTER TO" query
    111             # because we're cloning from an existing slave. (Need to remove the tailing semicolon!)
    112             cat xtrabackup_slave_info | sed -E 's/;$//g' > change_master_to.sql.in
    113             # Ignore xtrabackup_binlog_info in this case (it's useless).
    114             rm -f xtrabackup_slave_info xtrabackup_binlog_info
    115           elif [[ -f xtrabackup_binlog_info ]]; then
    116             # We're cloning directly from master. Parse binlog position.
    117             [[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1
    118             rm -f xtrabackup_binlog_info xtrabackup_slave_info
    119             echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',
    120                   MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
    121           fi
    122 
    123           # Check if we need to complete a clone by starting replication.
    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 
    128             echo "Initializing replication from clone position"
    129             mysql -h 127.0.0.1 
    130                   -e "$(<change_master_to.sql.in), 
    131                           MASTER_HOST='mysql-0.mysql', 
    132                           MASTER_USER='root', 
    133                           MASTER_PASSWORD='', 
    134                           MASTER_CONNECT_RETRY=10; 
    135                         START SLAVE;" || exit 1
    136             # In case of container restart, attempt this at-most-once.
    137             mv change_master_to.sql.in change_master_to.sql.orig
    138           fi
    139 
    140           # Start a server to send backups when requested by peers.
    141           exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c 
    142             "xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"
    143         volumeMounts:
    144         - name: data
    145           mountPath: /var/lib/mysql
    146           subPath: mysql
    147         - name: conf
    148           mountPath: /etc/mysql/conf.d
    149         resources:
    150           requests:
    151             cpu: 100m
    152             memory: 100Mi
    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       accessModes: ["ReadWriteOnce"]
    164       resources:
    165         requests:
    166           storage: 10Gi
    1 [root@localhost k8s_mysql]# kubectl apply -f satefulset.yml
    2 [root@localhost k8s_mysql]# kubectl get po -o wide
    3 NAME      READY   STATUS             RESTARTS   AGE     IP           NODE                    NOMINATED NODE   READINESS GATES
    4 mysql-0   2/2     Running            5          13s     10.42.1.73   localhost.localdomain   <none>           <none>
    5 mysql-1   2/2     Running            0          25s     10.42.1.74   localhost.localdomain   <none>           <none>
    6 mysql-2   1/2     CrashLoopBackOff   8          18m     10.42.1.75   localhost.localdomain   <none>           <none>  

    ps:由于我只有一台性能不咋地的虚拟机,因此导致其中一个节点不能运行起来,不过能在此说明问题就行。

    • 验证
     1 root@mysql-0:/# mysql -h mysql-0.mysql
     2 Welcome to the MySQL monitor.  Commands end with ; or g.
     3 Your MySQL connection id is 1360
     4 Server version: 8.0.18 MySQL Community Server - GPL
     5 
     6 Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
     7 
     8 Oracle is a registered trademark of Oracle Corporation and/or its
     9 affiliates. Other names may be trademarks of their respective
    10 owners.
    11 
    12 Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.
    13 
    14 mysql> show databases;
    15 +--------------------+
    16 | Database           |
    17 +--------------------+
    18 | information_schema |
    19 | mysql              |
    20 | performance_schema |
    21 | sys                |
    22 +--------------------+
    23 4 rows in set (0.00 sec)
    24 
    25 mysql> create database addtest;
    26 Query OK, 1 row affected (0.01 sec)
    27 
    28 mysql> show databases;
    29 +--------------------+
    30 | Database           |
    31 +--------------------+
    32 | addtest            |
    33 | information_schema |
    34 | mysql              |
    35 | performance_schema |
    36 | sys                |
    37 +--------------------+
    38 5 rows in set (0.00 sec)
    39 
    40 mysql> exit
    41 Bye
    42 root@mysql-0:/# mysql -h mysql-1.mysql
    43 Welcome to the MySQL monitor.  Commands end with ; or g.
    44 Your MySQL connection id is 1217
    45 Server version: 8.0.18 MySQL Community Server - GPL
    46 
    47 Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
    48 
    49 Oracle is a registered trademark of Oracle Corporation and/or its
    50 affiliates. Other names may be trademarks of their respective
    51 owners.
    52 
    53 Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.
    54 
    55 mysql> show databases;
    56 +--------------------+
    57 | Database           |
    58 +--------------------+
    59 | addtest            |
    60 | information_schema |
    61 | mysql              |
    62 | performance_schema |
    63 | sys                |
    64 +--------------------+
    65 5 rows in set (0.00 sec)
    66 
    67 mysql> exit
  • 相关阅读:
    使用 libevent 和 libev 提高网络应用性能
    An existing connection was forcibly closed by the remote host
    各种浏览器的兼容css
    vs输出窗口,显示build的时间
    sass
    网站设置404错误页
    List of content management systems
    css footer not displaying at the bottom of the page
    强制刷新css
    sp_executesql invalid object name
  • 原文地址:https://www.cnblogs.com/cooper-73/p/12988614.html
Copyright © 2011-2022 走看看