Explain in detail the whole process of MeterSphere configuring external Mysql5.7

Explain in detail the whole process of MeterSphere configuring external Mysql5.7

I bought cloud server from cnaaa.com.

Build a MySQL cluster with master-slave replication

img

Principle of local storage

Local storage is used here, that is to say, users hope that Kubernetes can directly use the local disk directory on the host without relying on remote storage services to provide persistent container Volume 1. We fix the storage
on a node, But when the Pod is scheduled, it floats around. How can the Pod be fixed on the PVC through the PVC?
2. Is it okay to add a nodeAffinity to this Pod?

Of course, but this destroys the developer's definition of resource objects in a disguised way, and the developer should not need to consider the details of scheduling all the time. Scheduling changes should be handed over to O&M. So in order to implement local storage, we adopted the method of delayed binding . The method is very simple. We all know that StorageClass is generally designed by operation and maintenance personnel. We only need to specify no-provisioner in StorageClass. This is because Local Persistent Volume does not yet support Dynamic Provisioning, so it cannot automatically create a corresponding PV when a user creates a PVC. At the same time, this StorageClass also defines a property of volumeBindingMode=WaitForFirstConsumer. It is a very important feature in Local Persistent Volume, namely: late binding.

Create a PV

First, pre-allocate several PVs on the Node (the IP of the Node node used in the experiment is node1) (it is not recommended to do this in production), and ensure that there is a corresponding directory on node1

ssh root@node1
mkdir -pv /data/svr/projects/{
    
    mysql,mysql2,mysql3}
vim 01-persistentVolume-1.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-mysql-pv
spec:
  capacity:
    storage: 15Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /data/svr/projects/mysql
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node1
vim 01-persistentVolume-2.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-mysql-pv-2
spec:
  capacity:
    storage: 15Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /data/svr/projects/mysql2
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node1
vim 01-persistentVolume-3.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-mysql-pv-3
spec:
  capacity:
    storage: 15Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /data/svr/projects/mysql3
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - node1

Remember, this is not recommended in production. I just manually pre-created it for experimental purposes. **The formal method should use Dynamic Provisioning through StorageClass instead of Static Provisioning mechanism to produce PV

[root@master mysql]# kubectl apply -f 01-persistentVolume-1.yaml 
persistentvolume/example-mysql-pv created
[root@master mysql]# kubectl apply -f 01-persistentVolume-2.yaml 
persistentvolume/example-mysql-pv-2 created
[root@master mysql]# kubectl apply -f 01-persistentVolume-3.yaml 
persistentvolume/example-mysql-pv-3 created
[root@master mysql]# kubectl get pv
NAME                 CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS    REASON   AGE
example-mysql-pv     15Gi       RWO            Delete           Available           local-storage            8s
example-mysql-pv-2   15Gi       RWO            Delete           Available           local-storage            6s
example-mysql-pv-3   15Gi       RWO            Delete           Available           local-storage            3s
02-storageclass.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
[root@master mysql]# kubectl apply -f 02-storageclass.yaml 
storageclass.storage.k8s.io/local-storage created
[root@master mysql]# kubectl get sc
NAME            PROVISIONER                    RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-storage   kubernetes.io/no-provisioner   Delete          WaitForFirstConsumer   false                  5s

Create Namespace

03-mysql-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: mysql
  labels:
    app: mysql
[root@master mysql]# kubectl apply -f 03-mysql-namespace.yaml 
namespace/mysql unchanged
[root@master mysql]# kubectl get ns -n mysql
NAME              STATUS   AGE
mysql             Active   3d

Create a database configuration file configmap

Use ConfigMap to assign different configuration files to Master/Slave nodes
vim 04-mysql-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql
  namespace: mysql
  labels:
    app: mysql
data:
  master.cnf: |
    # Master配置
    [mysqld]
    log-bin=mysqllog
    skip-name-resolve
  slave.cnf: |
    # Slave配置
    [mysqld]
    super-read-only
    skip-name-resolve
    log-bin=mysql-bin
    replicate-ignore-db=mysql
[root@master mysql]# kubectl apply -f 04-mysql-configmap.yaml 
configmap/mysql created
[root@master mysql]# kubectl get cm -n mysql
NAME               DATA   AGE
mysql              2      5s

Create a MySQL password Secret

