前言
大家好,我是秋意零。
前一篇,我們介紹了如何從 0 到 1 搭建 Kubernetes 集群?,F(xiàn)在我們可以正式了解,Kubernetes 核心特征了。今天我們來(lái)探究 Pod,為什么需要 Pod?
?? 簡(jiǎn)介
- ?? 個(gè)人主頁(yè): 秋意零
- ?? 個(gè)人介紹:在校期間參與眾多云計(jì)算相關(guān)比賽,如:?? “省賽”、“國(guó)賽”,并斬獲多項(xiàng)獎(jiǎng)項(xiàng)榮譽(yù)證書
- ?? 目前狀況:24 屆畢業(yè)生,拿到一家私有云(IAAS)公司 offer,暑假開始實(shí)習(xí)
- ?? 賬號(hào):各個(gè)平臺(tái), 秋意零 賬號(hào)創(chuàng)作者、 云社區(qū) 創(chuàng)建者
- ??歡迎大家:歡迎大家一起學(xué)習(xí)云計(jì)算,走向年薪 30 萬(wàn)
專欄
深入探索 Kubernetes 專欄地址
系列文章目錄
【云原生|探索 Kubernetes-1】容器的本質(zhì)是進(jìn)程
【云原生|探索 Kubernetes-2】容器 Linux Cgroups 限制
【云原生|探索 Kubernetes 系列 3】深入理解容器進(jìn)程的文件系統(tǒng)
【云原生|探索 Kubernetes 系列 4】現(xiàn)代云原生時(shí)代的引擎
【云原生|探索 Kubernetes 系列 5】簡(jiǎn)化 Kubernetes 的部署,深入解析其工作流程
正文開始:
- 快速上船,馬上開始掌舵了(Kubernetes),距離開船還有 3s,2s,1s…
一、最小管理單元介紹
在 Kubernetes 中所有特征性服務(wù),如:Pod、Service、Deployment、DaemonSet 等。像這些都是 Kubernetes 中的 API 對(duì)象,都提供了一個(gè) API 接口,并可以通過(guò)這些對(duì)象接口實(shí)現(xiàn)調(diào)用,也就是我們常說(shuō)的: “API 接口調(diào)用”。如果后期有需求的話,本專欄也會(huì)包含這部分的內(nèi)容哦!!
Pod 是 Kubernetes 中最小的 API 對(duì)象,或者說(shuō)是最小的部署和管理單元。
下面我們看看,ChatGPT 詳解介紹的 Pod:
二、為什么 Kubernetes 需要 Pod ?
回答這個(gè)問(wèn)題之前,我們回憶一下我們?cè)谧x本專欄第 1 篇文章時(shí)講過(guò)的,容器的本質(zhì)是進(jìn)程。
- 如果模糊了可以跳轉(zhuǎn)復(fù)習(xí)復(fù)習(xí): 【云原生|探索 Kubernetes-1】容器的本質(zhì)是進(jìn)程
容器是進(jìn)程,容器鏡像就相當(dāng)于 windows 系統(tǒng)中的 “.exe” 安裝包,而 Kubernetes 就是操作系統(tǒng)。
- 我們?cè)诒緦诘?4 篇文章提到過(guò):【云原生|探索 Kubernetes 系列 4】現(xiàn)代云原生時(shí)代的引擎(目錄:四、Kubernetes 要解決的問(wèn)題是什么?)
來(lái)感受一下
我們?cè)?Linux 機(jī)器上,安裝 pstree 命令,需要執(zhí)行以下指令:
# 1.查找 pstree 命令的依賴包
$ yum provides pstree
...
psmisc-22.20-17.el7.x86_64 : Utilities for managing processes on your system
...
$ yum install -y psmisc-22.20-17.el7.x86_64
pstree
命令,以樹狀圖形式顯示進(jìn)程信息:
我們發(fā)現(xiàn)操作系統(tǒng)中的進(jìn)程,并不是單個(gè)獨(dú)自運(yùn)行的,而是以進(jìn)程組的方式,相互協(xié)作組織在一起。
- 圖中,我們可以看到,框出的地方:
master
進(jìn)程 id 是1134
,而它還包含了兩個(gè)進(jìn)程pickup
和qmgr
進(jìn)程 id 也是1134
。它們同屬于 1134 進(jìn)程組,這些進(jìn)程相互協(xié)作,共同完成 master 程序的職責(zé)。(好笑的是:我并不知道,master 這個(gè)進(jìn)程的作用)
注意:上訴中,提到的
pickup
和qmgr
“進(jìn)程” 其實(shí)是 Linxu 系統(tǒng)中的 “線程”。這些線程,可以共享文件、信號(hào)、數(shù)據(jù)內(nèi)存、甚至部分代碼,從而緊密協(xié)作共同完成一個(gè)程序的職責(zé)。
這樣一來(lái)我們就能理解 Pod 了吧,Kubernetes 項(xiàng)目所做的,其實(shí)就是將 “進(jìn)程組” 的概念映射到了容器技術(shù)中:
- Pod 里面包含了容器,Pod 里面的容器看作是 Pod 的線程,而 Pod 看作是一個(gè)進(jìn)程組,運(yùn)行在操作系統(tǒng)中,也就是我們這里的 Kubernetes 中。從而 Pod 成為 Kubernetes 操作系統(tǒng)中的 “一等公民”。
這么做的原因
在 Borg 項(xiàng)目的開發(fā)和實(shí)踐過(guò)程中,工程師發(fā)現(xiàn),他們部署的應(yīng)用,一般都存在類似 “進(jìn)程和進(jìn)程組” 的關(guān)系,應(yīng)用之間有著密切的協(xié)作關(guān)系,使得它們必須部署在同一臺(tái)機(jī)器上。所以我們上圖中的 master
進(jìn)程和其 pickup
和 qmgr
“子進(jìn)程”,必須在同一臺(tái)機(jī)器上,否則它們之間的 Socket 通信和文件交換,都會(huì)出現(xiàn)問(wèn)題。
1.容器的 “單進(jìn)程模型”:
-
單進(jìn)程模型,這句話是說(shuō):不是只能運(yùn)行一個(gè)進(jìn)程,而是不具備管理多個(gè)進(jìn)程的能力。因?yàn)槿萜鞯?
PID=1
的進(jìn)程就是自己應(yīng)用本身,其他的進(jìn)程都是這個(gè) PID=1 進(jìn)程的子進(jìn)程。所以PID=1
的進(jìn)程應(yīng)用,一般是不會(huì)具有像操作系統(tǒng)里面的init (初始化)進(jìn)程
或者systemd 進(jìn)程管理
的功能。 -
舉個(gè)例子,比如:現(xiàn)在容器中有個(gè)
PID=1
的Web
應(yīng)用,然后你進(jìn)入容器在里面安裝啟動(dòng)了一個(gè)Nginx
進(jìn)程PID=3
。當(dāng)Nginx
進(jìn)程異常退出的時(shí)候,你是不知道的,退出后它的內(nèi)存垃圾回收等工作,PID=1
的Web 應(yīng)用
是不會(huì)理睬的,這種情況下PID=1
的進(jìn)程是被宿主機(jī)管理的,而其他進(jìn)程就沒有誰(shuí)來(lái)管理了。
總結(jié):容器不提倡單進(jìn)程不是因?yàn)椴荒苓\(yùn)行多個(gè)進(jìn)程,而是因?yàn)闆]有 systemd 這種功能的 1 號(hào)進(jìn)程來(lái)管理程序。
2.舉個(gè)例子:
而由于,容器的 “單進(jìn)程模型”,master 進(jìn)程組必須被部署在不同的三個(gè)容器中,假設(shè)這三個(gè)容器,設(shè)置的內(nèi)存配額都至少需要 1 GB。如果,我們的 Kubernetes 集群上有兩個(gè)節(jié)點(diǎn):node-1 上有 3 GB 可用內(nèi)存,node-2 有 2.5 GB 可用內(nèi)存。
-
這時(shí),假設(shè)我要用 Docker Swarm 來(lái)運(yùn)行這個(gè)
master
程序。為了能夠讓這三個(gè)容器都運(yùn)行在同一臺(tái)機(jī)器上,我就必須在另外兩個(gè)容器(pickup
和qmgr
)上設(shè)置一個(gè)affinity=master
(與 master 容器有親和性)的約束,即:pickup
和qmgr
它們倆必須和master
容器運(yùn)行在同一臺(tái)機(jī)器上。- 親和性:指和誰(shuí)比較熟悉或者喜歡誰(shuí),它們倆就會(huì)靠近在一起。比如:小明和小紅,小明喜歡小紅,而開始它們被分配到了不同班級(jí),這時(shí)候由于喜歡(親和性)小紅,小明就要求老師給他轉(zhuǎn)到和小紅一個(gè)班去。
-
然后,我們
docker run master
、docker run pickup
、docker run qmgr
啟動(dòng)這三個(gè)容器。 -
這三個(gè)容器進(jìn)入 Swarm 的調(diào)度隊(duì)列,然后,
master
和pickup
容器都先后被調(diào)度到 node-2 上(這種情況是完全有可能的)。當(dāng) qmgr 容器被開始調(diào)度時(shí),Swarm 都懵逼了:node-2 上本來(lái) 2.5 GB 的可用內(nèi)存,運(yùn)行了master
和pickup
容器現(xiàn)在就剩下 0.5 GB 了,不足以運(yùn)行qmgr
容器,可是,根據(jù)affinity=master
的約束,qmgr
容器又只能運(yùn)行在 node-2 上。
這就是成組調(diào)度沒有被處理成功的例子。而 Kubernetes 就把這個(gè)問(wèn)題完美解決了:因?yàn)?Pod 是 Kubernetes 中最小的調(diào)度單元,這就說(shuō)明 Kubernetes 是按照 Pod 而不是容器資源需求來(lái)調(diào)度計(jì)算的。
所以,像上面的 master
、pickup
、 qmgr
這三個(gè)容器。在 Kubernetes 中,我們會(huì)將他們組成一個(gè) Pod。這個(gè) Pod 要求的內(nèi)存資源是 3 GB,在調(diào)度的時(shí)候 Kubernetes 就直接會(huì)將它調(diào)度到 node-1 節(jié)點(diǎn)(3 GB)上,而不會(huì)考慮 node-2 節(jié)點(diǎn)(2.5GB)上。
這樣它們之間就能進(jìn)行文件交換、使用 localhost 或者 Socket 文件進(jìn)行本地通信、會(huì)發(fā)生非常頻繁的遠(yuǎn)程調(diào)用、需要共享某些 Linux Namespace(比如,一個(gè)容器要加入另一個(gè)容器的 Network Namespace)等等。像這樣容器間的緊密協(xié)作,我們可以稱為 “超親密關(guān)系”。
也意味著,不是所有容器都應(yīng)該屬于一個(gè) Pod。比如:Wordpres 系統(tǒng),一個(gè) Web 前端和 Mysql 后端,它們之間有訪問(wèn)關(guān)系,但是沒有必要做成一個(gè) Pod ,適合做兩個(gè) Pod。
三、容器設(shè)計(jì)模式
如果只是處理 “超親密關(guān)系” 調(diào)度問(wèn)題,那么就可以不使用 Pod ???為什么 Kubernetes 中最小的單元還是 Pod 呢?
那就是 Pod 還有一個(gè)更重要的意義:容器設(shè)計(jì)模式。
為了理解這一層含義,我就必須先給你介紹一下 Pod 的實(shí)現(xiàn)原理。
Pod 實(shí)現(xiàn)原理
Pod 是一個(gè)邏輯概念,我們看不見摸不著。Kubernetes 真是處理的,還是宿主機(jī)中的 Namespace 和 Cgroups,所以隔離環(huán)境不是什么 Pod。
Pod 又是怎么定義和創(chuàng)建的呢?:
-
Pod 其實(shí)是一組共享了網(wǎng)絡(luò)(Network Namespace)和卷(Volume)的容器組成的。
- 這樣的話就是,包含有 A、B 兩個(gè)容器的 Pod,就等于一個(gè)容器(A)共享另一個(gè)容器(B)的網(wǎng)絡(luò)和卷的操作。
$ docker run --net=B --volumes-from=B --name=A image-A
這樣的話,容器 A 就依賴于容器 B,所以對(duì)應(yīng)在 Pod 中它們的關(guān)系就是拓?fù)潢P(guān)系,而不是對(duì)等關(guān)系了。
為了打破這種, 容器 A 依賴于容器 B 的拓?fù)潢P(guān)系,Pod 中最開始就創(chuàng)建了一個(gè)中間容器,叫 Infra 容器
。這個(gè) Infra 容器,在 Pod 生命周期中是第一個(gè)創(chuàng)建的容器,這樣像 A 和 B 或者其它容器只需要加入這個(gè) Infra 容器
提供網(wǎng)絡(luò)(Network Namespace)和卷,就可以與之關(guān)聯(lián)起來(lái)了,也就組成了我們的 Pod,所以 Pod 中的容器使用的是同一個(gè) Linxu Namespace
。如下圖所示:
-
Infra 容器一定要占用極少的資源,所以它使用的是一個(gè)非常特殊的鏡像,k8s.gcr.io/pause。這個(gè)鏡像是一個(gè)用匯編語(yǔ)言編寫的、永遠(yuǎn)處于 “暫?!?狀態(tài)的容器,解壓后的大小也只有 100~200 KB 左右。
共享網(wǎng)絡(luò)
由于,Pod 中的容器 A 和容器 B 是加入的在 Infra 容器中的,所以:
- 他們之間可以直接使用 localhost 進(jìn)行通信;
- 一個(gè) Pod 只有一個(gè) IP 地址,也就是這個(gè) Pod 的 Network Namespace 對(duì)應(yīng)的 IP 地址,所以 Pod IP 和 容器 IP 是一樣的。
- 當(dāng)然,其他的所有網(wǎng)絡(luò)資源,都是一個(gè) Pod 一份,并且被該 Pod 中的所有容器共享;
- Pod 的生命周期只跟 Infra 容器一致,而與容器 A 和 B 無(wú)關(guān)。
而對(duì)于同一個(gè) Pod 里面的所有用戶容器來(lái)說(shuō),它們的進(jìn)出流量,也可以認(rèn)為都是通過(guò) Infra 容器完成的。如果你要為 Kubernetes 開發(fā)一個(gè)網(wǎng)絡(luò)插件時(shí),應(yīng)該重點(diǎn)考慮的是如何配置這個(gè) Pod 的 Network Namespace,而不是每一個(gè)用戶容器如何使用你的網(wǎng)絡(luò)配置,這是沒有意義的。
所以 Pod IP 和 容器 IP 是一樣的,驗(yàn)證過(guò)程:
- 1.首先創(chuàng)建一個(gè) Pod,當(dāng)中包含一個(gè) busybox 和一個(gè) centos 容器
# 以 yaml 格式打印輸出出來(lái),一般用于生成模板
[root@master01 ~]# kubectl run qyl-centos --image=centos -oyaml --dry-run
W0530 18:08:54.937948 30966 helpers.go:663] --dry-run is deprecated and can be replaced with --dry-run=client.
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: qyl-centos
name: qyl-centos
spec:
containers:
- image: centos
name: qyl-centos
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
[root@master01 ~]# cat busybox-pod.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: centos-busybox
name: centos-busybox
spec:
containers:
- image: busybox
name: busybox
imagePullPolicy: IfNotPresent
command: [ "/bin/sh", "-c", "sleep 3600" ]
- image: centos
name: qyl-centos-buxybox
imagePullPolicy: IfNotPresent
command: [ "/bin/bash", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
[root@master01 ~]# kubectl apply -f busybox-pod.yaml
pod/qyl-centos created
- 2.查看 Pod 和里面容器的 IP 地址一致。
kubectl get pod -o wide | grep centos-busybox
kubectl exec -it pod/centos-busybox -c busybox -- ip a
kubectl exec -it pod/centos-busybox -c qyl-centos-buxybox -- ip a
共享卷
Kubernetes 項(xiàng)目只要把所有 Volume 的定義都在 Pod 層級(jí)即可(和 Pod 是兄弟)。一個(gè) Volume 對(duì)應(yīng)的宿主機(jī)目錄對(duì)于 Pod 來(lái)說(shuō)就只有一個(gè),Pod 里的容器只要聲明掛載這個(gè) Volume,就一定可以共享這個(gè) Volume 對(duì)應(yīng)的宿主機(jī)目錄。
比如下面這個(gè)例子:
- debian-container 和 nginx-container 都聲明掛載了 shared-data 這個(gè) Volume。而 shared-data 是 hostPath 類型。所以,它對(duì)應(yīng)在宿主機(jī)上的目錄就是:/data。而這個(gè)目錄,其實(shí)就被同時(shí)綁定掛載進(jìn)了上述兩個(gè)容器當(dāng)中。
- 這也是為什么,nginx-container 可以從它的 /usr/share/nginx/html 目錄中,讀取到 debian-container 生成的 index.html 文件的原因。
cat > nginx.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: two-containers
spec:
volumes:
- name: shared-data
hostPath:
path: /data
containers:
- name: nginx-container
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: centos-container
image: couchbase/centos7-systemd
imagePullPolicy: IfNotPresent
volumeMounts:
- name: shared-data
mountPath: /pod-data
command: ["/bin/sh"]
args: ["-c", echo "Hello this is centos container" > /pod-data/index.html;sleep 3600]
EOF
[root@master01 ~]# kubectl get -f nginx.yaml -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
two-containers 2/2 Running 0 10s 10.244.241.72 master01 <none> <none>
[root@master01 ~]# curl 10.244.241.72
Hello this is centos container
容器設(shè)計(jì)模式
Pod 這種 “超親密關(guān)系” 思想,希望,當(dāng)用戶想在一個(gè)容器里跑多個(gè)功能并不相關(guān)的應(yīng)用時(shí),應(yīng)該優(yōu)先考慮它們是不是更應(yīng)該部署在一個(gè) Pod 中。
為了能夠掌握這種思考方式,你就應(yīng)該盡量嘗試使用它來(lái)描述一些用單個(gè)容器難以解決的問(wèn)題。
WAR 包與 Web 服務(wù)器
現(xiàn)在有一個(gè) Java Web 應(yīng)用 WAR 包,這個(gè) WAR 一般是放在 Tomcat 的 webapps Web解析目錄下,使其運(yùn)行起來(lái)。
使用 Docker 有兩種方式實(shí)現(xiàn)這個(gè)關(guān)系。
- 把 WAR 包直接放在 Tomcat 鏡像的 webapps 目錄下,做成一個(gè)鏡像運(yùn)行起來(lái)。但是,如果你要更新 WAR 包的內(nèi)容,或者要升級(jí) Tomcat 鏡像,就要重新制作一個(gè)新的發(fā)布鏡像,非常麻煩。
- 你壓根兒不管 WAR 包,永遠(yuǎn)只發(fā)布一個(gè) Tomcat 容器。不過(guò),這個(gè)容器的 webapps 目錄,就必須聲明一個(gè) Volume,不管是什么類型(分布式、本地存儲(chǔ)都可以),只要將 Tomcat 容器的 webapps 目錄掛載出去,之后只需要在外對(duì)這個(gè) WAR 進(jìn)行更新操作(就像上面的 Nginx 例子一樣)而無(wú)需重新更新鏡像那么麻煩。
注意:這里使用了 initContainers ,它是為了完成一些初始化工作(完成就退出,不完成就不會(huì)退出),比如這里是將 sample.war 拷貝在 Pod 卷里的 /app 目錄下,這樣 tomcat 只要使用這個(gè)共享卷就能看見這個(gè) sample.war 包,并使用。
apiVersion: v1
kind: Pod
metadata:
name: javaweb-2
spec:
initContainers:
- image: geektime/sample:v2
name: war
command: ["cp", "/sample.war", "/app"]
volumeMounts:
- mountPath: /app
name: app-volume
containers:
- image: geektime/tomcat:7.0
name: tomcat
command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
volumeMounts:
- mountPath: /root/apache-tomcat-7.0.42-v2/webapps
name: app-volume
ports:
- containerPort: 8080
hostPort: 8001
volumes:
- name: app-volume
emptyDir: {}
這樣,我們就用這種 “組合” 方式,解決了 WAR 包與 Tomcat 容器之間耦合關(guān)系的問(wèn)題。
這種 “組合” 操作,是容器設(shè)計(jì)模式最常用的一種模式,叫做:sidecar
。
sidecar(邊車) 模式:我們可以在一個(gè) Pod 中,啟動(dòng)一個(gè)輔助容器,來(lái)完成一些獨(dú)立于主進(jìn)程(主容器)之外的工作。比如,這里的 initContainers 容器(不僅僅是使用 initContainers 也是可以是 containers 類型,如上面的 Nginx 例子 )。
容器的日志收集
現(xiàn)在有一個(gè) Web 容器應(yīng)用,需要不斷地把日志文件輸出到它的 /var/log 目錄中。
- 這時(shí),我們就可以將 Pod 聲明的 Volume 掛載到該容器的 /var/log 目錄上。
- 同時(shí)啟動(dòng)一個(gè) sidecar 容器,因?yàn)楣蚕砭淼木壒?,只要我掛載后,就能看到 Web 容器應(yīng)用日志在 /var/log 目錄上生成的日志。
- 接下來(lái) sidecar 容器,將 /var/log 日志信息,轉(zhuǎn)發(fā)到 Elasticsearch 或者數(shù)據(jù)庫(kù)中存儲(chǔ)起來(lái),這樣就完成了日志收集工作。
Pod 的另一個(gè)重要特性是,它的所有容器都共享同一個(gè) Network Namespace。這就使得很多與 Pod 網(wǎng)絡(luò)相關(guān)的配置和管理,也都可以交給 sidecar 完成,而完全無(wú)須干涉用戶容器。這里最典型的例子莫過(guò)于 Istio 這個(gè)微服務(wù)治理項(xiàng)目了。
容器設(shè)計(jì)模式 小論文
總結(jié)
重點(diǎn)說(shuō)明了,Pod 的工作原理。
我們從最開始進(jìn)程組來(lái)展開了 Pod 的好處;
接著闡述了 Pod 的工作原理Pod 其實(shí)就是共享了網(wǎng)絡(luò)和卷一組容器;
最后闡述了容器設(shè)計(jì)模式的玩法,以及它的重要性。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-485688.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-485688.html
到了這里,關(guān)于【探索 Kubernetes|作業(yè)管理篇 系列 7】探究 Pod 有什么用,為什么需要它的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!