深入淺出 Kubernetes:初識 Pod(上)
- 2019 年 10 月 4 日
- 筆記
版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/solaraceboy/article/details/97923925
文章目錄
深入淺出 Kubernetes:初識 Pod(上)
一 概念
Pod 的中文意為: 豆莢,從字面意思不難理解,它就像一個豆莢,裡面包含許多豆子,這些豆子就可以類比為 container 。實際上,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 上獲取,鏈接如下: