您好,登錄后才能下訂單哦!
小編給大家分享一下怎么在Kubernetes上運(yùn)行高可用的WordPress和MySQL,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
WordPress是用于編輯和發(fā)布Web內(nèi)容的主流平臺(tái)。在本教程中,我將逐步介紹如何使用Kubernetes來(lái)構(gòu)建高可用性(HA)WordPress部署。
WordPress由兩個(gè)主要組件組成:WordPress PHP服務(wù)器和用于存儲(chǔ)用戶信息、帖子和網(wǎng)站數(shù)據(jù)的數(shù)據(jù)庫(kù)。我們需要讓整個(gè)應(yīng)用程序中這兩個(gè)組件在高可用的同時(shí)都具備容錯(cuò)能力。
在硬件和地址發(fā)生變化的時(shí)候,運(yùn)行高可用服務(wù)可能會(huì)很困難:非常難維護(hù)。借助Kubernetes以及其強(qiáng)大的網(wǎng)絡(luò)組件,我們可以部署高可用的WordPress站點(diǎn)和MySQL數(shù)據(jù)庫(kù),而無(wú)需(幾乎無(wú)需)輸入單個(gè)IP地址。
在本教程中,我將向你展示如何在Kubernetes中創(chuàng)建存儲(chǔ)類、服務(wù)、配置映射和集合,如何運(yùn)行高可用MySQL,以及如何將高可用WordPress集群掛載到數(shù)據(jù)庫(kù)服務(wù)上。如果你還沒有Kubernetes集群,你可以在Amazon、Google或者Azure上輕松找到并且啟動(dòng)它們,或者在任意的服務(wù)器上使用Rancher Kubernetes Engine (RKE)
現(xiàn)在我來(lái)簡(jiǎn)要介紹一下我們將要使用的技術(shù)及其功能:
WordPress應(yīng)用程序文件的存儲(chǔ):具有GCE持久性磁盤備份的NFS存儲(chǔ)
數(shù)據(jù)庫(kù)集群:帶有用于奇偶校驗(yàn)的xtrabackup的MySQL
應(yīng)用程序級(jí)別:掛載到NFS存儲(chǔ)的WordPress DockerHub映像
負(fù)載均衡和網(wǎng)絡(luò):基于Kubernetes的負(fù)載均衡器和服務(wù)網(wǎng)絡(luò)
該體系架構(gòu)如下所示:
在Kubernetes中,狀態(tài)集提供了一種定義pod初始化順序的方法。我們將使用一個(gè)有狀態(tài)的MySQL集合,因?yàn)樗艽_保我們的數(shù)據(jù)節(jié)點(diǎn)有足夠的時(shí)間在啟動(dòng)時(shí)復(fù)制先前pods中的記錄。我們配置這個(gè)狀態(tài)集的方式可以讓MySQL主機(jī)在其他附屬機(jī)器之前先啟動(dòng),因此當(dāng)我們擴(kuò)展時(shí),可以直接從主機(jī)將克隆發(fā)送到附屬機(jī)器上。
首先,我們需要?jiǎng)?chuàng)建一個(gè)持久卷存儲(chǔ)類和配置映射,以根據(jù)需要應(yīng)用主從配置。我們使用持久卷,避免數(shù)據(jù)庫(kù)中的數(shù)據(jù)受限于集群中任何特定的pods。這種方式可以避免數(shù)據(jù)庫(kù)在MySQL主機(jī)pod丟失的情況下丟失數(shù)據(jù),當(dāng)主機(jī)pod丟失時(shí),它可以重新連接到帶xtrabackup的附屬機(jī)器,并將數(shù)據(jù)從附屬機(jī)器拷貝到主機(jī)中。MySQL的復(fù)制負(fù)責(zé)主機(jī)-附屬的復(fù)制,而xtrabackup負(fù)責(zé)附屬-主機(jī)的復(fù)制。
要?jiǎng)討B(tài)分配持久卷,我們使用GCE持久磁盤創(chuàng)建存儲(chǔ)類。不過(guò),Kubernetes提供了各種持久性卷的存儲(chǔ)方案:
# storage-class.yamlkind: StorageClassapiVersion: storage.k8s.io/v1metadata: name: slowprovisioner: kubernetes.io/gce-pdparameters: type: pd-standard zone: us-central1-a
創(chuàng)建類,并且使用指令:$ kubectl create -f storage-class.yaml
部署它。
接下來(lái),我們將創(chuàng)建configmap,它指定了一些在MySQL配置文件中設(shè)置的變量。這些不同的配置由pod本身選擇有關(guān),但它們也為我們提供了一種便捷的方式來(lái)管理潛在的配置變量。
創(chuàng)建名為mysql-configmap.yaml
的YAML文件來(lái)處理配置,如下:
# mysql-configmap.yamlapiVersion: v1kind: ConfigMapmetadata: name: mysql labels: app: mysqldata: master.cnf: | # Apply this config only on the master. [mysqld] log-bin skip-host-cache skip-name-resolve slave.cnf: | # Apply this config only on slaves. [mysqld] skip-host-cache skip-name-resolve
創(chuàng)建configmap
并使用指令:$ kubectl create -f mysql-configmap.yaml
來(lái)部署它。
接下來(lái)我們要設(shè)置服務(wù)以便MySQL pods可以互相通信,并且我們的WordPress pod可以使用mysql-services.yaml
與MySQL通信。這也為MySQL服務(wù)啟動(dòng)了服務(wù)負(fù)載均衡器。
# mysql-services.yaml# Headless service for stable DNS entries of StatefulSet members.apiVersion: v1kind: Servicemetadata: name: mysql labels: app: mysqlspec: ports: - name: mysql port: 3306 clusterIP: None selector: app: mysql
通過(guò)此服務(wù)聲明,我們就為實(shí)現(xiàn)一個(gè)多寫入、多讀取的MySQL實(shí)例集群奠定了基礎(chǔ)。這種配置是必要的,每個(gè)WordPress實(shí)例都可能寫入數(shù)據(jù)庫(kù),所以每個(gè)節(jié)點(diǎn)都必須準(zhǔn)備好讀寫。
執(zhí)行命令 $ kubectl create -f mysql-services.yaml
來(lái)創(chuàng)建上述的服務(wù)。
到這為止,我們創(chuàng)建了卷聲明存儲(chǔ)類,它將持久磁盤交給所有請(qǐng)求它們的容器,我們配置了configmap
,在MySQL配置文件中設(shè)置了一些變量,并且我們配置了一個(gè)網(wǎng)絡(luò)層服務(wù),負(fù)責(zé)對(duì)MySQL服務(wù)器請(qǐng)求的負(fù)載均衡。上面說(shuō)的這些只是準(zhǔn)備有狀態(tài)集的框架, MySQL服務(wù)器實(shí)際在哪里運(yùn)行,我們接下來(lái)將繼續(xù)探討。
本節(jié)中,我們將編寫一個(gè)YAML配置文件應(yīng)用于使用了狀態(tài)集的MySQL實(shí)例。
我們先定義我們的狀態(tài)集:
1, 創(chuàng)建三個(gè)pods并將它們注冊(cè)到MySQL服務(wù)上。
2, 按照下列模版定義每個(gè)pod:
? 為主機(jī)MySQL服務(wù)器創(chuàng)建初始化容器,命名為init-mysql
.
? 給這個(gè)容器使用mysql:5.7鏡像
? 運(yùn)行一個(gè)bash腳本來(lái)啟動(dòng)xtrabackup
? 為配置文件和configmap
掛載兩個(gè)新卷
3, 為主機(jī)MySQL服務(wù)器創(chuàng)建初始化容器,命名為clone-mysql
.
? 為該容器使用Google Cloud Registry的xtrabackup:1.0
鏡像
? 運(yùn)行bash腳本來(lái)克隆上一個(gè)同級(jí)的現(xiàn)有xtrabackups
? 為數(shù)據(jù)和配置文件掛在兩個(gè)新卷
? 該容器有效地托管克隆的數(shù)據(jù),便于新的附屬容器可以獲取它
4, 為附屬M(fèi)ySQL服務(wù)器創(chuàng)建基本容器
? 創(chuàng)建一個(gè)MySQL附屬容器,配置它連接到MySQL主機(jī)
? 創(chuàng)建附屬xtrabackup
容器,配置它連接到xtrabackup主機(jī)
5, 創(chuàng)建一個(gè)卷聲明模板來(lái)描述每個(gè)卷,每個(gè)卷是一個(gè)10GB的持久磁盤
下面的配置文件定義了MySQL集群的主節(jié)點(diǎn)和附屬節(jié)點(diǎn)的行為,提供了運(yùn)行附屬客戶端的bash配置,并確保在克隆之前主節(jié)點(diǎn)能夠正常運(yùn)行。附屬節(jié)點(diǎn)和主節(jié)點(diǎn)分別獲得他們自己的10GB卷,這是他們?cè)谖覀冎岸x的持久卷存儲(chǔ)類中請(qǐng)求的。
apiVersion: apps/v1beta1kind: StatefulSetmetadata: name: mysqlspec: selector: matchLabels: app: mysql serviceName: mysql replicas: 3 template: metadata: labels: app: mysql spec: initContainers: - name: init-mysql image: mysql:5.7 command: - bash - "-c" - | set -ex # Generate mysql server-id from pod ordinal index. [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} echo [mysqld] > /mnt/conf.d/server-id.cnf # Add an offset to avoid reserved server-id=0 value. echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf # Copy appropriate conf.d files from config-map to emptyDir. 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 command: - bash - "-c" - | set -ex # Skip the clone if data already exists. [[ -d /var/lib/mysql/mysql ]] && exit 0 # Skip the clone on master (ordinal index 0). [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} [[ $ordinal -eq 0 ]] && exit 0 # Clone data from previous peer. ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql # Prepare the backup. 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" 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"] initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 readinessProbe: exec: # Check we can execute queries over TCP (skip-networking is off). command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"] initialDelaySeconds: 5 periodSeconds: 2 timeoutSeconds: 1 - name: xtrabackup image: gcr.io/google-samples/xtrabackup:1.0 ports: - name: xtrabackup containerPort: 3307 command: - bash - "-c" - | set -ex cd /var/lib/mysql # Determine binlog position of cloned data, if any. if [[ -f xtrabackup_slave_info ]]; then # XtraBackup already generated a partial "CHANGE MASTER TO" query # because we're cloning from an existing slave. mv xtrabackup_slave_info change_master_to.sql.in # Ignore xtrabackup_binlog_info in this case (it's useless). rm -f xtrabackup_binlog_info elif [[ -f xtrabackup_binlog_info ]]; then # We're cloning directly from master. Parse binlog position. [[ `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 # Check if we need to complete a clone by starting replication. 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" # In case of container restart, attempt this at-most-once. 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-0.mysql', MASTER_USER='root', MASTER_PASSWORD='', MASTER_CONNECT_RETRY=10; START SLAVE; EOF fi # Start a server to send backups when requested by peers. 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: 100m memory: 100Mi volumes: - name: conf emptyDir: {} - name: config-map configMap: name: mysql volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 10Gi
將該文件存為mysql-statefulset.yaml
,輸入kubectl="" create="" -f="" mysql-statefulset.yaml
并讓kubernetes部署你的數(shù)據(jù)庫(kù)。
現(xiàn)在當(dāng)你調(diào)用$="" kubectl="" get="" pods
,你應(yīng)該看到3個(gè)pods啟動(dòng)或者準(zhǔn)備好,其中每個(gè)pod上都有兩個(gè)容器。主節(jié)點(diǎn)pod表示為mysql-0,而附屬的pods為mysql-1
和mysql-2
.讓pods執(zhí)行幾分鐘來(lái)確保xtrabackup
服務(wù)在pod之間正確同步,然后進(jìn)行wordpress的部署。
您可以檢查單個(gè)容器的日志來(lái)確認(rèn)沒有錯(cuò)誤消息拋出。 查看日志的命令為$="" logs="" <container_name="">
主節(jié)點(diǎn)xtrabackup
容器應(yīng)顯示來(lái)自附屬的兩個(gè)連接,并且日志中不應(yīng)該出現(xiàn)任何錯(cuò)誤。
整個(gè)過(guò)程的最后一步是將我們的WordPress pods部署到集群上。為此我們希望為WordPress的服務(wù)和部署進(jìn)行定義。
為了讓W(xué)ordPress實(shí)現(xiàn)高可用,我們希望每個(gè)容器運(yùn)行時(shí)都是完全可替換的,這意味著我們可以終止一個(gè),啟動(dòng)另一個(gè)而不需要對(duì)數(shù)據(jù)或服務(wù)可用性進(jìn)行修改。我們也希望能夠容忍至少一個(gè)容器的失誤,有一個(gè)冗余的容器負(fù)責(zé)處理slack。
WordPress將重要的站點(diǎn)相關(guān)數(shù)據(jù)存儲(chǔ)在應(yīng)用程序目錄/var/www/html
中。對(duì)于要為同一站點(diǎn)提供服務(wù)的兩個(gè)WordPress實(shí)例,該文件夾必須包含相同的數(shù)據(jù)。
當(dāng)運(yùn)行高可用WordPress時(shí),我們需要在實(shí)例之間共享/var/www/html
文件夾,因此我們定義一個(gè)NGS服務(wù)作為這些卷的掛載點(diǎn)。
下面是設(shè)置NFS服務(wù)的配置,我提供了純英文的版本:
使用指令$ kubectl create -f nfs.yaml
部署NFS服務(wù)?,F(xiàn)在,我們需要運(yùn)行$ kubectl describe services nfs-server
獲得IP地址,這在后面會(huì)用到。
注意:將來(lái),我們可以使用服務(wù)名稱講這些綁定在一起,但現(xiàn)在你需要對(duì)IP地址進(jìn)行硬編碼。
# wordpress.yamlapiVersion: v1kind: Servicemetadata: name: wordpress labels: app: wordpressspec: ports: - port: 80 selector: app: wordpress tier: frontend type: LoadBalancer---apiVersion: v1kind: PersistentVolumemetadata: name: nfsspec: capacity: storage: 20G accessModes: - ReadWriteMany nfs: # FIXME: use the right IP server: <ip of="" the="" nfs="" service=""> path: "/"---apiVersion: v1kind: PersistentVolumeClaimmetadata: name: nfsspec: accessModes: - ReadWriteMany storageClassName: "" resources: requests: storage: 20G---apiVersion: apps/v1beta1 # for versions before 1.8.0 use apps/v1beta1kind: Deploymentmetadata: name: wordpress labels: app: wordpressspec: selector: matchLabels: app: wordpress tier: frontend strategy: type: Recreate template: metadata: labels: app: wordpress tier: frontend spec: containers: - image: wordpress:4.9-apache name: wordpress env: - name: WORDPRESS_DB_HOST value: mysql - name: WORDPRESS_DB_PASSWORD value: "" ports: - containerPort: 80 name: wordpress volumeMounts: - name: wordpress-persistent-storage mountPath: /var/www/html volumes: - name: wordpress-persistent-storage persistentVolumeClaim: claimName: nfs
我們現(xiàn)在創(chuàng)建了一個(gè)持久卷聲明,和我們之前創(chuàng)建的NFS服務(wù)建立映射,然后將卷附加到WordPress pod上,即/var/www/html
根目錄,這也是WordPress安裝的地方。這里保留了集群中WordPress pods的所有安裝和環(huán)境。有了這些配置,我們就可以對(duì)任何WordPress節(jié)點(diǎn)進(jìn)行啟動(dòng)和拆除,而數(shù)據(jù)能夠留下來(lái)。因?yàn)镹FS服務(wù)需要不斷使用物理卷,該卷將保留下來(lái),并且不會(huì)被回收或錯(cuò)誤分配。
使用指令$ kubectl create -f wordpress.yaml
部署WordPress實(shí)例。默認(rèn)部署只會(huì)運(yùn)行一個(gè)WordPress實(shí)例,可以使用指令$ kubectl scale --replicas=<number of="" replicas="">
deployment/wordpress
擴(kuò)展WordPress實(shí)例數(shù)量。
要獲得WordPress服務(wù)負(fù)載均衡器的地址,你需要輸入$ kubectl get services wordpress
并從結(jié)果中獲取EXTERNAL-IP字段來(lái)導(dǎo)航到WordPress。
OK,現(xiàn)在我們已經(jīng)部署好了服務(wù),那我們來(lái)拆除一下它們,看看我們的高可用架構(gòu)如何處理這些混亂。在這種部署方式中,唯一剩下的單點(diǎn)故障就是NFS服務(wù)(原因總結(jié)在文末結(jié)論中)。你應(yīng)該能夠測(cè)試其他任何的服務(wù)來(lái)了解應(yīng)用程序是如何響應(yīng)的?,F(xiàn)在我已經(jīng)啟動(dòng)了WordPress服務(wù)的三個(gè)副本,以及MySQL服務(wù)中的一個(gè)主兩個(gè)附屬節(jié)點(diǎn)。
首先,我們先kill掉其他而只留下一個(gè)WordPress節(jié)點(diǎn),來(lái)看看應(yīng)用如何響應(yīng):$ kubectl scale --replicas=1 deployment/wordpress
現(xiàn)在我們應(yīng)該看到WordPress部署的pod數(shù)量有所下降。$ kubectl get pods
應(yīng)該能看到WordPress pods的運(yùn)行變成了1/1。
點(diǎn)擊WordPress服務(wù)IP,我們將看到與之前一樣的站點(diǎn)和數(shù)據(jù)庫(kù)。如果要擴(kuò)展復(fù)原,可以使用$ kubectl scale --replicas=3 deployment/wordpress
再一次,我們可以看到數(shù)據(jù)包留在了三個(gè)實(shí)例中。
下面測(cè)試MySQL的狀態(tài)集,我們使用指令縮小備份的數(shù)量:$ kubectl scale statefulsets mysql --replicas=1
我們會(huì)看到兩個(gè)附屬?gòu)脑搶?shí)例中丟失,如果主節(jié)點(diǎn)在此時(shí)丟失,它所保存的數(shù)據(jù)將保存在GCE持久磁盤上。不過(guò)就必須手動(dòng)從磁盤恢復(fù)數(shù)據(jù)。
如果所有三個(gè)MySQL節(jié)點(diǎn)都關(guān)閉了,當(dāng)新節(jié)點(diǎn)出現(xiàn)時(shí)就無(wú)法復(fù)制。但是,如果一個(gè)主節(jié)點(diǎn)發(fā)生故障,一個(gè)新的主節(jié)點(diǎn)就會(huì)自動(dòng)啟動(dòng),并且通過(guò)xtrabackup重新配置來(lái)自附屬節(jié)點(diǎn)的數(shù)據(jù)。因此,在運(yùn)行生產(chǎn)數(shù)據(jù)庫(kù)時(shí),我不建議以小于3的復(fù)制系數(shù)來(lái)運(yùn)行。在結(jié)論段中,我們會(huì)談?wù)勧槍?duì)有狀態(tài)數(shù)據(jù)有什么更好的解決方案,因?yàn)镵ubernetes并非真正是為狀態(tài)設(shè)計(jì)的。
到現(xiàn)在為止,你已經(jīng)完成了在Kubernetes構(gòu)建并部署高可用WordPress和MySQL的安裝!
不過(guò)盡管取得了這樣的效果,你的研究之旅可能還遠(yuǎn)沒有結(jié)束??赡苣氵€沒注意到,我們的安裝仍然存在著單點(diǎn)故障:NFS服務(wù)器在WordPress pods之間共享/var/www/html
目錄。這項(xiàng)服務(wù)代表了單點(diǎn)故障,因?yàn)槿绻鼪]有運(yùn)行,在使用它的pods上html目錄就會(huì)丟失。教程中我們?yōu)榉?wù)器選擇了非常穩(wěn)定的鏡像,可以在生產(chǎn)環(huán)境中使用,但對(duì)于真正的生產(chǎn)部署,你可以考慮使用GlusterFS對(duì)WordPress實(shí)例共享的目錄開啟多讀多寫。
這個(gè)過(guò)程涉及在Kubernetes上運(yùn)行分布式存儲(chǔ)集群,實(shí)際上這不是Kubernetes構(gòu)建的,因此盡管它運(yùn)行良好,但不是長(zhǎng)期部署的理想選擇。
對(duì)于數(shù)據(jù)庫(kù),我個(gè)人建議使用托管的關(guān)系數(shù)據(jù)庫(kù)服務(wù)來(lái)托管MySQL實(shí)例,因?yàn)闊o(wú)論是Google的CloudSQL還是AWS的RDS,它們都以更合理的價(jià)格提供高可用和冗余處理,并且不需擔(dān)心數(shù)據(jù)的完整性。Kuberntes并不是圍繞有狀態(tài)的應(yīng)用程序設(shè)計(jì)的,任何建立在其中的狀態(tài)更多都是事后考慮。目前有大量的解決方案可以在選擇數(shù)據(jù)庫(kù)服務(wù)時(shí)提供所需的保證。
也就是說(shuō),上面介紹的是一種理想的流程,由Kubernetes教程、web中找到的例子創(chuàng)建一個(gè)有關(guān)聯(lián)的現(xiàn)實(shí)的Kubernetes例子,并且包含了Kubernetes 1.8.x中所有的新特性。
以上是“怎么在Kubernetes上運(yùn)行高可用的WordPress和MySQL”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。