共計 7445 個字符,預計需要花費 19 分鐘才能閱讀完成。
這篇文章給大家介紹如何在生產環(huán)境構建 K8S,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
在分布式系統(tǒng)上管理服務是運維團隊面臨的最困難的問題之一。在生產中突破新軟件并學習如何可靠地運營是非常重要的。本文是一則實例,講述為什么學習運營 Kubernetes 很重要,以及為什么很難。下面是關于 Kubernetes bug 導致的一小時中斷故障的事后剖析。
為什么選擇在 Kubernetes 之上構建?如何將 Kubernetes 集成到現(xiàn)有基礎設施中?丸趣 TV 小編給出的方法是建立 (和改進) 對 Kubernetes 集群的可靠性的信任,以及構建在 Kubernetes 之上的抽象。
我們最近在 Kubernetes 之上構建了一個分布式的 cron 作業(yè)調度系統(tǒng),這是一個令人興奮的容器編排的新平臺。Kubernetes 現(xiàn)在非常流行,并且有許多令人興奮的承諾:最令人興奮的是,程序員不需要知道或關心他們的應用程序運行的是什么機器。
什么是 Kubernetes?
Kubernetes 是一個分布式系統(tǒng),用于調度程序在集群中運行。你可以告訴 Kubernetes 運行一個程序的 5 個副本,它將在工作節(jié)點上動態(tài)調度它們。容器自動調度以增加利用率,節(jié)省資金,強大的 deployment primitives 允許逐步推出新的代碼,安全上下文和網絡策略允許企業(yè)以安全的方式運行多租戶的工作負載。
Kubernetes 有很多不同類型的調度能力。它可以調度長時間運行的 HTTP 服務、在集群中每臺機器上運行的 daemonsets、每小時運行的 cron 作業(yè)等等。
為什么是 Kubernetes?
每個基礎設施項目都是從業(yè)務需求開始的,我們的目標是提高現(xiàn)有分布式 cron 作業(yè)系統(tǒng)的可靠性和安全性。我們的要求是:
建立和運營一支小團隊(只有 2 人在項目中全職工作)。
在 20 臺機器上可靠地安排大約 500 個不同的 cron 作業(yè)。
我們決定在 Kubernetes 之上建立的幾個原因:
希望構建一個現(xiàn)有的開源項目。
kubernetes 包含一個分布式 cron 作業(yè)調度器,不必自己編寫。
kubernetes 是一個非常活躍的項目,經常接受捐贈。
kubernetes 是用 Go 寫的,很容易學。幾乎所有 Kubernetes 的 bug 都是由團隊中沒有經驗的程序員做的。
如果我們能夠成功地運營 Kubernetes,可以在未來的 Kubernetes 上構建,例如,目前正在開發(fā)基于 kubernet 的系統(tǒng)來訓練機器學習模型。
我們以前使用 Chronos 作為 cron 作業(yè)調度系統(tǒng), 但它不再是滿足可靠性要求, 而且大部分都沒有維護(在過去 9 個月中 1 次提交, 最后一次合并請求的時間是 2016 年 3 月))Chronos 未維護的, 我們認為不值得繼續(xù)投資改善現(xiàn)有的集群。
如果你正考慮 Kubernetes,請記住: 不要僅僅因為其他公司在使用 Kubernetes 而使用它。建立一個可靠的集群需要花費大量的時間,使用它的業(yè)務案例并不是很突出。把你的時間用在聰明的方法上。
可靠性是什么意思?
說到運營服務,“可靠”這個詞本身并沒有什么意義。要討論可靠性,首先需要建立一個 SLO(服務級別目標)。
我們有三個主要目標:
99.99% 的 cron 作業(yè)應該在預定運行時間的 20 分鐘內開始運行。20 分鐘是一個很寬的窗口,但是我們采訪了內部客戶,沒有人要求更高的精確度。
Jobs 應該運行 99.99% 的時間(不被終止)。
向 Kubernetes 的遷移不會導致任何面向客戶的事件。
這意味著:
Kubernetes API 的短暫停機時間是可以接受的(如果停機 10 分鐘,只要在 5 分鐘內恢復即可)。
調度錯誤 (cron 作業(yè)運行完全丟失并且根本無法運行) 是不可接受的。我們非常重視安排錯誤報告。
要謹慎對待 pod evictions 和安全終止實例,以免作業(yè)過于頻繁地終止。
需要一個好的遷移計劃。
建立一個 Kubernetes 集群
我們建立第一個 Kubernetes 集群的基本方法是從零開始構建集群,而不是使用 kubeadm 或 kops 之類的工具。使用 Puppet(常用的配置管理工具)調配了配置。從頭開始構建很好,原因有兩個:能夠深入地集成 Kubernetes 在架構中,并且深入理解其內部。
我們希望將 Kubernetes 整合到現(xiàn)有的基礎架構中。與現(xiàn)有系統(tǒng)無縫集成,以便進行日志記錄,證書管理,加密,網絡安全,監(jiān)控,AWS 實例管理,部署,數(shù)據庫代理,內部 DNS 服務器,配置管理以及更多。整合所有這些系統(tǒng)有時需要一點創(chuàng)造力,但總體上比試圖讓 kubeadm / kops 成為我們想要的更容易。
在信任并了解如何操作這些現(xiàn)有系統(tǒng)后,我們希望繼續(xù)在新的 Kubernetes 群集中使用。例如,安全證書管理是一個非常棘手的問題,已經有辦法頒發(fā)和管理證書。通過適當?shù)恼希覀儽苊饬藶?Kubernetes 創(chuàng)建新的 CA。
準確了解設置的參數(shù)是如何影響 Kubernetes 設置的。例如,在配置用于身份驗證的證書 /CAs 時,使用了超過 12 個參數(shù)。了解這些參數(shù)有助于在遇到身份驗證問題時更容易調試設置。
對 Kubernetes 建立信心
在 Kubernetes 之初,團隊中沒有人使用過 Kubernetes。如何從“沒有人用過 Kubernetes”到“我們有信心在生產中運行 Kubernetes”?
戰(zhàn)略 0:與其他公司交談
我們向其他公司詢問了 Kubernetes 的經歷。他們都以不同的方式或在不同的環(huán)境中使用 Kubernetes(運行 HTTP 服務,裸機,Google Kubernetes 引擎等)。
在談到 Kubernetes 這樣龐大而復雜的系統(tǒng)時,重要的是認真思考自己的用例,做自己的實驗,建立對自己環(huán)境的信心,并做出決定。例如,你不該讀這篇博客文章并得出結論:“Stripe 正在成功使用 Kubernetes,所以它也適用于我們!”
以下是我們在與幾家運營 Kubernetes 集群的公司溝通后后學到的:
優(yōu)先考慮企業(yè) etcd 集群的可靠性(etcd 是存儲所有 Kubernetes 集群狀態(tài)的地方)。
某些 Kubernetes 功能比其他功能更穩(wěn)定,因此請小心 Alpha 功能。一些公司只有在穩(wěn)定后才能使用穩(wěn)定特性(例如,如果某個功能在 1.8 版本中保持穩(wěn)定,則在使用它之前會等待 1.9 或 1.10)。
考慮使用托管的 Kubernetes 系統(tǒng),如 GKE / AKS / EKS。從頭開始建立高可用性 Kubernetes 系統(tǒng)是一項巨大的工作。AWS 在此項目中沒有托管的 Kubernetes 服務,所以這不適合我們。
注意由覆蓋網絡 / 軟件定義網絡引入的額外網絡延遲。
策略 1: 閱讀代碼。
我們計劃很大程度上依賴于 Kubernetes 的一個組件,即 cronjob 控制器。這個組件當時處于 alpha 階段,這讓我們有點擔心。我們在一個測試集群中嘗試了它,但是如何判斷它在生產中是否適合我們呢?
值得慶幸的是,所有 cronjob 控制器的核心功能只有 400 行 Go。通過源代碼快速讀取顯示:
cron 作業(yè)控制器是一個無狀態(tài)的服務(與其他 Kubernetes 組件一樣,除了 etcd)。
每 10 秒鐘,這個控制器調用 syncAll 函數(shù):go wait.Until(jm.syncAll,10 * time.Second,stopCh)
syncAll 函數(shù)從 Kubernetes API 中獲取所有 cron 作業(yè),遍歷該列表,確定下一步應該運行哪些作業(yè),然后啟動這些作業(yè)。
核心邏輯似乎相對容易理解。更重要的是,如果在這個控制器中有一個 bug,它可能是我們可以修復的東西。
策略 2: 做負載測試
在開始認真構建集群之前,我們做了一些負載測試。我們并不擔心 Kubernetes 集群能夠處理多少節(jié)點(計劃部署大約 20 個節(jié)點),但是確實想讓某些 Kubernetes 能夠處理我們希望運行的那么多的 cron 作業(yè)(大約每分鐘 50 個)。
在一個 3 節(jié)點集群中運行了測試,創(chuàng)建了 1000 個 cron 作業(yè),每個任務每分鐘運行一次。這些工作中的每一個都簡單地運行 bash -c echo hello world。我們選擇簡單的作業(yè),是因為希望測試集群的調度和編排能力,而不是集群的總計算能力。
測試集群無法處理每分鐘 1000 個 cron 作業(yè)。每個節(jié)點每秒最多只能啟動一個 pod,而集群能夠每分鐘運行 200 個 cron 作業(yè)。由于我們只希望每分鐘運行大約 50 個 cron 作業(yè),所以我們認為這些限制不是阻礙因素。
策略 3: 優(yōu)先構建和測試高可用性 etcd 集群。
在設置 Kubernetes 時,最重要的事情之一就是運行 etcd。Etcd 是 Kubernetes 集群的核心,它是存儲集群中所有數(shù)據的地方。除了 etcd 之外,其他一切都是無狀態(tài)的。如果 etcd 沒有運行,不能對 Kubernetes 集群進行任何更改(盡管現(xiàn)有的服務將繼續(xù)運行!)
這張圖顯示了 etcd 是 Kubernetes 集群的核心——API 服務器是 etcd 前面的無狀態(tài) REST/ 認證端點,然后其他組件通過 API 服務器與 etcd 對話。 在運行時,有兩個要點需要牢記:
設置復制, 這樣集群不會死如果你失去了一個節(jié)點。我們現(xiàn)在有三個 etcd 副本。
確保足夠的 I / O 帶寬。我們的 etcd 版本有一個問題,一個具有高 fsync 延遲的節(jié)點可能觸發(fā)連續(xù)的 leader elections,導致集群無法使用。通過確保所有節(jié)點的 I / O 帶寬都比 etcd 的寫入數(shù)量多,從而彌補了這一點。
設置復制不是一個設置 - 忘記操作。我們仔細地測試后發(fā)現(xiàn)可能會丟失一個 etcd 節(jié)點,并且集群優(yōu)雅地恢復了。
以下是為建立 etcd 集群所做的一些工作:
設置復制
監(jiān)控 etcd 服務是可用的
寫一些簡單的工具, 以便輕松創(chuàng)建新的 etcd 節(jié)點,并加入到集群當中
編寫一些簡單的工具,以便我們可以輕松創(chuàng)建新的 etcd 節(jié)點并將它們加入到群集中
補丁 etcd 的高集成, 這樣我們可以在生產環(huán)境中運行超過 1 個 etcd 集群
測試從一個 etcd 備份中恢復
測試可以在不停機情況下重建整個集群
很高興很早就做了這個測試。某個周五的早晨,在我們的生產集群中,一個 etcd 節(jié)點停止了對 ping 的響應。我們得到了警報,終止了節(jié)點,帶來了一個新的節(jié)點,加入到集群中,同時 Kubernetes 繼續(xù)運行。
策略 4:逐步將工作遷移到 Kubernetes
我們的目標之一是將工作遷移到 Kubernetes 而不造成任何中斷。成功進行生產遷移的秘訣不是避免犯錯(這是不可能的),而是設計你的遷移以減少錯誤的影響。
我們很幸運有多種職位可以遷移到新集群,所以可以遷移一些低影響的工作崗位,接受一兩次失敗。
在開始遷移之前,構建了易于使用的工具,如果有必要,可以在不到五分鐘的時間內在舊系統(tǒng)和新系統(tǒng)之間來回移動作業(yè)。這種簡單的工具減少了錯誤的影響 – 如果遷移一個沒有計劃的依賴的工作,沒有什么大不了的!可以將其移回原處,解決問題,然后再試。
以下是我們采用的整體遷移策略:
根據他們的重要程度大致排序
將一些重復的工作遷移到 Kubernetes。如果發(fā)現(xiàn)新的情況,快速回滾,修復問題,然后重試。
策略 5: 調查 Kubernetes bug 并修復它們
我們在項目開始時制定了一個規(guī)則: 如果 Kubernetes 做了一些意外的事情,必須調查,找出原因,并提出補救措施。
調查每個問題都很耗時,但很重要。如果只是簡單地將 Kubernetes 的”古怪行為”看作是復雜的分布式系統(tǒng)的功能,我們擔心,因為它們會被調用導致產生 bug 集群。
在使用了這種方法之后,我們發(fā)現(xiàn)并且修復了 Kubernetes 的幾個 bug。
以下是測試中發(fā)現(xiàn)的一些問題:
名稱超過 52 個字符的 Cronjob 無法安排作業(yè)。
Pods 有時會永遠停留在掛起狀態(tài)。
調度程序會每 3 個小時崩潰一次。
Flannel 的 hostgw 后端沒有替換過時的路由表項
修復這些 bug 讓我們對 Kubernetes 項目的使用感覺好得多——不僅它運行得比較好,而且也接受補丁并有一個良好的 PR 審查過程。
Kubernetes 有 bug,像所有的軟件一樣。特別是,我們非常頻繁地使用調度器(cron 作業(yè)總是在創(chuàng)建新的 pods),而調度器使用緩存有時會導致 bug、回退和崩潰。緩存是困難的! 但是代碼庫是可接近的,我們已經能夠處理遇到的 bug。
值得一提的是,Kubernetes 的 pod 驅逐邏輯。Kubernetes 有一個稱為節(jié)點控制器的組件,它負責將 pod 驅逐出去,如果節(jié)點沒有響應,則將它們移到另一個節(jié)點。allnodes 會暫時無響應(例如,由于網絡或配置問題),在這種情況下,Kubernetes 可以終止集群中的所有 pod。
如果運行的是大型 Kubernetes 集群,請仔細閱讀節(jié)點控制器文檔,仔細地考慮設置,并進行廣泛測試。每次通過創(chuàng)建網絡分區(qū)測試對這些設置的配置更改(例如,pod- 驅逐超時),就會發(fā)生令人驚訝的事情。最好在測試中發(fā)現(xiàn)這些意外,而不是在生產中發(fā)現(xiàn)。
策略 6:有意引起 Kubernetes 集群問題
之前討論過在 Stripe 中進行游戲日練習。這個想法是要想出你最終會在生產中發(fā)生的情況,然后在生產中故意造成這些情況,從而確保能夠處理它們。
在集群上進行了幾次練習之后,經常發(fā)現(xiàn)諸如監(jiān)視或配置錯誤等問題。很高興在早期發(fā)現(xiàn)這些問題,而不是六個月后突然發(fā)現(xiàn)。
以下是運行的一些比賽日練習:
終止 Kubernetes API 服務器
終止所有 Kubernetes API 服務器并將其恢復(這非常有效)
終止 etcd 節(jié)點
從 API 服務器中關閉 Kubernetes 集群中的工作節(jié)點(以便它們無法通信)。這導致節(jié)點上的所有 pods 被遷移到其他節(jié)點。
很高興看到 Kubernetes 如何應對我們投入的大量干擾。Kubernetes 的設計是為了適應錯誤 – 它有存儲所有狀態(tài)的 etcd 集群,一個只是該數(shù)據庫的 REST 接口的 API 服務器,以及一個協(xié)調所有集群管理的無狀態(tài)控制器集合。
如果任何 Kubernetes 核心組件(API 服務器,控制器管理器或調度程序)被中斷或重新啟動,一旦它們出現(xiàn),它們將從 etcd 讀取相關狀態(tài)并繼續(xù)無縫運行。這是我們希望的事情之一,而且在實踐中實際運作良好。
以下是測試中發(fā)現(xiàn)的一些問題:
“沒有得到 paged,來修復監(jiān)控。“
“當銷毀 API 服務器實例并將其恢復后,需要人工干預。最好解決這個問題。“
“有時執(zhí)行 etcd 故障轉移時,API 服務器會啟動超時請求,直至重新啟動。”
在運行這些測試后,針對發(fā)現(xiàn)的問題開發(fā)了補救措施:改進了監(jiān)控,發(fā)現(xiàn)了固定配置問題,并提交了 Kubernetes bug。
使 cron 作業(yè)易于使用
簡單地探討一下我們是如何使基于 kubernetes 的系統(tǒng)易于使用的。
最初的目標是設計一個運行 cron 作業(yè)的系統(tǒng),團隊有信心運營和維護。一旦建立了對 Kubernetes 的信心,就需要工程師們輕松地配置和增加新的 cron 作業(yè)。我們開發(fā)了一個簡單的 YAML 配置格式,這樣用戶就不需要了解 Kubernetes 的內部結構來使用這個系統(tǒng)。這是我們開發(fā)的格式:
name: job-name-here
kubernetes:
schedule: 15 */2 * * *
command:
– ruby
– /path/to/script.rb
resources:
requests:
cpu: 0.1
memory: 128M
limits:
memory: 1024M
沒有做什么特別的事情——我們編寫了一個簡單的程序,將這種格式轉換為 Kubernetes cron 作業(yè)配置,將其應用于 kubectl。
我們還編寫了一個測試套件,以確保作業(yè)名稱不會太長,并且所有名稱都是惟一的。我們目前不使用 cgroups 來強化對大多數(shù)作業(yè)的內存限制,但計劃將來推出。
我們的簡單格式易于使用,而且由于自動生成了來自相同格式的 Chronos 和 Kubernetes cron 作業(yè)定義,所以在兩個系統(tǒng)之間遷移作業(yè)非常簡單。這是使我們的增量遷移工作良好的關鍵部分。將作業(yè)遷移到 Kubernetes 時,可以用一個簡單的三行配置更改,在不到十分鐘的時間內將其移回。
監(jiān)控 Kubernetes
監(jiān)測 Kubernetes 集群的內部狀態(tài)非常令人愉悅。我們使用 kube-state-metrics 軟件包進行監(jiān)測,并使用一個名為 veneurl – Prometheus 的小型 Go 程序來獲取 Prometheus 的度量標準,將它們作為 statsd 指標發(fā)布到我們的監(jiān)控系統(tǒng)中。
例如,以下是過去一小時內集群中未決 Pod 的數(shù)量圖表。Pending 意味著等待分配一個工作節(jié)點來運行。可以看到上午 11 點的數(shù)字峰值,很多 cron 作業(yè)在每小時的第 0 分鐘運行。
還有一個監(jiān)視器,用于檢查有沒有任何 Pod 在 Pending 狀態(tài)中卡住 – 每個 Pod 在 5 分鐘內開始在 worker 節(jié)點上運行,否則會收到警報。
Kubernetes 未來計劃
設置 Kubernetes,到順暢地運行生產代碼并將所有 cron 作業(yè)遷移到新集群,花了五個月的時間,三位工程師全職工作。我們投資學習 Kubernetes 的一個重要原因是希望能夠在 Stripe 中更廣泛地使用 Kubernetes。
以下是適用于運行 Kubernetes(或任何其他復雜分布式系統(tǒng))的原則:
為企業(yè)的 Kubernetes 項目,以及所有基礎設施項目,定義清晰的商業(yè)原因。了解業(yè)務案例和用戶的需求使項目變得更加容易。
積極削減范圍。避免使用許多 Kubernetes 的基本特性來簡化集群。這讓我們可以更快速地發(fā)送消息,例如,由于 pod-to-pod 聯(lián)網不是我們項目的必需條件,可以關閉節(jié)點之間的所有網絡連接,并將 Kubernetes 的網絡安全性推遲。
花大量時間學習如何正確地運營 Kubernetes 集群。仔細測試邊界情況。分布式系統(tǒng)非常復雜,有很多潛在的問題。以前面的例子為例: 如果節(jié)點控制器由于配置與 API 服務器失去聯(lián)系,那么它可以殺死集群中的所有 pods。學習 Kubernetes 在每次配置更改后的表現(xiàn)如何,需要時間和精心的關注。
通過專注于這些原則,我們已經有信心在生產中使用 Kubernetes。我們將繼續(xù)開發(fā) Kubernetes 的使用,例如,我們正在關注 AWS EKS 的發(fā)布。我們正在完成另一個系統(tǒng)的工作,訓練機器學習模型,并且正在探索將一些 HTTP 服務遷移到 Kubernetes。隨著我們繼續(xù)在生產中運行 Kubernetes 時,我們計劃對開源項目做出貢獻。
關于如何在生產環(huán)境構建 K8S 就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。