Kubernetes投入生產的3年,我們得到的一些經驗教訓

我們從2017年開始基於1.9.4版本構建第一個Kubernetes 集羣。 我們有兩個集羣,一個集羣在裸金屬的RHEL 虛擬機上運行,另一個集羣在AWS EC2上運行。

現在,我們的Kubernetes 基礎設施平臺由分佈在多個數據中心的400多臺虛擬機組成。 該平臺託管了高可用的關鍵任務軟件應用程序和系統,以管理具有近四百萬個活動設備的大型實時網絡。

Kubernetes 最終使我們變得更輕鬆,但是這個過程很艱難,是一種思維上的轉變。 不僅讓我們的技能和工具有了徹底的轉變,還讓我們的設計和思維也得到了徹底的轉變。 我們不得不採用多種新技術,並進行大量投資以擴展和提高我們的團隊和基礎架構的技能。

回顧Kubernetes 在生產環境中運行的這三年,我們記下了一些很重要的經驗教訓。

  1. Java應用程序的奇怪案例

在微服務和容器化方面,工程師傾向於避免使用Java,這主要是由於Java 臭名昭著的內存管理。 但是,現在情況發生了改變,過去幾年來Java 的容器兼容性得到了改善。 畢竟,大量的系統(例如Apache KafkaElasticsearch)在Java上運行。

回顧2017-18年度,我們有一些應用程序在Java 8上運行。這些應用程序通常很難理解像Docker 這樣的容器環境,並因堆內存問題和異常的垃圾回收趨勢而崩潰。 我們瞭解到,這是由於JVM 無法使用Linuxcgroupnamespace造成的,而它們是容器化技術的核心。

但是,從那時起,Oracle 一直在不斷提高Java 在容器領域的兼容性。 甚至Java 8的後續補丁都引入了實驗性的JVM 標誌來解決這些問題,XX:+UnlockExperimentalVMOptionsXX:+UseCGroupMemoryLimitForHeap

但是,儘管做了所有的這些改進,不可否認的是,Java 在內存佔用方面仍然聲譽不佳,與Python 或Go 等同行相比啓動速度慢。 這主要是由JVM 的內存管理和類加載器引起的。

現在,如果我們必須選擇Java,請確保版本爲11或更高。 並且Kubernetes 的內存限制要在JVM 最大堆內存(-Xmx)的基礎上增加1GB,以留有餘量。 也就是說,如果JVM 使用8GB的堆內存,則我們對該應用程序的Kubernetes 資源限制爲9GB。

  1. Kubernetes 生命週期管理:升級

Kubernetes 生命週期管理(例如升級或增強)非常繁瑣,尤其是如果已經在裸金屬或虛擬機上構建了自己的集羣。 對於升級,我們已經意識到,最簡單的方法是使用最新版本構建新集羣,並將工作負載從舊版本過渡到新版本。 節點原地升級所做的努力和計劃是不值得的。

Kubernetes 具有多個活動組件,需要升級保持一致。 從Docker 到Calico 或Flannel 之類的CNI 插件,你需要仔細地將它們組合在一起才能正常工作。 雖然像Kubespray、Kubeone、Kops和Kubeaws 這樣的項目使它變得更容易,但它們都有缺點。

我們在RHEL 虛擬機上使用Kubespray 構建了自己的集羣。 Kubespray 非常棒,它具有用於構建、添加和刪除新節點、升級版本的playbook,以及我們在生產環境中操作Kubernetes 所需的幾乎所有內容。 但是,用於升級的playbook附帶了免責聲明,以避免我們跳過子版本。 因此,必須經過所有中間版本才能到達目標版本。

關鍵是,如果你打算使用Kubernetes 或已經在使用Kubernetes,請考慮生命週期活動以及解決這一問題的方案。 構建和運行集羣相對容易一些,但是生命週期維護是一個全新的體驗,具有多個活動組件。

  1. 構建和部署

在準備重新設計整個構建和部署流水線之前, 我們的構建過程和部署必須經歷Kubernetes 世界的完整轉型。 不僅在Jenkins 流水線中進行了大量的重構,而且還使用了諸如Helm 之類的新工具,策劃了新的git 流和構建、標籤化docker 鏡像,以及版本化helm 的部署chart。

你需要一種策略來維護代碼,以及Kubernetes 部署文件、Docker 文件、Docker 鏡像、Helm chart,並設計一種方法將它們組合在一起。

經過幾次迭代,我們決定採用以下設計。

  • 應用程序代碼及其helm chart 放在各自的git 存儲庫中。 這使我們可以分別對它們進行版本控制(語義版本控制)。
  • 然後,我們將chart 版本與應用程序版本關聯起來,並使用它來跟蹤發佈。 例如,app-1.2.0使用charts-1.1.0進行部署。 如果只更改Helm 的values 文件,則只更改chart 的補丁版本(例如,從1.1.01.1.1)。所有這些版本均由每個存儲庫中的RELEASE.txt中的發行說明規定。
  • 對於我們未構建或修改代碼的系統應用程序,例如Apache Kafka 或Redis ,工作方式有所不同。 也就是說,我們沒有兩個git 存儲庫,因爲Docker 標籤只是Helm chart 版本控制的一部分。 如果我們更改了docker 標籤以進行升級,則會升級chart 標籤的主要版本。
  1. 存活和就緒探針(雙刃劍)

