前言:
微服務技術是現在非常流行的一種技術,許許多多的大公司采用微服務架構,這樣可以對它們的業務隨時進行拓展或者縮減服務量。
具體的微服務架構了解可以自己百度了解,本文記錄的主要是使用Kubernetes對Mysql集群服務進行搭建。
Mysql集群服務描述:
1.搭建一個主從復制的Mysql集群
2.一個主節點“Master” 多個從節點“Slave”
3.所有的寫操作,只能在主節點上執行;
4.讀操作可以在所有節點上執行
5.從節點需要能水平擴展; (注:本文的存儲券pv采用的nfs服務,如果想對節點進行拓展需要添加PV券。)(這點后續待完善)
圖形描述:

分析情況:
首先我們部署的Mysql服務是主從復制+讀寫分離的,那么在主從的節點上肯定就是有區別的,所以我們在部署Pod的時候需要將它們區分開。
在搭建這套服務的時候有三個需要重點問題:
第1個問題: 區分開Master和Slave節點的配置文件
第2個問題:在Slave節點開始運行的時候需要克隆前一個節點的數據(這里采用的是StatefulSet進行部署,所以是有序的,節點2克隆節點1,節點1克隆節點0以此類推)
第3個問題:在設置好配置文件和同步好數據之后,就需要在 Slave 節點第一次啟動之前,需要執行一些初始化 SQL 操作(綁定上Master節點開始主從復制)
代碼實現:
目錄:
1.拉取所需鏡像(pull-google.com.sh)
2.配置數據持久化(PersistentVolume)
3.配置Master和Slave節點所需的不同配置信息(ConfigMap)
4.創建Mysql對外服務(Service)
5.定義Mysql容器(StatefulSet)
1.拉取所需鏡像:
下面是拉取gcr.io鏡像源腳本並拉取鏡像
[root@k8s-m~ ]# cat /usr/local/bin/pull-google.com.sh image=$1 echo $1 img=`echo $image | sed 's/k8s\.gcr\.io/anjia0532\/google-containers/g;s/gcr\.io/anjia0532/g;s/\//\./g;s/ /\n/g;s/_/-/g;s/anjia0532\./anjia0532\//g' | uniq | awk '{print ""$1""}'` echo "docker pull $img" docker pull $img echo "docker tag $img $image" docker tag $img $image [root@k8s-m~ ]# chmod +x /usr/local/bin/pull-google.com.sh [root@k8s-m~ ]# pull-google.com.sh gcr.io/google-samples/xtrabackup:1.0
2.我使用的是NFS服務進行資源存儲。我直接將NFS服務器裝在了Master主節點上,如果有條件的也可以專門制作一台NFS服務器。
由於我們搭建的是Mysql服務集群,所以就涉及到了數據持久化。那么這里准備了三個持久化硬盤提供給一個Master和兩個Slave節點使用。
# 在master上安裝nfs服務 [root@master ~]# yum install nfs-utils -y
在配置好NFS服務器之后,接下來就是配置好PV存儲券:
這里我配置了三個存儲券:然后都是存在kerry命名空間下的
apiVersion: v1 kind: PersistentVolume metadata: name: pv-a namespace: kerry spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce - ReadOnlyMany #persistentVolumeReclaimPolicy: Retain persistentVolumeReclaimPolicy: Recycle nfs: server: 192.168.29.200 path: /net/mysql-0
--- apiVersion: v1 kind: PersistentVolume metadata: name: pv-b namespace: kerry spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce - ReadOnlyMany #persistentVolumeReclaimPolicy: Retain persistentVolumeReclaimPolicy: Recycle nfs: server: 192.168.29.200 path: /net/mysql-1
--- apiVersion: v1 kind: PersistentVolume metadata: name: pv-c namespace: kerry spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce - ReadOnlyMany #persistentVolumeReclaimPolicy: Retain persistentVolumeReclaimPolicy: Recycle nfs: server: 192.168.29.200 path: /net/mysql-2
3.創建configMap配置字典(以為有主從復制和讀寫分離的區分,所以在配置信息上也有所不同)
apiVersion: v1 kind: ConfigMap metadata: name: mysql namespace: kerry labels: app: mysql data: master.cnf: | # 主節點Mysql的配置文件
#master.cnf開啟了log-bin,即:使用二進制文件的方式進行主從復制,這是一個標准的設置 [mysqld] log-bin slave.cnf: | # 從節點Mysql的配置文件
#slave.cnf開啟了super-read-only,代表的是從節點會拒絕除了主節點的數據同步操作之外的所以寫操作
# 即:它對用戶是只讀的 [mysqld] super-read-only
4.創建Mysql對外服務(這里配置了三個SVC)
4.1這個Service負責統一管理所有的Mysql服務Pod
apiVersion: v1 kind: Service metadata: name: mysql-headless namespace: kerry labels: app: mysql spec: ports: - name: mysql port: 3306 clusterIP: None selector: app: mysql
4.2這個Service負責統一管理擁有讀權限的Pod
apiVersion: v1 kind: Service metadata: name: mysql-read namespace: kerry labels: app: mysql spec: ports: - name: mysql port: 3306 targetPort: 3306 nodePort: 30036 type: NodePort selector: app: mysql
4.3這個Service負責統一管理擁有讀寫權限的Pod,也就是Master節點pod
apiVersion: v1 kind: Service metadata: name: mysql-readwrite namespace: kerry labels: app: mysql spec: ports: - name: mysql port: 3306 targetPort: 3306 nodePort: 30006 selector: statefulset.kubernetes.io/pod-name: mysql-ss-0 type: NodePort
5.定義Mysql容器(配置StatefulSet)(最重要的一步,)
在配置Pod模板呢,首先涉及到了四個模塊
InitContainers:
1.初始化Mysql配置文件(為Master和slave節點配置上對應的配置信息 (.cnf) )
2.克隆Mysql數據(為當前節點配置上一個節點的數據) 【0-Master節點不需要,1-Slave節點配置0-Master的,2-Slave節點配置1-Slave節點的,以此類推】
Containers:
3.Mysql數據庫(配置上存活探針等等...)
4.初始化SQL操作(在Slave節點第一次啟動之前,需要執行初始化SQL操作,使之綁定上Master節點主從同步)
大致的框架
在開始碼代碼之前,我們要先為 StatefulSet 對象規划出大致的框架,如下圖所示:

