大家好,我是老 Z!
上篇文章實現了 MySQL 數據庫在基於 KubeSphere 部署的 K8s 集羣上的安裝部署,部署方式採用了圖形化界面這種形式。本文將會介紹如何使用 GitOps 來部署 MySQL,部署過程涉及的所有 YAML 文件都會使用 Git 進行版本管理,並存放在 Git 倉庫中。因此,本文還會涉及 GitOps 的基礎操作。
原生 K8s 使用 GitOps 部署 MySQL
上篇文章我們完成了通過 KubeSphere 部署單實例 MySQL,那麼原生的 K8s 又該如何操作?GitOps 又是什麼、又該如何實現?
什麼是 GitOps(網文摘抄)
- GitOps 是一套使用 Git 來管理基礎架構和應用配置的實踐,而 Git 指的是一個開源版控制系統。
- GitOps 在運行過程中以 Git 爲聲明性基礎架構和應用的單一事實來源。
- GitOps 使用 Git 拉取請求來自動管理基礎架構的置備和部署。
- Git 存儲庫包含系統的全部狀態,因此係統狀態的修改痕跡既可查看也可審計。
- GitOps 經常被用作 K8s 和雲原生應用開發的運維模式,並且可以實現對 K8s 的持續部署。
- GitOps 是一種持續交付的方式。它的核心思想是將應用系統的聲明性基礎架構和應用程序存放在 Git 版本庫中。
準備資源配置清單-思路梳理
我們知道玩 K8s 的必備技能就是要手寫資源配置清單,一般使用 YAML 格式的文件來創建我們預期的資源配置。
此時我們也要手寫 MySQL 的資源配置清單?我很慌,參數我記不全啊。
NO!NO!NO!投機取巧的時刻到了,前面賣的關子在這揭開了。
前面我們已經通過 KubeSphere 的圖形界面創建了 MySQL 的資源配置,而且 KubeSphere 一個很棒的功能就是可以直接在線編輯資源的 YAML 文件。
我們可以在創建資源的時候,直接編輯 YAML 文件創建資源。也可以通過編輯 YAML 的方式修改已有的資源。
當然啊,你不用圖形界面,直接在 K8s 底層用命令行的方式去獲取 YAML 格式的輸出,再編輯,也是可以的。
梳理一下 MySQL 涉及的資源配置清單包含的資源。
- StatefulSet(有狀態副本集)
- Service(服務)
- 集羣內部(Headless)
- 集羣外部(自定義服務)
- ConfigMap
- Secret
接下來我們就分別獲取這些資源配置清單。
準備資源配置清單
ConfigMap
配置->配置字典,找到 mysql-cnf,點擊右側的三個豎點,點擊編輯 YAML。
打開編輯 YAML 頁面,可以直接複製所有內容,也可以點擊右上角的下載圖標,下載文件 (也可以利用上傳圖標上傳文件)。
獲取的現網配置不能完全的拿來就用,需要修改,把系統自動添加的一些元數據信息清理掉。
現網的 mysql-cfm.yaml。
kind: ConfigMap
apiVersion: v1
metadata:
name: mysql-cnf
namespace: lstack
annotations:
kubesphere.io/creator: lstack
data:
custom.cnf: |-
[mysqld]
#performance setttings
lock_wait_timeout = 3600
open_files_limit = 65535
back_log = 1024
max_connections = 512
max_connect_errors = 1000000
table_open_cache = 1024
table_definition_cache = 1024
thread_stack = 512K
sort_buffer_size = 4M
join_buffer_size = 4M
read_buffer_size = 8M
read_rnd_buffer_size = 4M
bulk_insert_buffer_size = 64M
thread_cache_size = 768
interactive_timeout = 600
wait_timeout = 600
tmp_table_size = 32M
max_heap_table_size = 32M
修改後的 mysql-cfm.yaml。
kind: ConfigMap
apiVersion: v1
metadata:
name: mysql-cnf
namespace: lstack
data:
custom.cnf: |-
[mysqld]
#performance setttings
lock_wait_timeout = 3600
open_files_limit = 65535
back_log = 1024
max_connections = 512
max_connect_errors = 1000000
table_open_cache = 1024
table_definition_cache = 1024
thread_stack = 512K
sort_buffer_size = 4M
join_buffer_size = 4M
read_buffer_size = 8M
read_rnd_buffer_size = 4M
bulk_insert_buffer_size = 64M
thread_cache_size = 768
interactive_timeout = 600
wait_timeout = 600
tmp_table_size = 32M
max_heap_table_size = 32M
Secret
配置->保密字典,找到 mysql-secret,點擊右側的三個豎點,點擊編輯 YAML。
現網的 mysql-secret.yaml。
kind: Secret
apiVersion: v1
metadata:
name: mysql-secret
namespace: lstack
annotations:
kubesphere.io/creator: lstack
data:
MYSQL_ROOT_PASSWORD: UEA4OHcwcmQ=
type: Opaque
修改後的 mysql-secret.yaml。
kind: Secret
apiVersion: v1
metadata:
name: mysql-secret
namespace: lstack
data:
MYSQL_ROOT_PASSWORD: UEA4OHcwcmQ=
type: Opaque
這裏要說一句,Secret 裏的值是用 base64 方式加密的,所以這裏的 MYSQL_ROOT_PASSWORD,要用實際的密碼用 base64 的方式加密。
-
base64 解密。
[root@ks-k8s-master-0 ~]# echo "UEA4OHcwcmQ=" | base64 -d P@88w0rd
-
base 加密。
[root@ks-k8s-master-0 ~]# echo -n "P@88w0rd" | base64 UEA4OHcwcmQ=
StatefulSet
應用負載->工作負載->有狀態副本集,找到 mysql,點擊右側的三個豎點,點擊編輯 YAML。
現網的 mysql-sts.yaml。
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: mysql
namespace: lstack
labels:
app: mysql
annotations:
kubesphere.io/creator: lstack
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
creationTimestamp: null
labels:
app: mysql
annotations:
logging.kubesphere.io/logsidecar-config: '{}'
spec:
volumes:
- name: host-time
hostPath:
path: /etc/localtime
type: ''
- name: volume-rca2zx
configMap:
name: mysql-cnf
items:
- key: custom.cnf
path: custom.cnf
defaultMode: 420
containers:
- name: lstack-mysql
image: 'mysql:5.7.38'
ports:
- name: tcp-mysql
containerPort: 3306
protocol: TCP
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_ROOT_PASSWORD
resources:
limits:
cpu: '2'
memory: 4000Mi
requests:
cpu: 500m
memory: 500Mi
volumeMounts:
- name: host-time
mountPath: /etc/localtime
- name: data
mountPath: /var/lib/mysql
- name: volume-rca2zx
readOnly: true
mountPath: /etc/mysql/conf.d/custom.cnf
subPath: custom.cnf
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
restartPolicy: Always
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirst
serviceAccountName: default
serviceAccount: default
securityContext: {}
schedulerName: default-scheduler
volumeClaimTemplates:
- kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: data
namespace: lstack
creationTimestamp: null
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: glusterfs
volumeMode: Filesystem
status:
phase: Pending
serviceName: mysql-1dpr
podManagementPolicy: OrderedReady
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0
revisionHistoryLimit: 10
修改後的 mysql-sts.yaml。
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: mysql
namespace: lstack
labels:
app: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
volumes:
- name: host-time
hostPath:
path: /etc/localtime
type: ''
- name: volume-cnf
configMap:
name: mysql-cnf
items:
- key: custom.cnf
path: custom.cnf
defaultMode: 420
containers:
- name: lstack-mysql
image: 'mysql:5.7.38'
ports:
- name: tcp-mysql
containerPort: 3306
protocol: TCP
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_ROOT_PASSWORD
resources:
limits:
cpu: '2'
memory: 4000Mi
requests:
cpu: 500m
memory: 500Mi
volumeMounts:
- name: host-time
mountPath: /etc/localtime
- name: data
mountPath: /var/lib/mysql
- name: volume-cnf
mountPath: /etc/mysql/conf.d/custom.cnf
subPath: custom.cnf
volumeClaimTemplates:
- metadata:
name: data
namespace: lstack
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: glusterfs
serviceName: mysql-headless
Service
先創建 Headless 服務,應用負載->服務->,找到 mysql-xxxx(mysql),點擊右側的三個豎點,點擊編輯 YAML。
現網的 mysql-headless.yaml。
kind: Service
apiVersion: v1
metadata:
name: mysql-1dpr
namespace: lstack
labels:
app: mysql
annotations:
kubesphere.io/alias-name: mysql
kubesphere.io/creator: lstack
kubesphere.io/serviceType: statefulservice
spec:
ports:
- name: tcp-mysql
protocol: TCP
port: 3306
targetPort: 3306
selector:
app: mysql
clusterIP: None
clusterIPs:
- None
type: ClusterIP
sessionAffinity: None
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
修改後的 mysql-headless.yaml。
kind: Service
apiVersion: v1
metadata:
name: mysql-headless
namespace: lstack
labels:
app: mysql
spec:
ports:
- name: tcp-mysql
protocol: TCP
port: 3306
targetPort: 3306
selector:
app: mysql
clusterIP: None
type: ClusterIP
再看看自定義的 mysql-external 服務 ,應用負載->服務->,找到 mysql-external,點擊右側的三個豎點,點擊編輯 YAML。
現網的 mysql-external.yaml。
kind: Service
apiVersion: v1
metadata:
name: mysql-external
namespace: lstack
labels:
app: mysql-external
annotations:
kubesphere.io/creator: lstack
spec:
ports:
- name: tcp-mysql-external
protocol: TCP
port: 3306
targetPort: 3306
nodePort: 32529
selector:
app: mysql
clusterIP: 10.233.36.71
clusterIPs:
- 10.233.36.71
type: NodePort
sessionAffinity: None
externalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
這裏有一點要說明 nodePort 這個參數,如果 K8s 集羣可控,建議規劃一套服務端口使用規範,每個需要 nodePort 的服務都指定固定的端口,這樣有利於運維的標準化。
修改後的 mysql-external.yaml(注意 nodePort 參數沒有指定)。
kind: Service
apiVersion: v1
metadata:
name: mysql-external
namespace: lstack
labels:
app: mysql-external
spec:
ports:
- name: tcp-mysql-external
protocol: TCP
port: 3306
targetPort: 3306
selector:
app: mysql
type: NodePort
將 MySQL 資源配置清單提交到 Git 倉庫。
通過上面的操作,我們獲取了 MySQL 的資源配置清單。
本人強迫症,喜歡分類存放,所以我用了 4 個文件,mysql-headless.yaml 跟 mysql-sts.yaml 合併在一個文件當然你也可以放到一個配置文件裏。
- mysql-external.yaml
- mysql-sts.yaml
- mysql-secret.yaml
- mysql-cfm.yaml
將資源配置清單提交到 Git 倉庫
選擇 GitHub 作爲主倉庫,Gitee 作爲同步倉庫 (人工)。
本系列文檔所有 k8s 的資源配置清單文件使用了一個公共倉庫,生產環境建議每種服務創建一個配置倉庫,有利於更精細化的版本控制。
本文爲了演示主備倉庫的使用,所有選擇了 Github 和 Gitee 兩種 Git 服務,實際使用中爲了更好的使用體驗建議選擇 Gitee。
在 GitHub 新建一個倉庫,倉庫名稱k8s-yaml,添加一個 README 文件初始化倉庫,點擊Create repository,確認創建。
將代碼倉庫 Clone 回本地。
$ git clone [email protected]:devops/k8s-yaml.git
$ ls k8s-yaml
README.md
新創建一個文件夾,用自己喜歡的文本編輯器 (推薦 vscode) 編輯 MySQL 的資源配置清單,並將文件放入新創建的文件夾。
爲了以後的擴展性,這裏創建了一個 single 命名的二級目錄,存放單實例的資源配置清單文件。
$ mkdir -p k8s-yaml/mysql/single
$ ls -l k8s-yaml/mysql/single
total 32
-rw-r--r-- 1 z staff 646 5 11 19:23 mysql-cfm.yaml
-rw-r--r-- 1 z staff 266 5 11 19:31 mysql-external.yaml
-rw-r--r-- 1 z staff 134 5 11 19:23 mysql-secret.yaml
-rw-r--r-- 1 z staff 1911 5 11 19:31 mysql-sts.yaml
將編輯好的資源配置文件清單,提交到 GitHub。
$ cd k8s-yaml
$ git add .
$ git commit -am '添加MySQL single資源配置清單'
$ git push
在 GitHub 上查看,確認代碼是否提交。
接下來將資源配置清單同步到 Gitee 備份倉庫。
- 本文采用了手工推送同步的方式 (個人習慣)
- Gitee 也支持自動同步 GitHub 的倉庫 (更便捷)
在 Gitee 新建一個倉庫,倉庫名稱k8s-yaml,類型默認私有,點擊創建。
創建完成後可去倉庫設置中修改爲開源。
創建完成後,因爲我們創建的時候,沒選擇初始化倉庫的配置,所以,默認會顯示一個幫助頁面,告訴你該如何提交代碼到倉庫。
因爲,我們已經有了代碼倉庫,所以我們選擇已有倉庫的配置方法,將已有代碼提交到 Gitee。
根據幫助提示操作,要注意 origin 我們要換成 gitee。
$ git remote add gitee https://gitee.com/zdevops/k8s-yaml.git
$ git push -u gitee
在 Gitee 上查看,確認代碼是否提交。
修改 Gitee 倉庫爲開源 (可選)。
Gitee 倉庫->管理->倉庫設置->基本信息,最後面是否開源,選擇開源,倉庫公開須知,三個都勾選,點擊保存。
修改後,你的代碼倉庫就是開源,所有人可見的了。
GitOps 初體驗-在 K8s 集羣上部署 MySQL
MySQL 資源配置清單已經存放到了 Git 在線倉庫,接下來開啓我們的 GitOps 體驗之旅。
登錄 k8s 的 master 節點,執行後面的操作任務。
生產環境建議打造獨立的運維管理節點進行整個集羣的管理 , 可以參考《基於 KubeSphere 玩轉 k8s-運維管理節點打造手記》
安裝 Git。
$ yum install git -y
創建 devops 目錄,我選擇 /opt 目錄作爲 devops 的根目錄。
$ mkdir /opt/devops
$ cd /opt/devops/
從 Gitee 下載 k8s-yaml 倉庫的代碼。
$ git clone https://gitee.com/zdevops/k8s-yaml.git
$ ls k8s-yaml/
mysql README.md
由於是同一個測試環境,先清理掉現有的 MySQL 服務。
$ kubectl get secrets -n lstack
NAME TYPE DATA AGE
default-token-x2gzv kubernetes.io/service-account-token 3 31d
mysql-secret Opaque 1 2d20h
$ kubectl get configmaps -n lstack
NAME DATA AGE
kube-root-ca.crt 1 31d
mysql-cnf 1 47h
$ kubectl get service -n lstack
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
glusterfs-dynamic-afe88cf4-86b1-4215-833a-534c5f779a22 ClusterIP 10.233.13.188 <none> 1/TCP 2d
mysql-1dpr ClusterIP None <none> 3306/TCP 2d
mysql-external NodePort 10.233.36.71 <none> 3306:32529/TCP 47h
$ kubectl get statefulsets -n lstack
NAME READY AGE
mysql 1/1 2d
# 清理
$ kubectl delete statefulsets mysql -n lstack
statefulset.apps "mysql" deleted
$ kubectl delete service mysql-external -n lstack
service "mysql-external" deleted
$ kubectl delete service mysql-1dpr -n lstack
service "mysql-1dpr" deleted
$ kubectl delete secrets mysql-secret -n lstack
secret "mysql-secret" deleted
$ kubectl delete configmaps mysql-cnf -n lstack
configmap "mysql-cnf" deleted
利用資源配置清單一鍵部署 MySQL。
$ cd /opt/devops/k8s-yaml/
$ ls
mysql README.md
$ kubectl apply -f mysql/single/
驗證結果,發現 StatefulSet 沒有創建,分析問題。
$ kubectl get statefulsets -n lstack
No resources found in lstack namespace.
# 一開始我以爲我遺漏了配置文件,ls看一眼,發現文件都在
$ ls
mysql README.md
$ cd mysql/
$ ls
single
$ cd single/
$ ls
mysql-cfm.yaml mysql-external.yaml mysql-secret.yaml mysql-sts.yaml
# 確認一下文件內容,發現文件也有內容
$ vi mysql-sts.yaml
# 再次執行,發現了端倪,爲啥只有service/mysql-headless 的資源配置,沒有statefulset
$ kubectl apply -f mysql-sts.yaml
service/mysql-headless unchanged
# 再次確認,發現編輯文件的時候遺漏了一點,當一個配置文件有多種資源定義時,不同資源的配置直接需要用"---"分隔。修改配置文件再次執行,發現執行成功。
$ vi mysql-sts.yaml
$ cd ..
$ kubectl apply -f single/
$ kubectl get statefulsets -n lstack -o wide
NAME READY AGE CONTAINERS IMAGES
mysql 1/1 31s lstack-mysql mysql:5.7.38
$ kubectl get pods -n lstack -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql-0 1/1 Running 0 35s 10.233.116.59 ks-k8s-master-2 <none> <none>
回到我們的 KubeSphere 的管理控制檯,發現 mysql 的工作負載也能在界面中顯示,這也驗證了在原生 k8s 上的操作也會直接反應到 KubeSphere 的管理控制檯。
二次體驗 GitOps
正好藉着上面出現的問題,二次體驗一下 GitOps。我們直接在部署服務器上修改了 mysql-sts.yaml,且修改後的結果驗證成功。
爲了演示 GitOps 的更多場景,直接在部署服務器上修改,然後提交到在線代碼倉庫。
實際工作中我都是在自己的辦公電腦上修改,提交到在線代碼倉庫,然後部署服務器拉取更新代碼。
修改後的 mysql-sts.yaml,由於篇幅問題這裏只演示關鍵部分,StatefulSet 的完整配置見 Gitee 倉庫或是前文。
---
kind: StatefulSet
apiVersion: apps/v1
metadata:
name: mysql
namespace: lstack
labels:
app: mysql
...
---
kind: Service
apiVersion: v1
metadata:
name: mysql-headless
namespace: lstack
labels:
app: mysql
spec:
ports:
- name: tcp-mysql
protocol: TCP
port: 3306
targetPort: 3306
selector:
app: mysql
clusterIP: None
type: ClusterIP
提交修改後的代碼到代碼倉庫。
# 修改後查看git倉庫的變化
$ git diff
diff --git a/mysql/single/mysql-sts.yaml b/mysql/single/mysql-sts.yaml
index f775920..1eded9c 100644
--- a/mysql/single/mysql-sts.yaml
+++ b/mysql/single/mysql-sts.yaml
@@ -1,3 +1,4 @@
+---
kind: StatefulSet
apiVersion: apps/v1
metadata:
@@ -68,6 +69,7 @@ spec:
storageClassName: glusterfs
serviceName: mysql-headless
+---
kind: Service
apiVersion: v1
metadata:
# 本地提交代碼變更
$ git commit -am '修復mysql statefulset配置不生效問題'
# push到在線代碼倉庫,有一個warning可以忽略,也可以按提示執行
$ git push
查看 Gitee 在線代碼倉庫是否有變更。
在個人的辦公電腦上,同步更新後的代碼。
# 更新代碼
$ git pull
# 同步更新後的代碼到Github
$ git push -u origin
查看 GitHub 在線代碼倉庫是否有變更。
再次體驗 GitOps
模擬一個業務場景,再次體驗一下 GitOps。
-
MySQL 上線運行後,由於業務量上漲,初始配置參數中的 max_connections 太小了,需要增大。
-
配置參數調整完成後,更新線上配置,並重啓服務 (生產環境數據庫不要輕易重啓,這種需求可以用臨時修改解決)。
-
這裏只是模擬一個簡單的例子,帶大家體驗 GitOps,實際使用中所有的配置文件都建議使用 Git 進行版本控制。
編輯本地 Git 倉庫 MySQL 資源配置清單中的 mysql-cfm.yaml 文件,修改 max_connections,從 512 變成 1024。
提交修改到 Git 在線倉庫。
# 提交本地修改
$ git commit -am '修改mysql-cnf中max_connections的值'
# 提交到Github
$ git push
# 同步到Gitee
$ git push -u gitee
登錄運維管理節點,更新 Git 代碼,並重新運行。
$ git pull
$ kubectl apply -f mysql/single/
# 查看ConfigMap的變化
$ kubectl get configmaps mysql-cnf -n lstack -o yaml
apiVersion: v1
data:
custom.cnf: |-
[mysqld]
#performance setttings
lock_wait_timeout = 3600
open_files_limit = 65535
back_log = 1024
max_connections = 1024
max_connect_errors = 1000000
table_open_cache = 1024
table_definition_cache = 1024
thread_stack = 512K
sort_buffer_size = 4M
join_buffer_size = 4M
read_buffer_size = 8M
read_rnd_buffer_size = 4M
bulk_insert_buffer_size = 64M
thread_cache_size = 768
interactive_timeout = 600
wait_timeout = 600
tmp_table_size = 32M
max_heap_table_size = 32M
kind: ConfigMap
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","data":{"custom.cnf":"[mysqld]\n#performance setttings\nlock_wait_timeout = 3600\nopen_files_limit = 65535\nback_log = 1024\nmax_connections = 1024\nmax_connect_errors = 1000000\ntable_open_cache = 1024\ntable_definition_cache = 1024\nthread_stack = 512K\nsort_buffer_size = 4M\njoin_buffer_size = 4M\nread_buffer_size = 8M\nread_rnd_buffer_size = 4M\nbulk_insert_buffer_size = 64M\nthread_cache_size = 768\ninteractive_timeout = 600\nwait_timeout = 600\ntmp_table_size = 32M\nmax_heap_table_size = 32M"},"kind":"ConfigMap","metadata":{"annotations":{},"name":"mysql-cnf","namespace":"lstack"}}
creationTimestamp: "2022-05-12T07:20:07Z"
name: mysql-cnf
namespace: lstack
resourceVersion: "8928391"
uid: 1b7322cf-f11e-445d-a2ba-b42a90ade469
# 重啓mysql pod使配置生效
$ kubectl delete -f mysql/single/mysql-sts.yaml
$ kubectl apply -f mysql/single/mysql-sts.yaml
# 查看mysql容器內部配置是否更新
$ kubectl exec mysql-0 -n lstack -- cat /etc/mysql/conf.d/custom.cnf
[mysqld]
#performance setttings
lock_wait_timeout = 3600
open_files_limit = 65535
back_log = 1024
max_connections = 1024
max_connect_errors = 1000000
table_open_cache = 1024
table_definition_cache = 1024
thread_stack = 512K
sort_buffer_size = 4M
join_buffer_size = 4M
read_buffer_size = 8M
read_rnd_buffer_size = 4M
bulk_insert_buffer_size = 64M
thread_cache_size = 768
interactive_timeout = 600
wait_timeout = 600
tmp_table_size = 32M
切記! 上面的例子只是讓大家體驗 GitOps,生產環境不要輕易重啓數據庫服務器,除非你知道自己在幹什麼。
現在經過驗證,我們的 MySQL 的配置可用且比較穩定,我們把這個好的狀態記錄下來,避免以後修改變更弄壞了,再找不回原來正確的配置。
在我們的個人電腦上給當前的 Git 代碼打個 Tag,記錄當前的狀態 (也可以通過在線倉庫的管理界面操作)。
# 打tag -a tag名字 -m tag描述
$ git tag -a v0.1 -m 'mysql version v0.1'
# 查看現有tag
$ git tag -l
v0.1
# 查看tag詳細信息
$ git show v0.1
tag v0.1
Tagger: devops <[email protected]>
Date: Thu May 12 18:15:34 2022 +0800
mysql version v0.1
commit 180f97ac96da504a0b46eb4871ef423f64fde093 (HEAD -> main, tag: v0.1, origin/main, origin/HEAD, gitee/main)
Author: devops <[email protected]>
Date: Thu May 12 17:48:18 2022 +0800
修改mysql-cnf中max_connections的值
diff --git a/mysql/single/mysql-cfm.yaml b/mysql/single/mysql-cfm.yaml
index e24d96d..50d1778 100644
--- a/mysql/single/mysql-cfm.yaml
+++ b/mysql/single/mysql-cfm.yaml
@@ -10,7 +10,7 @@ data:
lock_wait_timeout = 3600
open_files_limit = 65535
back_log = 1024
- max_connections = 512
+ max_connections = 1024
max_connect_errors = 1000000
table_open_cache = 1024
table_definition_cache = 1024
# 將tag推送到遠程服務器
$ git push -u origin --tags
$ git push -u gitee --tags
# 線上服務器驗證(圖略)
運維管理服務器更新代碼,並切換到指定 tag(注意!使用 Git 一定要養成每次操作前 git pull 這種習慣)。
## 更新代碼
$ git pull
## 切換到v0.1
$ git checkout -b v0.1
通過上面的幾波操作,我們可以看到,我們所有的配置變更都採用了 Git 管理,完整的記錄了配置的全生命週期管理,通過給倉庫打分支或是 tag,可以方便我們切換到任意已記錄狀態。
高可用部署 MySQL(預留佔坑)
暫時沒有高可用部署的需求,因此不涉及高可用模式的 MySQL 的部署,但是有一些思考留着佔坑。
目前的做法
- 不給自己找麻煩,有高可用需求直接買雲服務商的 RDS。
- 實在需要自己搭建,在 K8s 集羣之外部署主從。
以後可能的方向
- K8s 上的 MySQL 主從部署
- Operator
- Helm
遺留問題
此部分內容也是運維 MySQL 必備的技能,有些內容我也沒有經驗無法分享,有些內容會在 << 基於 KubeSphere 的 K8s 生產實踐之路 >> 系列文檔中介紹。
- MySQL 數據庫備份
- MySQL 高可用部署
- MySQL 安全加固
- MySQL 調優
MySQL 性能 (基準) 測試
運維一定要做到對自己的運維環境心中有數,MySQL 上線前一定要進行性能 (基準測試),有助於瞭解我們的數據庫服務器能達到的理想狀態。本次介紹的只是皮毛,只是告訴大家一些基本入門的知識,更細節、更深入的內容請參考其他更專業的文檔。
性能 (基準) 測試工具安裝
工具選型 (sysbench)
- 雲廠商展示自家數據庫產品性能都用這個工具
- 據說很多 DBA 也喜歡用
sysbench 工具安裝
- 安裝工具
# 導入軟件源
$ curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash
# 安裝sysbench
$ yum install sysbench -y
- 驗證-執行命令查看版本
$ sysbench --version
sysbench 1.0.20
性能 (基準) 測試
測試方案
-
測試參數
-
指標 值 線程數 8/16/32 單表數據量 100000 表數量 16 性能指標
指標 說明 TPS Transactions Per Second ,即數據庫每秒執行的事務數,以 commit 成功次數爲準。 QPS Queries Per Second ,即數據庫每秒執行的 SQL 數(含 insert、select、update、delete 等)。 RT Response Time ,響應時間。包括平均響應時間、最小響應時間、最大響應時間、每個響應時間的查詢佔比。比較需要重點關注的是,前 95-99% 的最大響應時間。因爲它決定了大多數情況下的短板。 Concurrency Threads 併發量,每秒可處理的查詢請求的數量。
準備測試數據
使用我們在 k8s 上創建的數據庫,涉及數據庫操作命令,需要終端登錄到容器內運行。
提前創建測試用數據庫 sbtest,並賦予 root 從任意 IP 遠程管理所有數據庫的權限。
生產環境千萬不要這麼搞,一定要遵循最小化原則!
# bash
root@mysql-0:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.38 MySQL Community Server (GPL)
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> create database sbtest;
Query OK, 1 row affected (0.02 sec)
mysql> grant all privileges on *.* to 'root'@'%' identified by 'P@88w0rd' with grant option;
Query OK, 0 rows affected, 1 warning (0.02 sec)
- 測試數據庫是否能連接
# 安裝mysql客戶端,下面的示例是在k8s節點上安裝的,由於系統是最小化安裝,所有會安裝很多依賴。實際測試可以起一個mysql的pod或是用其他的mysql客戶端工具。
$ yum install mysql -y
# 測試MySQL服務連通性 -h 是k8s節點的IP -P 是mysql外部服務的端口號
$ mysql -h 192.168.9.91 -P 32529 -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 5
Server version: 5.7.38 MySQL Community Server (GPL)
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]>
- 準備測試數據
$ sysbench --db-driver=mysql --mysql-host=192.168.9.91 --mysql-port=32529 --mysql-user=root --mysql-password=P@88w0rd --mysql-db=sbtest --table-size=100000 --tables=16 --threads=8 --events=999999999 --report-interval=10 --time=100 /usr/share/sysbench/oltp_common.lua prepare
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Initializing worker threads...
Creating table 'sbtest6'...
Creating table 'sbtest2'...
Creating table 'sbtest8'...
Creating table 'sbtest3'...
Creating table 'sbtest7'...
Creating table 'sbtest5'...
Creating table 'sbtest1'...
Creating table 'sbtest4'...
Inserting 100000 records into 'sbtest3'
Inserting 100000 records into 'sbtest6'
Inserting 100000 records into 'sbtest1'
Inserting 100000 records into 'sbtest4'
Inserting 100000 records into 'sbtest7'
Inserting 100000 records into 'sbtest5'
Inserting 100000 records into 'sbtest2'
Inserting 100000 records into 'sbtest8'
Creating a secondary index on 'sbtest3'...
Creating table 'sbtest11'...
Inserting 100000 records into 'sbtest11'
Creating a secondary index on 'sbtest5'...
Creating a secondary index on 'sbtest1'...
Creating a secondary index on 'sbtest6'...
Creating a secondary index on 'sbtest4'...
Creating a secondary index on 'sbtest7'...
Creating a secondary index on 'sbtest2'...
Creating a secondary index on 'sbtest8'...
Creating table 'sbtest13'...
Inserting 100000 records into 'sbtest13'
Creating table 'sbtest9'...
Inserting 100000 records into 'sbtest9'
Creating table 'sbtest14'...
Creating table 'sbtest12'...
Inserting 100000 records into 'sbtest14'
Inserting 100000 records into 'sbtest12'
Creating table 'sbtest15'...
Inserting 100000 records into 'sbtest15'
Creating table 'sbtest16'...
Creating table 'sbtest10'...
Inserting 100000 records into 'sbtest16'
Inserting 100000 records into 'sbtest10'
Creating a secondary index on 'sbtest11'...
Creating a secondary index on 'sbtest13'...
Creating a secondary index on 'sbtest9'...
Creating a secondary index on 'sbtest12'...
Creating a secondary index on 'sbtest14'...
Creating a secondary index on 'sbtest15'...
Creating a secondary index on 'sbtest10'...
Creating a secondary index on 'sbtest16'...
- 執行測試-8 線程測試
$ sysbench --db-driver=mysql --mysql-host=192.168.9.91 --mysql-port=32529 --mysql-user=root --mysql-password=P@88w0rd --mysql-db=sbtest --table-size=100000 --tables=16 --threads=8 --events=999999999 --report-interval=10 --time=100 /usr/share/sysbench/oltp_read_write.lua run
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Running the test with following options:
Number of threads: 8
Report intermediate results every 10 second(s)
Initializing random number generator from current time
Initializing worker threads...
Threads started!
[ 10s ] thds: 8 tps: 88.46 qps: 1782.38 (r/w/o: 1249.19/355.46/177.73) lat (ms,95%): 267.41 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 8 tps: 84.31 qps: 1678.47 (r/w/o: 1173.42/336.43/168.62) lat (ms,95%): 277.21 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 8 tps: 70.20 qps: 1413.82 (r/w/o: 990.21/283.20/140.40) lat (ms,95%): 369.77 err/s: 0.00 reconn/s: 0.00
[ 40s ] thds: 8 tps: 47.30 qps: 946.00 (r/w/o: 662.20/189.20/94.60) lat (ms,95%): 484.44 err/s: 0.00 reconn/s: 0.00
[ 50s ] thds: 8 tps: 43.80 qps: 875.99 (r/w/o: 613.19/175.20/87.60) lat (ms,95%): 484.44 err/s: 0.00 reconn/s: 0.00
[ 60s ] thds: 8 tps: 60.70 qps: 1213.08 (r/w/o: 849.69/242.00/121.40) lat (ms,95%): 411.96 err/s: 0.00 reconn/s: 0.00
[ 70s ] thds: 8 tps: 53.90 qps: 1078.22 (r/w/o: 754.42/216.00/107.80) lat (ms,95%): 376.49 err/s: 0.00 reconn/s: 0.00
[ 80s ] thds: 8 tps: 56.49 qps: 1127.98 (r/w/o: 790.11/224.88/112.99) lat (ms,95%): 397.39 err/s: 0.00 reconn/s: 0.00
[ 90s ] thds: 8 tps: 50.60 qps: 1014.59 (r/w/o: 709.56/203.82/101.21) lat (ms,95%): 434.83 err/s: 0.00 reconn/s: 0.00
[ 100s ] thds: 8 tps: 54.70 qps: 1093.12 (r/w/o: 765.22/218.50/109.40) lat (ms,95%): 390.30 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 85582
write: 24452
other: 12226
total: 122260
transactions: 6113 (61.10 per sec.)
queries: 122260 (1221.96 per sec.)
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 100.0494s
total number of events: 6113
Latency (ms):
min: 35.63
avg: 130.89
max: 951.86
95th percentile: 390.30
sum: 800129.59
Threads fairness:
events (avg/stddev): 764.1250/4.14
execution time (avg/stddev): 100.0162/0.01
- 執行測試-16 線程測試
$ sysbench --db-driver=mysql --mysql-host=192.168.9.91 --mysql-port=32529 --mysql-user=root --mysql-password=P@88w0rd --mysql-db=sbtest --table-size=100000 --tables=16 --threads=16 --events=999999999 --report-interval=10 --time=100 /usr/share/sysbench/oltp_read_write.lua run
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Running the test with following options:
Number of threads: 16
Report intermediate results every 10 second(s)
Initializing random number generator from current time
Initializing worker threads...
Threads started!
[ 10s ] thds: 16 tps: 114.41 qps: 2310.22 (r/w/o: 1621.18/458.63/230.41) lat (ms,95%): 369.77 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 16 tps: 106.35 qps: 2111.86 (r/w/o: 1474.74/424.41/212.71) lat (ms,95%): 383.33 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 16 tps: 80.40 qps: 1612.01 (r/w/o: 1129.21/322.00/160.80) lat (ms,95%): 623.33 err/s: 0.00 reconn/s: 0.00
[ 40s ] thds: 16 tps: 63.40 qps: 1266.80 (r/w/o: 886.80/253.20/126.80) lat (ms,95%): 539.71 err/s: 0.00 reconn/s: 0.00
[ 50s ] thds: 16 tps: 57.20 qps: 1145.91 (r/w/o: 802.74/228.78/114.39) lat (ms,95%): 549.52 err/s: 0.00 reconn/s: 0.00
[ 60s ] thds: 16 tps: 69.91 qps: 1408.31 (r/w/o: 987.57/280.92/139.81) lat (ms,95%): 511.33 err/s: 0.00 reconn/s: 0.00
[ 70s ] thds: 16 tps: 78.00 qps: 1547.22 (r/w/o: 1080.51/310.70/156.00) lat (ms,95%): 484.44 err/s: 0.00 reconn/s: 0.00
[ 80s ] thds: 16 tps: 79.50 qps: 1599.87 (r/w/o: 1122.58/318.29/159.00) lat (ms,95%): 520.62 err/s: 0.00 reconn/s: 0.00
[ 90s ] thds: 16 tps: 67.80 qps: 1354.83 (r/w/o: 947.62/271.61/135.60) lat (ms,95%): 539.71 err/s: 0.00 reconn/s: 0.00
[ 100s ] thds: 16 tps: 73.90 qps: 1474.10 (r/w/o: 1030.80/295.50/147.80) lat (ms,95%): 502.20 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 110950
write: 31700
other: 15850
total: 158500
transactions: 7925 (79.00 per sec.)
queries: 158500 (1580.05 per sec.)
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 100.3103s
total number of events: 7925
Latency (ms):
min: 41.24
avg: 202.44
max: 1198.81
95th percentile: 511.33
sum: 1604328.52
Threads fairness:
events (avg/stddev): 495.3125/4.03
execution time (avg/stddev): 100.2705/0.03
- 執行測試-32 線程測試
$ sysbench --db-driver=mysql --mysql-host=192.168.9.91 --mysql-port=32529 --mysql-user=root --mysql-password=P@88w0rd --mysql-db=sbtest --table-size=100000 --tables=16 --threads=32 --events=999999999 --report-interval=10 --time=100 /usr/share/sysbench/oltp_read_write.lua run
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Running the test with following options:
Number of threads: 32
Report intermediate results every 10 second(s)
Initializing random number generator from current time
Initializing worker threads...
Threads started!
[ 10s ] thds: 32 tps: 140.10 qps: 2825.04 (r/w/o: 1981.25/560.39/283.39) lat (ms,95%): 450.77 err/s: 0.00 reconn/s: 0.00
[ 20s ] thds: 32 tps: 124.41 qps: 2515.49 (r/w/o: 1763.43/503.24/248.82) lat (ms,95%): 549.52 err/s: 0.00 reconn/s: 0.00
[ 30s ] thds: 32 tps: 95.90 qps: 1887.10 (r/w/o: 1316.70/378.60/191.80) lat (ms,95%): 733.00 err/s: 0.00 reconn/s: 0.00
[ 40s ] thds: 32 tps: 81.80 qps: 1656.59 (r/w/o: 1164.89/328.10/163.60) lat (ms,95%): 707.07 err/s: 0.00 reconn/s: 0.00
[ 50s ] thds: 32 tps: 82.60 qps: 1638.41 (r/w/o: 1143.51/329.70/165.20) lat (ms,95%): 657.93 err/s: 0.00 reconn/s: 0.00
[ 60s ] thds: 32 tps: 94.34 qps: 1905.84 (r/w/o: 1336.62/380.65/188.58) lat (ms,95%): 623.33 err/s: 0.00 reconn/s: 0.00
[ 70s ] thds: 32 tps: 87.86 qps: 1739.86 (r/w/o: 1215.31/348.73/175.82) lat (ms,95%): 634.66 err/s: 0.00 reconn/s: 0.00
[ 80s ] thds: 32 tps: 84.40 qps: 1705.48 (r/w/o: 1196.49/340.20/168.80) lat (ms,95%): 759.88 err/s: 0.00 reconn/s: 0.00
[ 90s ] thds: 32 tps: 80.50 qps: 1580.71 (r/w/o: 1101.70/318.00/161.00) lat (ms,95%): 612.21 err/s: 0.00 reconn/s: 0.00
[ 100s ] thds: 32 tps: 81.40 qps: 1661.90 (r/w/o: 1167.00/332.10/162.80) lat (ms,95%): 707.07 err/s: 0.00 reconn/s: 0.00
SQL statistics:
queries performed:
read: 133924
write: 38264
other: 19132
total: 191320
transactions: 9566 (95.33 per sec.)
queries: 191320 (1906.56 per sec.)
ignored errors: 0 (0.00 per sec.)
reconnects: 0 (0.00 per sec.)
General statistics:
total time: 100.3457s
total number of events: 9566
Latency (ms):
min: 51.94
avg: 335.14
max: 1405.78
95th percentile: 657.93
sum: 3205913.85
Threads fairness:
events (avg/stddev): 298.9375/5.15
execution time (avg/stddev): 100.1848/0.14
MySQL 容器性能監控圖。
清理測試數據 (爲了保證數據更精準,建議每次測試前都清理數據,準備數據,測試)。
$ sysbench --db-driver=mysql --mysql-host=192.168.9.91 --mysql-port=32529 --mysql-user=root --mysql-password=P@88w0rd --mysql-db=sbtest --table-size=100000 --tables=16 --threads=32 --events=999999999 --report-interval=10 --time=100 /usr/share/sysbench/oltp_read_write.lua cleanup
sysbench 1.0.20 (using bundled LuaJIT 2.1.0-beta2)
Dropping table 'sbtest1'...
Dropping table 'sbtest2'...
Dropping table 'sbtest3'...
Dropping table 'sbtest4'...
Dropping table 'sbtest5'...
Dropping table 'sbtest6'...
Dropping table 'sbtest7'...
Dropping table 'sbtest8'...
Dropping table 'sbtest9'...
Dropping table 'sbtest10'...
Dropping table 'sbtest11'...
Dropping table 'sbtest12'...
Dropping table 'sbtest13'...
Dropping table 'sbtest14'...
Dropping table 'sbtest15'...
Dropping table 'sbtest16'...
測試結果
結果彙總對比。
壓測線程數量 | TPS | QPS | 延遲 |
---|---|---|---|
8 | 61 | 1221 | 130 |
16 | 79 | 1580 | 202 |
32 | 95 | 1906 | 335 |
建議根據測試結果,調優!
總結
本文詳細介紹了 Git 常用操作、如何將代碼在多個在線代碼倉庫中存儲並保持同步,還介紹了 GitOps 的基本概念並演示瞭如何用 GitOps 理念在原生 K8s 上部署 MySQL 服務。最後,演示了 MySQL 常用性能測試工具 sysbench 的安裝和基礎使用。
我多年的一些運維經驗和運維思路貫穿了全文。
本文由博客一文多發平臺 OpenWrite 發佈!