查看原文獲得更好閱讀體驗。
剛開始接觸K8s的同學可能都會覺得有一定的學習難度,撲面而來的各種概念到底是什么。比如,如何提供一個服務給別人,我是應該用Pod還是用Deployment來運行我的應用等,在接下來的文章中,希望能夠解答你的這些疑惑。
Kubernetes可以看做云原生時代的操作系統,統一管理下層的基礎設施,如計算資源、網絡資源、存儲資源等等。將集群中存在的各種復雜關系抽象成各種API資源,以統一的方式暴露出各種接口,也便于未來的擴展以及開發團隊根據自己的需要定制。因此,我們可以看到在K8s中Docker僅僅是容器運行時的一個實現而已,只要遵守它的約定,實際上是可以替換為適合的其他容器技術的。基于這樣的設計思路,理清各種API對象的作用和關系就變得很重要了,只有理解了才能正確地使用K8s,接下來我們就通過一張關系圖一點點的來說明。
通過Pod終結單容器的蠻荒時代
在接觸K8s之前,大多人首先要接觸到的就是Docker。我們得到一個容器的鏡像之后,要把應用運行起來最簡單的方式就是
docker run
的命令。然而在實際的生產環境中,很少僅靠一個單容器就能夠滿足。比如,一個Web前端的應用,可能還得依賴后端的一個容器服務;后端的容器可能需要數據庫服務;后端的服務需要多副本等等場景。在這些假想的場景中,比較真實的需求就是這些容器應用需要共享同一個網絡棧,同一個存儲卷等,還有它們的生命周期如何管理調度。這個時候,僅僅依靠容器無法解決這個問題,我們第一個選手Pod就閃亮登場了。
Pod 內共享配置
有了Pod之后,同一個Pod內的容器可以共享很多信息,也可能需要讀取同一份配置。比如Pod內有兩個容器需要訪問同一個數據庫,那么我們可以把相關的配置信息寫到ConfigMap里。那如果還有一些比較敏感的信息的話,就需要放到Secret對象中,它其實是一個保存在 Etcd 里的鍵值對數據。這樣,你把 Credential 信息以 Secret 的方式存在 Etcd 里,Kubernetes 就會在你指定的 Pod(比如,Web 應用的 Pod)啟動時,自動把 Secret 里的數據以 Volume 的方式掛載到容器里。
任務和定時任務
有了Pod之后,事情就變得更清晰了。在集群內,我們可能會有多種形式的要求。比如,我們可能希望一個應用每天固定時間運行或者只允許運行一次,可能希望某個應用以守護進程的方式運行。在K8s里,自然也有方案來解決這些問題。
首先來看定時任務的需求,假設我的系統內有一個全網信息排行榜展示,要求每天需要在凌晨0點的時候更新一次。這個需求在K8s里就可以用CronJob來搞定。而如果僅僅需要執行一次的任務,那就直接使用Job對象就可以了。
默默工作的DaemonSet
再接下來,可能需要以守護進程的方式運行一個應用。比如,我想要在后臺進行日志的收集。這個時候DaemonSet就派上了用場,它會保證在所有的目標節點上運行一個Pod的副本。在這期間,如果有新的Node加入到K8s集群中的話,它也會自動完成調度,在新的機器上運行一個Pod副本。因此,前面說的監控、日志等任務很適合用DaemonSet的方式執
Deployment管理Pod
說完DaemonSet,下一個重點Deployment來了。前面說過容器之間的關聯關系、共享資源等問題需要處理,從而引入了Pod。對于Pod,也是同樣的問題需要解決,只不過高了一個抽象層次罷了。因為面臨Pod的生命周期管理、調度、多副本等問題需要解決,聰明的設計者引入了Deployment。它可以根據我們的需求(比如通過標簽)將Pod調度到目標機器上,調度完成之后,它還會繼續幫我們繼續監控容器是否在正確運行,一旦出現問題,會立刻告訴我們Pod的運行不正常以及尋找可能的解決方案,比如目標節點不可用的時候它可以快速地調度到別的機器上去。另外,如果需要對應用擴容提升響應能力的時候,通過Deployment可以快速地進行擴展。
在實際的工作中,Deployment并不是直接控制著Pod的,中間實際上還有一個ReplicaSet,但是在這里為了簡化理解過程,可以先忽略。
提供容器服務
前面的內容主要是圍繞著Pod自身的運行調度管理,下面面臨的問題是解決如何將服務提供給第三方的問題。
- 對內提供服務
首先要解決的是將服務提供給同一個集群內的其他服務使用。可能剛入門的同學會問為什么我們不能直接使用Pod的IP呢?原因是這樣,前面也說過Pod是會被管理調度的,可能被調度到不同的機器上,同時生命周期也可能會發生變化。這導致一個應用的IP可能會隨時發生變化,那么直接使用Pod的IP自然是不合理的。
針對這個問題K8s提供了Service對象來解決。
但是,并不是說Service就有一個固定的IP。而且,它和Pod IP還有很不一樣的地方。Pod的網絡是K8s在物理機上建立了一層Overlay Network實現的,而且在網卡上能夠看到這個網絡的地址。但是Service是一個完全虛擬的網絡層,并不會存在于任何網絡設備上。它通過修改集群內部的路由規則,僅對集群內部有效。Deploment創建好應用之后,再為它生成一個Service對象。接下來就可以通過Service的域名訪問到服務,形式是
<Service Name>.<NameSpace>
,比如你有為Deployment的應用創建了一個名為portal的Service在默認的命名空間,那么集群內想要通過Http訪問這個應用,就可以使用http://portal.default。這個域名僅在集群內有效,因為是內部的一個DNS負責解析。
- 對外提供服務
說完如何給內部提供服務以后,剩下的就是如何給外部提供服務了。在K8s里把這個叫做Ingress,正如其名,它是集群的入口。比如我們的集群Web應用想要讓用戶能夠訪問,那必然要在Ingress入口上增加一條解析記錄。這一點,熟悉像Nginx的朋友應該比較容易理解,事實上Nginx Ingress也是K8s生態中的一個成員。
關于Ingress的使用,在之前我曾寫過一篇使用Traefik作為Ingress的文章,我們可以通過Traefik實現為需要暴露的服務提供負載均衡、自動簽發Https證書、限流等很多功能,如果有興趣可以點擊查看。