Kubernetes 的存活探針和就緒探針是自動解決系統問題的出色功能。 它們可以在發生故障時重啓容器,並將流量從不正常的實例進行轉移。 但是,在某些故障情況下,這些探針可能會變成一把雙刃劍,並會影響應用程序的啓動和恢復,尤其是有狀態的應用程序,例如消息平臺或數據庫。

我們的Kafka 系統就是這個受害者。 我們運行了一個3 Broker 3 Zookeeper有狀態副本集,該狀態集的ReplicationFactor爲3,minInSyncReplica爲2。當系統意外故障或崩潰導致Kafka 啓動時,問題發生了。 這導致它在啓動期間運行其他腳本來修復損壞的索引,根據嚴重性,此過程可能需要10到30分鐘。 由於增加了時間,存活探針將不斷失敗,從而向Kafka 發出終止信號以重新啓動。 這阻止了Kafka 修復索引並完全啓動。

唯一的解決方案是在存活探針設置中配置initialDelaySeconds,以在容器啓動後延遲探針評估。 但是,問題在於很難對此加以評估。 有些恢復甚至需要一個小時,因此我們需要提供足夠的空間來解決這一問題。 但是,initialDelaySeconds越大,彈性的速度就越慢,因爲在啓動失敗期間Kubernetes 需要更長的時間來重啓容器。

因此,折中的方案是評估initialDelaySeconds字段的值,以在Kubernetes 中的彈性與應用程序在所有故障情況(磁盤故障、網絡故障、系統崩潰等)下成功啓動所花費的時間之間取得更好的平衡 。

更新:如果你使用最新版本,Kubernetes 引入了第三種探針類型,稱爲“啓動探針”,以解決此問題。 從1.16版開始提供alpha 版本,從1.18版開始提供beta 版本。

啓動探針會禁用就緒和存活檢查,直到容器啓動爲止,以確保應用程序的啓動不會中斷。

  1. 公開外部IP

我們瞭解到,使用靜態外部IP 公開服務會對內核的連接跟蹤機制造成巨大代價。除非進行完整的計劃,否則它很輕易就破壞了擴展性。

我們的集羣運行在Calico for CNI上,在Kubernetes 內部採用BGP作爲路由協議,並與邊緣路由器對等。對於Kubeproxy,我們使用IP Tables模式。我們在Kubernetes 中託管着大量的服務,通過外部IP 公開,每天處理數百萬個連接。由於來自軟件定義網絡的所有SNAT 和僞裝,Kubernetes 需要一種機制來跟蹤所有這些邏輯流。爲此,它使用內核的Conntrack and netfilter工具來管理靜態IP 的這些外部連接,然後將其轉換爲內部服務IP,然後轉換爲pod IP。所有這些都是通過conntrack表和IP 表完成的。

但是conntrack表有其侷限性。一旦達到限制,你的Kubernetes 集羣(如下所示的OS 內核)將不再接受任何新連接。在RHEL 上,可以通過這種方式進行檢查。

$  sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_maxnet.netfilter.nf_conntrack_count = 167012
net.netfilter.nf_conntrack_max = 262144

解決此問題的一些方法是使用邊緣路由器對等多個節點,以使連接到靜態IP的傳入連接遍及整個集羣。 因此,如果你的集羣中有大量的計算機,累積起來,你可以擁有一個巨大的conntrack表來處理大量的傳入連接。

回到2017年我們剛開始的時候,這一切就讓我們望而卻步,但最近,Calico 在2019年對此進行了詳細研究,標題爲“爲什麼conntrack不再是你的朋友”。

你是否一定需要Kubernetes嗎?

三年過去了,我們每天仍然在繼續發現和學習新知識。它是一個複雜的平臺,具有自己的一系列挑戰,尤其是在構建和維護環境方面的開銷。它將改變你的設計、思維、架構,並需要提高技能和擴大團隊規模以適應轉型。

但是,如果你在雲上並且能夠將Kubernetes 作爲一種“服務”使用,它可以減輕平臺維護帶來的大部分開銷,例如“如何擴展內部網絡CIDR?”或“如何升級我的Kubernetes 版本?”

今天,我們意識到,你需要問自己的第一個問題是“你是否一定需要Kubernetes?”。這可以幫助你評估所遇到的問題以及Kubernetes 解決該問題的重要性。

Kubernetes 轉型並不便宜,爲此支付的價格必須確實證明“你的”用例的必要性及其如何利用該平臺。如果可以,那麼Kubernetes 可以極大地提高你的生產力。

記住,爲了技術而技術是沒有意義的。

原文鏈接:
3 Years of Kubernetes in Production–Here’s What We Learned

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章