生產環境使用一年Kubernetes的經驗教訓
【編者的話】Luminis Technologies使用Kubernetes的經驗總結,供大家學習
2015年初,在Amazon EC2上執行部署多年後,我在 Luminis Technologies 的團隊接受了一個新任務,該任務是為所有我們的開發團隊建立一個新的部署平臺。基於AWS的配置環境多年來一直為我們服務的很好,但這套使用自定義指令碼和工具自動化部的配置環境對於運營團隊以外的團隊並不是很容易使用的,尤其是那些小團隊,他們沒有資源來學習所有這些指令碼和工具的詳細資訊。主要問題是沒有“部署單元”,一沒有個,導致開發和運營之間的存在一個鴻溝。 容器化趨勢 顯然會改變這種情況。
如果你仍然還沒有準備在生產環境引入Docker和Kubernetes,可以瞭解下我的團隊是如何成為早期“嚐鮮者”的。我們現在已經在生產環境中執行Kubernetes有一年多了。
開始用容器和容器編制工具
我現在相信 容器是未來部署應用的事實標準 ,容器讓你更容易打包應用程式所需的基礎設施。而像Docker這樣的工具可以提供真正的容器,我們也需要工具來管理容器的複製和故障切換,以及也需要API來自動化部署到多臺機器。
Kubernetes和Docker Swarm等編排工具 在2015年初的狀態還是很不成熟的,只有早期的alpha版本。我們還試著使用它們,開始使用的是Docker Swarm。
起初,我們自己用它來處理網路,通過通過Ambassador模式容器和很多指令碼來自動化部署。它能有多難?這是我們學到的第一課: 容器叢集、網路和自動化部署實際上是很難解決的問題。
我們很快意識到這一點,決定押注在另一個可用的工具上。Kubernetes似乎是最好的選擇,因為它是由谷歌,Red Hat、Core OS和其他團體支援的,這些團體顯然知道如何執行大規模部署。
使用Kubernetes負載平衡
在使用Kubernetes時,你必須熟悉 節點 、 服務 和和 複製控制器 等這些概念。如果你不熟悉這些概念,有一些優秀的資源可以讓你跟上節奏。 Kubernetes 文件 是一個很好的開始,因為它有好幾個初學者指南。
一旦有一個Kubernetes叢集可以啟動並執行,我們可以使用使用kubectl(Kubernetes CLI)部署一個應用程式,但我們很快發現當我們想自動化部署時,kubectl並不足夠。但首先,我們有另一個問題要解決:如何從網際網路上訪問部署的應用程式?
在部署前面的服務有一個IP地址,但是這個地址只在Kubernetes叢集中。這意味著這個服務在網際網路上根本不可用!當執行在谷歌雲引擎(Google Cloud Engine,GCE)時,Kubernetes可以自動配置一個負載均衡器來訪問應用程式。如果你不是在GCE上(像我們這樣),你需要做一些額外的工作來使負載平衡工作。
直接在主機埠上提供服務是有可能的,這是很多人開始會的,但是我們發現它錯過了很多Kubernetes的提供便利。如果我們依賴主機的埠,我們在部署多個應用程式時將會遇到埠衝突。這也使得它更難規模化叢集或更換主機。
兩步設定負載均衡器
我們發現一個更好的方法是配置一個負載均衡器例如HAProxy或NGINX,在Kubernetes叢集前面。我們開始在AWS上的VPN內執行Kubernetes叢集,使用AWS彈性負載均衡將外部網頁流量路由到一個內部HAProxy叢集。HAProxy為為每個Kubernetes服務配置一個“後端”,它將流量代理到每個節點。
這兩步配置負載均衡的方法主要是為了應對AWS ELB很有限的配置選項。其中限制之一是,它不能處理多個虛擬主機 。這正是我們使用HAProxy的原因。只用HAProxy(沒有ELB)也可以工作,但是你將不得不在DNS上解決AWS的動態IP地址問題。

