Kubernetes 是當前主流的容器編排服務,它主要解決「叢集環境」下「容器化應用」的「管理問題」,主要包括如下幾方面:
Kubernetes 的強大依賴於它良好的設計理念和抽象,吸引了越來越多的開發者投入到 Kubernetes 社群,把 Kubernetes 作為基礎設施執行服務的公司也逐步增多。
在設計理念方面,Kubernetes 只有 APIServer 與 etcd(儲存)通訊,其他元件在記憶體中維護狀態,透過 APIServer 持久化資料。管理元件動作的觸發是 level-based 而非 edge-based,並根據資源「當前狀態」和「期望狀態」進行相應動作。Kubernetes 採用分層設計,基於各類抽象介面、由不同的外掛滿足不同的需求。
在抽象方面,不同的 workload 服務於不同的應用,如針對無狀態應用的 Deployment、針對有狀態應用的 StatefulSet 等。在訪問管理方面,Service 解耦了叢集內部服務訪問方和提供者,Ingress 提供了叢集外部到叢集內部的訪問管理。
Kubernetes 雖然有良好的設計理念和抽象,但陡峭的學習曲線和不完善的開發資料極大增加了應用開發的難度。
本次分享將基於筆者的開發實踐,以 MySQL on Kubernetes 為例,描述如何基於 Kubernetes 開發高可靠應用,盡可能抽象出最佳實踐,降低基於 Kubernetes 開發高可靠應用的成本。
應用的設計和開發不能脫離業務需求,對 MySQL 應用的需求如下:
為了實現上述需求,需要依靠 Kubernetes 和應用兩方面協同工作,即開發基於 Kubernetes 高可靠應用,既需要 Kubernetes 相關的知識,也需要應用領域內的知識。
我們使用 Percona XtraDB Cluster 作為 MySQL 叢集方案,它是 multi-master 的 MySQL 架構,實體間基於 Galera Replication 技術實現資料的實時同步。這種叢集方案可以避免 master-slave 架構的叢集在主從切換時可能出現的資料丟失現象,進一步提升資料的可靠性。
備份方面,我們使用 xtrabackup 作為備份/恢復方案,實現資料的熱備份,在備份期間不影響使用者對叢集的正常訪問。
提供「定時備份」的同時,我們也提供「手動備份」,以滿足業務對備份資料的需求。
「資料鏈路」是使用者訪問 MySQL 服務的鏈路,我們使用 3 主節點的 MySQL 叢集方案,透過 TLB(七牛自研的四層負載均衡服務)對使用者提供訪問入口。TLB 既實現了訪問層面對 MySQL 實體的負載均衡,又實現了對服務的健康檢測,自動摘除異常的節點,同時在節點恢復時自動加入該節點。如下圖:
基於上述 MySQL 叢集方案和 TLB,一個或兩個節點的異常不會影響使用者對 MySQL 叢集的正常訪問,確保 MySQL 服務的高可用。
「控制鏈路」是 MySQL 叢集的管理鏈路,分為兩個層面:
全域性控制管理主要負責「建立/刪除叢集」「管理所有 MySQL 叢集狀態」等,基於 Operator 的理念來實現。每個 MySQL 叢集有一個控制器,負責該叢集的「任務排程」「健康檢測」「故障自動處理」等。
這種拆解將每個叢集的管理工作下放到每個叢集中,降低了叢集間控制鏈路的相互幹擾,同時又減輕了全域性控制器的壓力。
Operator 是 CoreOS 公司提出的一個概念,用來建立、配置、管理複雜應用,由兩部分構成:
-
自定義資源
-
為使用者提供一種簡單的方式描述對服務的期望
-
註冊 CR(CustomResource)資源
-
監聽 CR objects 的變更
-
使用者對該 CR 資源進行 CREATE/UPDATE/DELETE 操作
-
觸發相應的 handler 進行處理
我們根據實踐,對開發 Operator 做瞭如下抽象:
對 CR ADD/UPDATE/DELETE events 的操作,抽象為如下介面:
在上述抽象的基礎上,七牛提供了一個簡單的 Operator 框架,透明化了建立 CR、監聽 CR events 等的操作,將開發 Operator 的工作變的更為簡單。
我們開發了 MySQL Operator 和 MySQL Data Operator,分別用來負責「建立/刪除叢集」和「手動備份/恢復」工作。
由於每個 MySQL 叢集會有多種型別的任務邏輯,如「資料備份」「資料恢復」「健康檢測」「故障自動處理」等,這些邏輯的併發執行可能會引發異常,故需要任務排程器來協調任務的執行,Controller 起到的就是這方面的作用:
透過 Controller 和各類 Worker,每個 MySQL 叢集實現了自運維。
「被動檢測」是每個 MySQL 實體向 Controller 彙報健康狀態,「主動檢測」是由 Controller 請求每個 MySQL 實體的健康狀態。這兩種機制相互補充,提升健康檢測的可靠度和及時性。
對於健康檢測的資料,Controller 和 Operator 均會使用,如下圖所示:
Controller 使用健康檢測資料是為了及時發現 MySQL 叢集的異常,並做相應的故障處理,故需要準確、及時的健康狀態資訊。它在記憶體中維護所有 MySQL 實體的狀態,根據「主動檢測」和「被動檢測」的結果更新實體狀態並做相應的處理。
Operator 使用健康檢測資料是為了向外界反映 MySQL 叢集的執行情況,併在 Controller 異常時介入到 MySQL 叢集的故障處理中。
在實踐中,由於健康檢測的頻率相對較高,會產生大量的健康狀態,若每個健康狀態都被持久化,那麼 Operator 和 APIServer 均會承受巨大的訪問壓力。由於這些健康狀態僅最新的資料有意義,故在 Controller 層面將待向 Operator 彙報的健康狀態插入到一個有限容量的 Queue 中,當 Queue 滿時,舊的健康狀態將被丟棄。
當 Controller 檢測到 MySQL 叢集異常時,將會進行故障自動處理。
-
不丟資料
-
盡可能不影響可用性
-
對於已知的、能夠處理的故障進行自動處理
-
對於未知的、不能夠處理的故障不自動處理,人工介入
-
故障型別有哪些
-
如何及時檢測和感知故障
-
當前是否出現了故障
-
出現的故障是哪種故障型別
-
如何進行處理
針對上述關鍵問題,我們定義了 3 種級別的叢集狀態:
同時針對每個 mysqld 節點,定義瞭如下狀態:
Controller 收集到所有 MySQL 節點狀態後,會根據這些節點的狀態推算 MySQL 叢集的狀態。當檢測到 MySQL 叢集狀態不是 Green 時,會觸發「故障處理」邏輯,該邏輯會根據已知的故障處理方案進行處理。若該故障型別未知,人工介入處理。整個流程如下圖:
由於每種應用的故障場景和處理方案不同,這裡不再敘述具體的處理方法。
我們基於 Operator 的理念實現了高可靠的 MySQL 服務,為使用者定義了兩類資源,即 QiniuMySQL 和 QiniuMySQLData。前者描述使用者對 MySQL 叢集的配置,後者描述手動備份/恢復資料的任務,這裡以 QiniuMySQL 為例。
使用者可透過如下簡單的 yaml 檔案觸發建立 MySQL 叢集的操作:
在叢集建立好後,使用者可透過該 CR object 的 status 欄位獲取叢集狀態:
Helm 是為 Kubernetes 提供的包管理工具,透過將應用打包為 Chart,標準化了 Kubernetes 應用的交付、部署和使用流程。
Chart 本質上是 Kubernetes yaml 檔案和引數檔案的集合,這樣可以透過一個 Chart 檔案進行應用的交付。Helm 透過操作 Chart,可一鍵部署、升級應用。
由於篇幅原因及 Helm 操作的通用性,這裡不再描述具體的使用過程。
除了上述實現的「健康檢測」「故障自動處理」以及透過 Helm 管理應用的交付、部署,在運維過程中還有如下問題需要考慮:
我們透過 Prometheus Grafana 做監控/告警服務,服務將 metric 資料以 HTTP API 暴露給 Prometheus,由 Prometheus server 定時拉取。開發人員在 Grafana 上將 Prometheus 中的監控資料視覺化,根據對監控圖表和應用的把握,在監控圖中設定告警線,由 Grafana 實現告警。
這種先視覺化監控後告警的方式,極大程度上增強了我們對應用執行特徵的把握,明確需要關註的指標和告警線,降低無效告警的產生量。
在開發中,我們透過 gRPC 實現服務間的通訊。在 gRPC 生態系統中,有個名為 go-grpc-prometheus 的開源專案,透過在服務中插入幾行簡單的程式碼,就可以實現對 gRPC server 所有 rpc 請求的監控打點。
對於容器化服務,日誌管理包括「日誌收集」和「日誌滾動」兩方面維度。
我們將服務日誌打到 syslog 中,再透過某種手段將 syslog 日誌轉入到容器的 stdout/stderr 中,方便外部採用常規的方式進行日誌收集。同時,在 syslog 中配置了 logrotate 功能,自動進行日誌的滾動操作,避免日誌佔滿容器磁碟空間引發服務異常。
為了提升開發效率,我們使用 https://github.com/phusion/baseimage-docker 作為基礎映象,其中內建了 syslog 和 lograte 服務,應用只關心把日誌打入 syslog 即可,不用關心日誌的收集和日誌滾動問題。
在開發基於 Kubernetes 的高可靠 MySQL 應用過程中,隨著對 Kubernetes 和 MySQL 理解的深入,我們不斷進行抽象,逐步將如下通用的邏輯和最佳實踐以模組的方式實現:
-
Operator 開發框架
-
健康檢測服務
-
故障自動處理服務
-
任務排程服務
-
配置管理服務
-
監控服務
-
日誌服務
-
etc.
隨著這些通用邏輯和最佳實踐的模組化,在開發新的基於 Kubernetes 的高可靠應用時,開發者可像「搭積木」一樣將與 Kubernetes 相關的互動快速搭建起來,這樣的應用由於已經運用了最佳實踐,從一開始就具備高可靠的特性。同時,開發者可將註意力從 Kubernetes 陡峭的學習曲線轉移到應用自身領域,從應用自身加強服務的可靠性。
本次培訓內容包括:Docker基礎、容器技術、Docker映象、資料共享與持久化、Docker三駕馬車、Docker實踐、Kubernetes基礎、Pod基礎與進階、常用物件操作、服務發現、Helm、Kubernetes核心元件原理分析、Kubernetes服務質量保證、排程詳解與應用場景、網路、基於Kubernetes的CI/CD、基於Kubernetes的配置管理等,點選瞭解具體培訓內容。
長按二維碼向我轉賬
受蘋果公司新規定影響,微信 iOS 版的贊賞功能被關閉,可透過二維碼轉賬支援公眾號。