05-mysql-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
  namespace: mysql
  labels:
    app: mysql
type: Opaque
data:
  password: MTIzNDU2 # echo -n "123456" | base64
[root@master mysql]# kubectl apply -f 05-mysql-secret.yaml 
secret/mysql-secret created
[root@master mysql]# kubectl get secret -n mysql
NAME                  TYPE                                  DATA   AGE
mysql-secret          Opaque                                1      18s

Use Service to provide read-write separation for MySQL

06-mysql-services.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: mysql
  labels:
    app: mysql
spec:
  ports:
  - name: mysql
    port: 3306
  clusterIP: None
  selector:
    app: mysql
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-read
  namespace: mysql
  labels:
    app: mysql
spec:
  ports:
  - name: mysql
    port: 3306
  selector:
    app: mysql

All user write requests must directly access the Master node in the form of DNS records, that is, the DNS record mysql-0.mysql.

All user read requests must access the automatically assigned DNS record and can be forwarded to any Master or Slave node, that is, the DNS record mysql-read.

[root@master mysql]# kubectl apply -f 06-mysql-services.yaml 
service/mysql created
service/mysql-read created
[root@master mysql]# kubectl get svc -n mysql
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
mysql        ClusterIP   None           <none>        3306/TCP   3s
mysql-read   ClusterIP   10.107.90.19   <none>        3306/TCP   3s

Create a MySQL cluster instance

Use StatefulSet to build MySQL master-slave cluster
07-mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: mysql
  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
          # 从Pod的序号,生成server-id
          [[ $(hostname) =~ -([0-9]+)$ ]] || exit 1
          ordinal=${
    
    BASH_REMATCH[1]}
          echo [mysqld] > /mnt/conf.d/server-id.cnf
          # 由于server-id不能为0,因此给ID加100来避开它
          echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
          # 如果Pod的序号为0,说明它是Master节点,从ConfigMap里把Master的配置文件拷贝到/mnt/conf.d目录下
          # 否则,拷贝ConfigMap里的Slave的配置文件
          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
      - name: clone-mysql
        image: gcr.io/google-samples/xtrabackup:1.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        command:
        - bash
        - "-c"
        - |
          set -ex
          # 拷贝操作只需要在第一次启动时进行,所以数据已经存在则跳过
          [[ -d /var/lib/mysql/mysql ]] && exit 0
          # Master 节点(序号为 0)不需要这个操作
          [[ $(hostname) =~ -([0-9]+)$ ]] || exit 1
          ordinal=${
    
    BASH_REMATCH[1]}
          [[ $ordinal == 0 ]] && exit 0
          # 使用ncat指令,远程地从前一个节点拷贝数据到本地
          ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
          # 执行 --prepare,这样拷贝来的数据就可以用作恢复了
          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: mysql
        image: mysql:5.7
        env:
 #        - name: MYSQL_ALLOW_EMPTY_PASSWORD
 #          value: "1"
        - 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/mysql/conf.d
        resources:
          requests:
            cpu: 500m
            memory: 1Gi
        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: gcr.io/google-samples/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
          # 从备份信息文件里读取MASTER_LOG_FILE和MASTER_LOG_POS这2个字段的值,用来拼装集群初始化SQL
          if [[ -f xtrabackup_slave_info ]]; then
            # 如果xtrabackup_slave_info文件存在,说明这个备份数据来自于另一个Slave节点
            # 这种情况下,XtraBackup工具在备份的时候,就已经在这个文件里自动生成了“CHANGE MASTER TO”SQL语句
            # 所以,只需要把这个文件重命名为change_master_to.sql.in,后面直接使用即可
            mv xtrabackup_slave_info change_master_to.sql.in
            # 所以,也就用不着xtrabackup_binlog_info了
            rm -f xtrabackup_binlog_info
          elif [[ -f xtrabackup_binlog_info ]]; then
            # 如果只是存在xtrabackup_binlog_info文件,说明备份来自于Master节点,就需要解析这个备份信息文件,读取所需的两个字段的值
            [[ $(cat xtrabackup_binlog_info) =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1
            rm xtrabackup_binlog_info
            # 把两个字段的值拼装成SQL,写入change_master_to.sql.in文件
            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
            # 但一定要先等MySQL容器启动之后才能进行下一步连接MySQL的操作
            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"
            # 将文件change_master_to.sql.in改个名字
            # 防止这个Container重启的时候,因为又找到了change_master_to.sql.in,从而重复执行一遍初始化流程
            mv change_master_to.sql.in change_master_to.sql.orig
            # 使用change_master_to.sql.orig的内容,也就是前面拼装的SQL,组成一个完整的初始化和启动Slave的SQL语句
            mysql -h 127.0.0.1 -uroot -p${MYSQL_ROOT_PASSWORD} << EOF
          $(< change_master_to.sql.orig),
            MASTER_HOST='mysql-0.mysql.mysql',
            MASTER_USER='root',
            MASTER_PASSWORD='${MYSQL_ROOT_PASSWORD}',
            MASTER_CONNECT_RETRY=10;
          START SLAVE;
          EOF
          fi
          # 使用ncat监听3307端口。
          # 它的作用是,在收到传输请求的时候,直接执行xtrabackup --backup命令,备份MySQL的数据并发送给请求者
          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/mysql/conf.d
      volumes:
      - name: conf
        emptyDir: {
    
    }
      - name: config-map
        configMap:
          name: mysql
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes:
      - "ReadWriteOnce"
      storageClassName: local-storage
      resources:
        requests:
          storage: 3Gi

The overall StatefulSet has two Replicas, one Master and one Slave, and then use the init-mysql initContainers to initialize the configuration file. Then use the initContainers of clone-mysql for data transmission; at the same time, use the sidecar container of xtrabackup for SQL initialization and data transmission.
Create a StatefulSet

kubectl apply -f 07-mysql-statefulset.yaml

It can be seen that after the StatefulSet starts successfully, there will be two Pods running. Next, we can try to initiate a request to this MySQL cluster and perform some SQL operations to verify that it is normal. The whole process will be very slow because of pulling mysql and a foreign image of gcr.io/google-samples/xtrabackup:1.0, but after creating mysql-0 and pulling it once, the subsequent creation of m>ysql-1 is relatively fast.
Finally, the container checks the running status of the pod

[root@master mysql]# kubectl get po -n mysql
NAME      READY   STATUS    RESTARTS   AGE
mysql-0   2/2     Running   0          2m7s
mysql-1   2/2     Running   0          116s

service verification

Verify master-slave status
[root mysql]# kubectl -n mysql exec mysql-1 -c mysql -- bash -c "mysql -uroot -p123456 -e 'show slave status \G'"
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: mysql-0.mysql.mysql
                  Master_User: root
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mysqllog.000003
          Read_Master_Log_Pos: 154
               Relay_Log_File: mysql-1-relay-bin.000002
                Relay_Log_Pos: 319
        Relay_Master_Log_File: mysqllog.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: mysql0
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 154
              Relay_Log_Space: 528
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 100
                  Master_UUID: f8c7768a-6702-11ec-a648-c204e42fb62e
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
mysql: [Warning] Using a password on the command line interface can be insecure.
Next, we create databases and tables and insert databases through the Master container
[root@master mysql]# kubectl -n mysql exec mysql-0 -c mysql -- bash -c "mysql -uroot -p123456 -e 'create database test'"

[root@master mysql]# kubectl -n mysql exec mysql-0 -c mysql -- bash -c "mysql -uroot -p123456 -e 'use test;create table counter(c int);'"

[root@master mysql]# kubectl -n mysql exec mysql-0 -c mysql -- bash -c "mysql -uroot -p123456 -e 'use test;insert into counter values(123)'"

[root@master mysql]# kubectl -n mysql exec mysql-1 -c mysql -- bash -c "mysql -uroot -p123456 -e 'use test;select * from counter'"  
c
123
When you see the output, the master-slave synchronization is normal
extension node
[root@master mysql]# kubectl -n mysql scale statefulset mysql -—replicas=3
[root@master mysql]# kubectl get po -n mysql
NAME      READY   STATUS    RESTARTS   AGE
mysql-0   2/2     Running   0          11m
mysql-1   2/2     Running   0          11m
mysql-2   2/2     Running   0          20s
Check whether the expansion node data has been synchronized
kubectl -n mysql exec mysql-2 -c mysql -- bash -c "mysql -uroot -p123456 -e 'use test;select * from counter’"  
c
123

Guess you like

Origin blog.csdn.net/weixin_53641036/article/details/127080459