圖1:兩步負載平衡
在任何情況下,當新的Kubernetes服務建立時,我們需要一種機制來動態地重新配置負載均衡(HAProxy,在我們的例子中)。
Kubernetes社群目前正在開發一個特性 ingress 。 它能夠直接從Kubernetes配置一個外部負載均衡。目前這個特性還沒有真正可用,因為它沒有完成。去年,我們使用API和一個小開源工具來配置負載均衡。
配置負載均衡
首先,我們需要一個地方來儲存負載均衡的配置。他們可以儲存在任何地方,但由於我們已經有 etcd 可用,我們決定在那裡儲存負載均衡的配置。我們使用的工具 confd 監控etcd的配置更改,並基於模板生成一個新的HAProxy配置檔案。當一個新的服新增到Kubernetes,我們新增一個新的配置到etcd,這會產生一個新的配置檔案給HAProxy。
Kubernetes:成熟的正確方法
Kubernetes仍然存在許多尚未解決的問題,就像他們經常在負載均衡中表現的那樣。這些問題正在被社群所識別,也有一些文件來討論解決其中的一些問題。但想出適合每個人的解決方案是需要時間的,這就意味著在他們釋出版本解決其中一些問題之前需要花費很長一段時間。 這是一件好事 ,因為在設計新功能時走捷徑長期來看是非常不利的。
這並不意味著現在Kubernetes是不易使用的。使用API,可以讓Kubernetes做幾乎所有你需要的事,如果你現在開始使用它。一旦更多的功能整合到Kubernetes版本中,我們可以用標準方案替換我們自己的解決方案。
我們開發完自己的負載均衡解決方案後,我們的下一個挑戰是實現一個基本的部署方案:藍綠部署。
Kubernetes中的藍綠部署
藍綠部署是一個沒有任何停機時的方案。相比滾動更新,藍綠部署是先啟動一個新版本的副本叢集,此時所有的舊副本仍然為實時請求提供服務。只有當新的副本完全啟動並執行,負載均衡配置改變,將負載切換到新版本。這種方法的一個好處是,總是隻有一個版本的應用程式在執行,減少處理多個併發版本的複雜性。當副本的數量是相當小時,藍綠部署可以更好地工作。

圖2:Kubernetes藍綠部署
圖2顯示一個元件“部署者”,來協調部署。該元件可以很容易由你自己的團隊建立,因為我們基於Apache許可 開源了我們的實現 ,作為 Amdatu umbrella 專案 一部分,它還提供了一個web介面來配置部署。
這種機制的一個重要方面是健康檢查,在重新配置負載均衡前,它在節點上執行之。我們希望部署的每個元件都能夠進行健康檢查。現在我們通常通過HTTP在每個應用程式元件上新增一個健康檢查。
自動部署
有了“部署者” ,我們可以把部署掛到構建流上。構建成功後,構建伺服器可以提交一個新的容器到註冊中心如Docker Hub,然後構建伺服器喚起“部署者”自動將新版本部署到測試環境。通過觸發生產環境的部署者,可以將相同的映象提交到生產環境。

圖3:我們自動化容器部署流水線
知道你的資源約束
當我們開始使用Kubernetes時,知道我們的 資源約束 是至關重要。你可以配置資源請求和CPU /記憶體限制在每個節點上,你還可以控制資源保障和峰值限制。
對於有效地執行多個容器在一起,這些設定是非常重要的。如果我們不正確地設定這些值,容器會經常崩潰,因為他們無法分配足夠的記憶體。
早開始設定和測試約束。沒有限制,一切仍將執行很好,但當你把任何重負載放到其中一個容器時,你會得到一個巨大的,令人不快的意外。
我們如何監控Kubernetes
當我們使用Kubernetes配置完畢,我們很快意識到在這個新的動態環境中監控和日誌至關重要。登入到一個伺服器檢視日誌不再好使了,當你處理大量的副本和節點時。一旦你開始使用Kubernetes,你也應該有一個計劃建立集中化的日誌記錄和監控。
日誌記錄
有很多開源工具可用於日誌記錄。我們決定使用 Graylog (一個優秀的日誌記錄工具)和 Apache Kafka,一個訊息系統 從我們的容器收集和記錄日誌。容器傳送日誌給Kafka,Kafka處理日誌給Graylog索引。我們選擇使應用程式元件傳送日誌給Kafka,這樣我們就可以易於索引的方式流化日誌記錄。 其他替代方案 ,有工具可以從容器外部獲得日誌,並轉發給一個日誌記錄方案。
監控
當節點有錯誤時,Kubernetes做了出色的工作來恢復節點。當節點由於任何原因崩潰時,Kubernetes將重新啟動它們。當Kubernetes正在運行復制時,終端使用者可能甚至都不會察覺有錯誤發生。Kubernetes的恢復工作如此完美,以至於我們的容器因為記憶體洩露一天崩潰多次,而任何人(包括我們)都沒有發現。
儘管從Kubernetes的角度來看,這是很棒的,你可能仍然想知道何時發生了問題。我們使用一個定製的健康檢查面板來監測Kubernetes節點,單獨節點(使用程式特製的健康檢查)和其他服務如資料儲存。實現一個這樣的儀表面板,Kubernetes API再次被證明可以提供非常寶貴的資訊。
我們也認為測量負載、吞吐量、應用程式錯誤和其他統計資料是重要的。開源社群再一次提供了很多選擇。我們的應用程式元件在時間序列儲存 InfluxDB 中提供了測量指標。我們還使用了 Heapster 收集Kubernetes指標。在InfluxDB的指標可以通過一個開源的儀表板工具 Grafana 來視覺化。有很多替代品InfluxDB/Grafana的組合,他們中任何一個都可以提供很多有價值的東西來跟蹤容器如何執行的。
資料儲存和Kubernetes
許多Kubernetes新使用者都會問的一個問題是:“我該如何使用Kubernetes儲存我的資料 ?”
當執行一個數據庫如MongoDB或MySQL,你最有可能想要將資料持久化。在容器之外,容器重新啟動時會丟失資料。這對於無狀態的元件是極好的,但對於一個持久化資料庫並不是。Kubernetes中有卷的概念來持久化資料。
卷可以支援多種實現,包括在主機機器上的檔案、AWS彈性塊儲存(EBS)和 nfs 。當我們在研究持久化資料問題時,卷提供了一個好的答案,但對我們執行資料庫來說,它不是一個解決方案。
複製問題
在大多數部署,資料庫也是以副本執行的。Mongo通常執行在一個複製集合中,而MySQL可以以主/從模式執行。這就帶來了一些問題。首先,重要的是資料庫叢集中的每個節點是由一個不同的卷實現的。往同一個卷寫將會導致資料損壞。另一個問題是,大多數資料儲存需要精確配置,來使叢集啟動並執行;自動發現和配置的節點是不常見的。
同時,執行資料庫的機器通常是為這種型別工作負載專門進行過調優。更高的IOPS便是其中一個例子。 擴充套件(新增/移除節點)是一項昂貴的操作對於大多數資料庫。這些東西與Kubernetes部署的動態特性很不匹配。
決定生產環境執行資料庫不使用Kubernetes
這使給我們遇到一種情況,我們發現Kubernetes內執行一個數據庫的好處是有限的。Kubernetes給我們的動態性並不能使用,配置也比大多數Kubernetes部署複雜得多。
由於這個原因, 我們沒有在Kubernetes內執行生產環境資料庫 。相反,我們手動設定這些叢集在其他主機上,並進行所有必要的調優來優化資料庫儲存。我們Kubernetes內的應用程式執行就像正常連線到資料儲存叢集那樣。最重要的教訓是, 一旦有了Kubernetes,你不需要將一切執行在Kubernetes內 。不過,除了資料庫和HAProxy伺服器,其他一切確實都在Kubernetes內執行,包括我們的監控和日誌記錄方案。
擁抱Kubernetes,為什麼我們對明年很興奮
看看我們現在的部署,Kubernetes絕對是了不起的。Kubernetes API是一個很好的工具用於自動化部署流水線。部署不僅更可靠,而且速度快得多,因為我們不再和虛擬機器打交道。我們的構建和部署更加可靠,因為它在容器中更容易測試和分發。
我們現在看到的這個新的部署方式是必要的,這樣可以和行業內其他開發團隊更頻繁地進行部署,並降低他們的工作量。
成本計算
看成本,這個故事有兩個方面。為了執行Kubernetes,需要一個etcd叢集,以及主節點。雖然這些不一定是昂貴的元件,這個開銷對一個很小的部署可以說是相對昂貴的。對於這些型別的部署,最好的方式是使用託管解決方案如谷歌容器服務。
對於更大的部署,很容易在伺服器上節省很多。執行etcd和主節的開銷在這些部署中並不是很明顯的。Kubernetes使得在同一主機上執行很容器很容易,最大限度的利用可用的資源。這減少了所需的伺服器數量,直接節省你的錢。執行Kubernetes聽起來很不錯,但執行這種叢集的運營工作似乎不那麼有吸引力,有許多託管服務可以考慮,包括Cloud RTI,這就是我的團隊所使用的。
Kubernetes的光明未來
執行預釋出版本的Kubernetes是非常有挑戰性的,跟上(超越)新版本幾乎是不可能的。Kubernetes的開發在過去的一年裡一直在光速進行,社群已經成長為一個有很多開發人才的正規強大組織。很難相信僅僅在一年多的時間裡取得了這麼大的進步。
原文連結: One year using Kubernetes in production: Lessons learned (翻譯:姜俊厚)