一 概念
Pod 是一個邏輯概念,Kubernetes 真正處理的,還是宿主機操作系統上 Linux 容器的 Namespace 和 Cgroups,而並不存在一個所謂的 Pod 的邊界或者隔離環境。 Pod 是一組共享了某些資源的容器,Pod裏的所有容器,共享的是同一個 Network Namespace,並且可以聲明共享同一個 Volume 。在 Kubernetes 項目裏,Pod 的實現需要使用一箇中間容器,這個容器叫做Infra容器(Infra容器(k8s.gcr.io/pause)佔用極少的資源,它的鏡像時用彙編語言編寫的,永遠處於“暫停”狀態的容器)。 在Pod中,Infra 容器永遠都是第一個被創建的容器,而其他用戶定義的容器,則通過 join Network Namespace的方式,與Infra容器關聯在一起,對於同一個Pod裏面的所有用戶容器,它們的進出流量都是通過Infra容器完成的。同一個 Pod 裏面的所有用戶容器來說,它們的進出流量,也可以認爲都是通過 Infra 容器完成的。凡是調度、網絡、存儲,以及安全相關的屬性,基本上是 Pod 級別的。
二 Pod 中幾個重要字段的含義和用法
NodeSelector:是一個供用戶將 Pod 與 Node 進行綁定的字段,用法如下所示:
apiVersion: v1
kind: Pod
metadata:
name: gysl-nodeselect
spec:
nodeSelector:
kubernetes.io/hostname: 172.31.2.12
containers:
- name: gysl-nginx
image: nginx
這就意味着這個 Pod 只能在攜帶 kubernetes.io/hostname 標籤的 Node 上運行了,否則,調度失敗。
NodeName:一旦 Pod 的這個字段被賦值,Kubernetes 項目就會被認爲這個 Pod 已經經過了調度,調度的結果就是賦值的節點名字。所以,這個字段一般由調度器負責設置,但用戶也可以設置它來“騙過”調度器,當然這個做法一般是在測試或者調試的時候纔會用到。
apiVersion: v1
kind: Pod
metadata:
name: gysl-nodename
spec:
nodeName: 172.31.2.12
containers:
- name: gysl-nginx
image: nginx
HostAliases:定義了 Pod 的 hosts 文件(比如 /etc/hosts)裏的內容。
apiVersion: v1
kind: Pod
metadata:
name: gysl-hostaliases
spec:
hostAliases:
- ip: "10.0.0.20"
hostnames:
- "test.gysl"
- "app.gysl"
containers:
- name: gysl-nginx
image: nginx
最下面兩行記錄,就是我通過 HostAliases 字段爲 Pod 設置的。需要指出的是,在 Kubernetes 項目中,如果要設置 hosts 文件裏的內容,一定要通過這種方法。否則,如果直接修改了 hosts 文件的話,在 Pod 被刪除重建之後,kubelet 會自動覆蓋掉被修改的內容。
凡是跟容器的 Linux Namespace 相關的屬性,也一定是 Pod 級別的。這個原因也很容易理解:Pod 的設計,就是要讓它裏面的容器儘可能多地共享 Linux Namespace,僅保留必要的隔離和限制能力。
繼續看以下例子:
apiVersion: v1
kind: Pod
metadata:
name: gysl-shareprocessnamespace
spec:
shareProcessNamespace: true
containers:
- name: nginx
image: nginx
- name: busybox
image: busybox
tty: true
stdin: true
使用以下命令進入指定的 container :
kubectl attach -it gysl-shareprocessnamespace -c busybox
進入之後查看一下進程共享情況:
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /pause
6 root 0:00 nginx: master process nginx -g daemon off;
11 101 0:00 nginx: worker process
12 root 0:00 sh
32 root 0:00 ps aux
在這個容器裏,我們不僅可以看到它本身的 ps aux 指令,還可以看到 nginx 容器的進程,以及 Infra 容器的 /pause 進程。這就意味着,整個 Pod 裏的每個容器的進程,對於所有容器來說都是可見的:它們共享了同一個 PID Namespace。凡是 Pod 中的容器要共享宿主機的 Namespace,也一定是 Pod 級別的定義。
再看一個例子:
apiVersion: v1
kind: Pod
metadata:
name: gysl-share-namespace
spec:
hostPID: true
hostIPC: true
hostNetwork: true
nodeName: 172.31.2.11
shareProcessNamespace: true
containers:
- name: nginx-gysl
image: nginx
imagePullPolicy: IfNotPresent
- name: busybox-gysl
image: busybox
stdin: true
tty: true
imagePullPolicy: Always
lifecycle:
postStart:
exec:
command: ['/bin/sh','-c','echo "This is a test of gysl. ">/gysl.txt']
preStop:
exec:
command: ['/bin/sh','-c','echo "This is a demo of gysl."']
上面的例子中,定義了共享宿主機的 Network、IPC 和 PID Namespace。這就意味着,這個 Pod 裏的所有容器,會直接使用宿主機的網絡、直接與宿主機進行 IPC 通信、看到宿主機里正在運行的所有進程。
除此之外,ImagePullPolicy 和 Lifecycle 也是值得我們關注的兩個字段。
ImagePullPolicy 字段定義了鏡像拉取的策略。而它之所以是一個 Container 級別的屬性,是因爲容器鏡像本來就是 Container 定義中的一部分。ImagePullPolicy 的值默認是 Always,即每次創建 Pod 都重新拉取一次鏡像。如果它的值被定義爲 Never 或者 IfNotPresent,則意味着 Pod 永遠不會主動拉取這個鏡像,或者只在宿主機上不存在這個鏡像時才拉取。
Lifecycle 字段。它定義的是 Container Lifecycle Hooks。顧名思義,Container Lifecycle Hooks 的作用,是在容器狀態發生變化時觸發一系列“鉤子”。在這個字段中,我們看到了 postStart 和 preStop 兩個參數。postStart 參數在容器啓動後,立刻執行一個指定的操作。需要明確的是,postStart 定義的操作,雖然是在 Docker 容器 ENTRYPOINT 執行之後,但它並不嚴格保證順序。也就是說,在 postStart 啓動時,ENTRYPOINT 有可能還沒有結束。如果 postStart 執行超時或者錯誤,Kubernetes 會在該 Pod 的 Events 中報出該容器啓動失敗的錯誤信息,導致 Pod 也處於失敗的狀態。preStop 發生的時機,則是容器被殺死之前(比如,收到了 SIGKILL 信號)。而需要明確的是,preStop 操作的執行,是同步的。所以,它會阻塞當前的容器殺死流程,直到這個 Hook 定義操作完成之後,才允許容器被殺死,這跟 postStart 不一樣。
三 相關資源
文中涉及到的資源可以從本人 GitHub 上獲取,鏈接如下: