Kubernetes 之 Pod (上)

一 概念

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章