深入淺出 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 上獲取,鏈接如下:

Kubernetes 之 Pod