具體實現代碼:
下面所用到的兩個鏡像:Mysql,xtrabackup,都是從私人倉庫(Harbor)中拉取的。
如果想跟本文一樣使用私人倉庫進行部署鏡像可學習此文章:Harbor私人倉庫的安裝與應用
如果想從公共倉庫拉取,可替換為:
image: mysql:5.7
image: gcr.io/google-samples/xtrabackup:1.0 《==這個鏡像是來自國外倉庫,如果訪問不到的話用上面1模塊進行拉取所需鏡像
apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql-ss namespace: kerry spec: selector: matchLabels: app: mysql serviceName: mysql-headless replicas: 3 template: metadata: namespace: kerry labels: app: mysql spec: initContainers: - name: init-mysql image: 192.168.29.197/kerry/mysql:5.7 command: - bash - "-c"
- |
set ex # 從hostname中獲取索引,比如(mysql-1)會獲取(1) [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} echo [mysqld] > /mnt/conf.d/server-id.cnf # 為了不讓server-id相同而增加偏移量 echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf # 拷貝對應的文件到/mnt/conf.d/文件夾中 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: 192.168.29.197/kerry/xtrabackup:latest command: - bash - "-c"
- |
set -ex # 整體意思: # 1.如果是主mysql中的xtrabackup,就不需要克隆自己了,直接退出 # 2.如果是從mysql中的xtrabackup,先判斷是否是第一次創建,因為第二次重啟本地就有數據庫,無需克隆。若是第一次創建(通過/var/lib/mysql/mysql文件是否存在判斷),就需要克隆數據庫到本地。 # 如果有數據不必克隆數據,直接退出() [[ -d /var/lib/mysql/mysql ]] && exit 0 # 如果是master數據也不必克隆 [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} [[ $ordinal -eq 0 ]] && exit 0 # 從序列號比自己小一的數據庫克隆數據,比如mysql-2會從mysql-1處克隆數據 ncat --recv-only mysql-ss-$(($ordinal-1)).mysql-headless 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: mysql image: 192.168.29.197/kerry/mysql:5.7 env: - name: MYSQL_ALLOW_EMPTY_PASSWORD value: "1" ports: - name: mysql containerPort: 3306 volumeMounts: - name: data mountPath: /var/lib/mysql subPath: mysql - name: conf mountPath: /etc/mysql/conf.d resources: requests: cpu: 50m memory: 50Mi 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
- name: xtrabackup image: 192.168.29.197/kerry/xtrabackup:latest ports: - name: xtrabackup containerPort: 3307 command: - bash - "-c"
- |
set -ex # 確定binlog 克隆數據位置(如果binlog存在的話). cd /var/lib/mysql # 如果存在該文件,則該xrabackup是從現有的從節點克隆出來的。 if [[ -s 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 -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 <<EOF $(<change_master_to.sql.orig), MASTER_HOST='mysql-ss-0.mysql-headless', MASTER_USER='root', MASTER_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" volumeMounts: - name: data mountPath: /var/lib/mysql subPath: mysql - name: conf mountPath: /etc/mysql/conf.d resources: requests: cpu: 10m memory: 10Mi volumes: - name: conf emptyDir: {} - name: config-map configMap: name: mysql imagePullSecrets: - name: docker-secret volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteOnce resources: requests: storage: 0.1Gi
總結:
0自此Mysql集群服務就已經部署完了,當前唯一的一個問題就是由於我們的PV是NFS服務提供的,PV都是已經寫死的,如果說我們要增加Mysql會出現沒有多的PV提供使用,但是減少Mysql功能還是有的
也.就是說,我們只有3個pv提供使用,Mysql節點頂天也就3個,如果還要多的話就得添加多PV提供Pod綁定了。
參考文檔:https://www.cnblogs.com/luoahong/p/12857783.html 《== 這個博客為詳解版,對於其中各個部分分析透徹
參考文檔:https://blog.csdn.net/qq_38900565/article/details/102486100 《== 這邊博客為實用版,直接照搬代碼就可以跑起來Demo,方便實踐理解
