使用Kubernetes兩年來(lái)的經(jīng)驗(yàn)教訓(xùn)
在Ridecell公司管理基礎(chǔ)設(shè)施團(tuán)隊(duì)幾年后,我想在停下來(lái)休息時(shí)記錄下我的一些想法和經(jīng)驗(yàn)教訓(xùn)。
Kubernetes不僅僅是炒作
我在Kubernetes領(lǐng)域里活躍了很久,所以這并不出乎我的意料,但當(dāng)某件事情被大肆宣傳的時(shí)候,仔細(xì)檢查一下總是好的。在兩年多的時(shí)間里,我的團(tuán)隊(duì)完成了從Ansible+Terraform到純Kubernetes的全面遷移,在這個(gè)過(guò)程中,我們的部署率增加了三倍多,同時(shí)將部署錯(cuò)誤減少到“我都不記得上次是什么時(shí)候發(fā)生的”的水平。我們還提高了操作可見(jiàn)性,大量無(wú)趣卻很重要的自動(dòng)化任務(wù),以及基礎(chǔ)設(shè)施中斷時(shí)的平均恢復(fù)時(shí)間。
Kubernetes并不是魔法,但如果被一個(gè)懂它的團(tuán)隊(duì)使用,那它就是一個(gè)非常強(qiáng)大的工具。
Traefik + Cert-Manager + Ext-DNS組合很棒
Traefik作為Ingress控制器,Cert-Manager通過(guò)LetsEncrypt生成證書,External-DNS管理邊緣DNS記錄,這三個(gè)組合使得HTTP路由和管理像黃油一樣順暢。我一直對(duì)Traefik 2.0中刪除了很多1.x注釋功能的選擇頗有微詞,但它們終于在2.2中回歸了,盡管以不同的形式。作為一個(gè)邊緣代理,Traefik是一個(gè)可靠的選擇,它具有出色的指標(biāo)集成,是所有Ingress控制器中管理部件最少的,以及有一個(gè)反應(yīng)迅速的開(kāi)發(fā)團(tuán)隊(duì)。Cert-Manager配合任意Ingress方案都是一個(gè)神奇的工具,如果你在Kubernetes集群中做了TLS,但還沒(méi)開(kāi)始使用,那現(xiàn)在就去了解下吧。External-DNS沒(méi)有其他兩個(gè)那么受歡迎,但是對(duì)于自動(dòng)化DNS記錄和實(shí)際匹配的步驟來(lái)說(shuō),它的重要性不亞于其他兩個(gè)。
如果有什么不同的話,這些工具實(shí)際上可能使得設(shè)置新的HTTPS端點(diǎn)變得太容易。多年來(lái),我們最終使用了幾十個(gè)獨(dú)特的證書,這在Cert Transparency搜索和LetsEncrypt自己的證書到期警告等方面產(chǎn)生了很多噪音。以后我將會(huì)仔細(xì)考慮哪些主機(jī)名可以作為全局配置的通配符證書的一部分,以減少正在使用的證書總數(shù)。
Prometheus很震撼,Thanos并非大材小用
這是我第一次使用Prometheus作為主要的度量系統(tǒng),它不愧為該領(lǐng)域的首要工具。我們選擇Prometheus-Operator來(lái)管理它,這不失為一個(gè)好的選擇,讓我們更容易將抓取和規(guī)則配置分發(fā)到需要它們的應(yīng)用中。(如果重來(lái)的話,)我會(huì)在一開(kāi)始就使用Thanos。我原本以為使用它會(huì)過(guò)于大材小用,沒(méi)想到它是那么容易配置,而且在跨區(qū)域查詢和減少Prometheus資源使用方面起了很大幫助,即使我們沒(méi)有直接使用主-主互備高可用的設(shè)置。
在使用該技術(shù)棧時(shí)我遇到的最大困擾是Grafana的數(shù)據(jù)管理,如何存儲(chǔ)和組合儀表板。管理儀表板的工具有了巨大的增長(zhǎng),例如YAML文件、JSON文件、Kubernetes自定義對(duì)象,以及你能想到的其他任何東西。但根源問(wèn)題還是任何一個(gè)工具都很難從頭開(kāi)始編寫一個(gè)儀表盤,因?yàn)镚rafana有一百萬(wàn)種不同的配置選項(xiàng)和面板模式等等。我們最終將它作為一個(gè)有狀態(tài)的系統(tǒng)來(lái)處理,將所有的儀表板進(jìn)行分組管理,但我并不喜歡這種解決方案。這里是否有一個(gè)更好的工作流程呢?
GitOps才是正道
如果你使用Kubernetes,那么你應(yīng)該使用GitOps。關(guān)于工具選擇有很多,最簡(jiǎn)單的就是在你現(xiàn)有的CI系統(tǒng)中添加運(yùn)行kubectl apply的作業(yè),一直到使用專用的系統(tǒng)例如ArgoCD和Flux。不過(guò)我堅(jiān)定地站在ArgoCD陣營(yíng),它是一個(gè)可作為開(kāi)始的可靠的選擇,而且在過(guò)去的這些年里它越來(lái)越好。就在這周,GitOps-engine的第一個(gè)版本已經(jīng)上線,其將ArgoCD和Flux放在一個(gè)共享的底層系統(tǒng)上,所以現(xiàn)在更快更好了。如果你不喜歡這些工具的工作流,你現(xiàn)在甚至可以更容易構(gòu)建新的。在幾個(gè)月前我們遇到了一次意外的災(zāi)難恢復(fù)游戲日,因?yàn)橛腥瞬恍⌒膭h除了測(cè)試集群中的大部分命名空間,多虧了GitOps,我們的恢復(fù)方式是在bootstrap庫(kù)中執(zhí)行make apply,然后等待系統(tǒng)自行重建。話說(shuō)回來(lái),對(duì)于一些不能在git中生存的有狀態(tài)數(shù)據(jù)的Velero備份也是很重要的(比如cert-manager的證書,它雖然可以重新簽發(fā),但你可能會(huì)遇到LetsEncrypt的速率限制)。
我們遇到最大的問(wèn)題就是選擇將所有核心基礎(chǔ)設(shè)施保存在一個(gè)存儲(chǔ)庫(kù)中。我依然認(rèn)為使用一個(gè)單一的庫(kù)是正確的設(shè)計(jì),但我將會(huì)將不同的事物劃分到不同的ArgoCD實(shí)例中,而不是像現(xiàn)在將所有都放在一個(gè)“infra”的實(shí)例中。使用單個(gè)實(shí)例導(dǎo)致更長(zhǎng)的收斂時(shí)間和嘈雜的UI,而且如果我們習(xí)慣了正確地分割我們的Kustomize定義的話,它就沒(méi)有多大益處了。
我們應(yīng)用創(chuàng)建更多的Operator
我從一開(kāi)始就積極發(fā)展自定義Operator,且我們?cè)谶@方面取得了巨大的成功。我們從一個(gè)自定義資源和控制器開(kāi)始,用于部署我們的主要網(wǎng)絡(luò)應(yīng)用,并慢慢擴(kuò)展到該應(yīng)用和其他應(yīng)用所需的所有其他自動(dòng)化。使用普通的Kustomize和ArgoCD進(jìn)行簡(jiǎn)單的基礎(chǔ)架構(gòu)服務(wù)效果很好,但是當(dāng)我們想要控制外部事物時(shí)(例如從Kubernetes創(chuàng)建AWS IAM角色,通過(guò)kiam來(lái)使用),或者當(dāng)我們需要某種級(jí)別的狀態(tài)機(jī)來(lái)控制這些事物時(shí)(例如帶有SQL遷移的Django應(yīng)用部署),我們都會(huì)需要用到Operator。 作為其中的一部分,我們還為我們所有的自定義對(duì)象和控制器建立了一個(gè)非常徹底的測(cè)試套件,這極大地提高了操作的穩(wěn)定性和我們自己對(duì)系統(tǒng)正確工作的確定性。
當(dāng)前有越來(lái)越多的方式來(lái)構(gòu)建Opeator,但我仍然對(duì)kubebuilder相當(dāng)滿意(盡管公平地說(shuō),我們確實(shí)隨著時(shí)間的推移大幅修改了項(xiàng)目結(jié)構(gòu),所以說(shuō)它使用的是controller-runtime和controller-tools比kubebuilder本身更公平)。無(wú)論你最喜歡使用哪種語(yǔ)言和框架,都可能有可用的Operator工具包,你絕對(duì)應(yīng)該使用它。
Secret管理仍是難題
Kubernetes有自己的Secret對(duì)象,用于在運(yùn)行時(shí)管理秘密數(shù)據(jù),與容器或與其他對(duì)象一起使用,而且這個(gè)系統(tǒng)工作得很好。但是Secret的長(zhǎng)期工作流程還是有點(diǎn)亂。把一個(gè)原始的Secret提交到Git是很糟糕的,原因有很多,希望我不需要列舉,那么我們?nèi)绾喂芾磉@些對(duì)象呢?我的解決方案是開(kāi)發(fā)一個(gè)自定義的EncryptedSecret類型,它使用AWS KMS對(duì)每個(gè)值進(jìn)行加密,同時(shí)在Kubernetes中運(yùn)行的控制器像往常一樣將其解密回正常的Secret,還有一個(gè)用于解密-編輯-再加密循環(huán)的命令行工具。使用 KMS意味著我們可以通過(guò)IAM規(guī)則限制KMS密鑰的使用來(lái)做訪問(wèn)控制,并且只加密值,讓文件有合理的差異性?,F(xiàn)在有一些基于Mozilla Sops的社區(qū)Operator提供了大致相同的工作流,盡管Sops在本地編輯工作流程上有點(diǎn)令人沮喪。總的來(lái)說(shuō),這個(gè)領(lǐng)域還需要很多努力,人們應(yīng)該期待一個(gè)可審計(jì)、可版本化、可代碼審查的工作流,就像在GitOps世界里的所有事情一樣。
作為一個(gè)相關(guān)的問(wèn)題,Kubernetes的RBAC模型的弱點(diǎn)在Secrets上表現(xiàn)得最為明顯。幾乎在所有情況下,被用于一個(gè)事物的Secret必須和使用它的事物在同一個(gè)命名空間中,這往往意味著很多不同事物的Secret最終會(huì)在同一個(gè)命名空間中(數(shù)據(jù)庫(kù)密碼、廠商API令牌、TLS證書),如果你想給某人(或某事,同樣的問(wèn)題適用于Operator)訪問(wèn)其中一個(gè),他們就會(huì)獲得所有的訪問(wèn)權(quán)限。讓你的命名空間盡可能的小,任何可以放在它自己的命名空間的東西,都去做吧。你的RBAC策略會(huì)感謝你現(xiàn)在的做法。
原生CI和日志分析仍是開(kāi)放性問(wèn)題
我遇到的兩大生態(tài)系統(tǒng)坑就是CI和日志分析。有很多部署在Kubernetes的CI系統(tǒng),例如Jenkins、Concourse、Buildkite等。但感覺(jué)完全類原生的解決方案很少。JenkinsX可能是最接近原生體驗(yàn)的,但它是建立在非常大的復(fù)雜性上,我覺(jué)得非常可惜。Prow本身也是非常原生的,但定制化很多,所以也不是一個(gè)容易上手的工具。Tekton Pipelines和Argo Workflows都有原生CI系統(tǒng)的低級(jí)管道,但是找到一種方法將其暴露給我的開(kāi)發(fā)團(tuán)隊(duì)從來(lái)沒(méi)有超出理論操作人員的范圍。Argo-CI似乎已經(jīng)被放棄了,但Tekton團(tuán)隊(duì)似乎正在積極地追蹤這個(gè)用例,所以我對(duì)它的一些改進(jìn)充滿希望。
日志收集基本上是一個(gè)已解決的問(wèn)題,社區(qū)集中在Fluent Bit上,將其作為一個(gè)DaemonSet發(fā)送給一些Fluentd pods,然后再發(fā)到你用來(lái)存儲(chǔ)和分析的任何系統(tǒng)上。在存儲(chǔ)方面,我們有ElasticSearch和Loki作為主要的開(kāi)放競(jìng)爭(zhēng)者,每個(gè)都有自己的分析前端(Kibana和Grafana)。似乎主要還是最后一部分是我的挫敗感的來(lái)源。Kibana出現(xiàn)的時(shí)間更久,分析功能也很豐富,但你必須使用商業(yè)版來(lái)獲得基本的操作,比如用戶身份驗(yàn)證和用戶權(quán)限仍然非常模糊。Loki要新得多,分析工具就更少了(子字符串搜索和每行標(biāo)簽搜索),至今沒(méi)有任何針對(duì)權(quán)限的設(shè)計(jì)。如果你小心翼翼地確保所有的日志輸出是安全的,可以讓所有的工程師看到,這沒(méi)問(wèn)題,但你要準(zhǔn)備好在SOC/PCI等審計(jì)中遇到一些尖銳的問(wèn)題。
結(jié)語(yǔ)
Kubernetes并不是很多人所說(shuō)的那種可全套交付的解決方案,但是通過(guò)一些精心的工程設(shè)計(jì)和非凡的社區(qū)生態(tài)系統(tǒng),它可以成為一個(gè)無(wú)與倫比的平臺(tái)?;c(diǎn)時(shí)間學(xué)習(xí)每個(gè)底層組件,你將會(huì)在通往容器幸福的道路上走得很好,希望你在此過(guò)程中能避免我的一些錯(cuò)誤。