1. 什么是pod
一些關於pod的表述很專業,例如
Pod 是可以在 Kubernetes 中創建和管理的、最小的可部署的計算單元
pod是kubernetes項目中的最小API對象
pod是kubernetes項目的原子調度單位
官方描述:https://kubernetes.io/zh/docs/concepts/workloads/pods/
2. 為什么需要pod
對於這些對pod概念的總結大多殊路同歸。
在理解概念前不妨先想一個問題:
明明有了容器,為什么還需要pod?
因為:
為了解決容器不足,或者說容器無法滿足需求。
確實是這樣,先分析一下容器的本質:
namespace做隔離
Cgroup做限制
rootfs做文件系統
三者相輔相成組成容器基本模型
但是,宏觀的來說,容器的本質是系統中的一個進程。只不過這個進程啟動時被附加了以上等等一下特殊的屬性。
所謂容器只是一個恰當的說法。
就如系統中的大多數進程來說,不是單個進程獨自工作,而是以“進程組”的方式“原則性”的組織在一起,互相協作,完成復雜任務。當然,它們之間也會共享一些資源,例如pid,namespace,存儲等等。
在實際開發和運維中也是隨處可見的這種問題,應用之間有深切的聯系和依賴。
比如說,我要將一個應用容器化,這個應用由負責各個功能的5個進程組成,這時候,問題來了。
正是容器的局限性:單進程模型
單進程不是指容器中只能運行一個進程,而是容器無法去管理多個進程
例如,容器中有pid=1的進程,還有一個pid=5的進程,當這個pid=5的進程異常退出時,后續的垃圾回收等處理工作又由誰去做呢?
所以,這個應用的5個模塊就必須分別制成5個容器,而且必須在同一個機器上運行。
隨之而來的又是一個問題:
也就是容器調度問題,例如有兩個容器調度節點node1和node2,可用內存分別為5G和4.5G,
每個容器分1G內存。由於5個容器必須在一台機器,正常全部調度到node1剛剛好,沒有任何問題。
但是,因為是以容器為單位調度,有這樣一些特殊情況。當前4個容器被調度到node2上時,空間只有0.5G,不足以運行最后一個容器,它有只能在node1運行,這就是以容器為調度單位的缺點。
當然也有解決方案:如Mesos中的資源囤積(resource hoarding),也就是所有調度任務都到達了才進行調度,也有谷歌Omega論文提出樂觀調度,就是先不管沖突,而是在沖突之后通過一系列回滾機制解決沖突。
但這些都沒有很完善的解決容器調度問題,但是在kubernetes中,這些問題都迎刃而解。
因為不在按照傳統思維的將容器作為調度單位
kubernetes中的項目調度器是統一按照pod的資源需求做調度計算
也就是開始總結的那句話: pod是kubernetes項目的原子調度單位
3. pod結構
如圖所示,一個pod包含了兩類容器:
- 用戶容器
- Pause容器,也常常被稱為“根容器”(貌似老版本叫做infra容器)
用戶容器好理解,但是Pause容器,也就是根容器,他是做什么用的呢?
pause容器主要為每個用戶容器提供以下功能:
① PID命名空間:Pod中的不同應用程序可以看到其他應用程序的進程ID。
② 網絡命名空間:Pod中的多個容器能夠訪問同一個IP和端口范圍。
③ IPC命名空間:Pod中的多個容器能夠使用SystemV IPC或POSIX消息隊列進行通信。
④ UTS命名空間:Pod中的多個容器共享一個主機名;Volumes(共享存儲卷):
⑤ Pod中的各個容器可以訪問在Pod級別定義的Volumes。
4. 容器設計模式
考慮這樣一個問題,容器見的關系是一成不變的嗎?
舉一些例子:
- 在pod中的一些容器的啟動,必須依賴某一個正在運行的容器,也就是說這個容器必須比其他容器先啟動
- 在pod中的容器必須同時協作,也就是說所有容器必須並行執行
- 一個pod需要給外部的其他pod提供接口
- 外部訪問pod時,又怎樣確保響應報文的一致性
- ..........
常見容器設計模式:
Init(初始化)容器
Sidecar(邊車)容器
Adapter(適配器)容器
Ambassador(外交官)容器
關於容器設計模式可以參考論文:https://www.usenix.org/conference/hotcloud16/workshop-program/presentation/burns
5. pod實現原理
一定要明白一點:pod只是一個邏輯上的概念
因為kubernetes真正處理的還是宿主機操作系統上容器的Namespace和Cgroup,也就是說沒有所謂的pod邊界或隔離環境。
所以說,pod就是一組共享了某些資源的容器
在一個pod中所有容器是共享一個Network Namespace
的,根據聲明的不同來實現不同的資源共享
但是容器間的復雜關系在容器上難以解決,所以kubernetes項目里,pod的實現借用了一個中間容器,也就是常常說的根容器(也叫pause容器或infra容器,現在好像都統稱pause容器,infra容器已經不再使用)。
在pod中,根容器永遠是第一個創建的容器,用戶后面定義的容器會加入進pod的Network Namespace
,從而在視圖上容器都在pod里。
不妨在k8s中看看這個容器鏡像:
[root@master ~]# docker images | grep pause
registry.aliyuncs.com/google_containers/pause 3.2 80d28bedfe5d 15 months ago 683kB
#當然,主機上有多少個pod就能docker ps 過濾看到多少pause容器
pause鏡像大小只有683k,它是由匯編語言寫的鏡像
在一個pod中的容器,他們的Namespace文件,是一樣的
也就意味着:
- pod內的容器可以使用localhost進行通信
- 根容器能看到的網絡資源,其他容器都能看到,也就是pod的網絡資源和pod內的容器共享
- 一個pod有一個ip地址,和pod對應的Network namespace的ip一致
- pod的生命周期只與根容器有關,與pod內的容器無關
- 從pod里的容器的視角來說,它們的流量進出可以看做是通過根容器完成的