1. 程式人生 > 程式設計 >Kubernetes 入門:深入瞭解 Pod

Kubernetes 入門:深入瞭解 Pod

《Kubernetes 入門:深入瞭解 Pod 》最早釋出在 blog.hdls.me/15346044250…

Pod 作為 k8s 的基本排程單元,是 k8s 的核心資源所在。本文從 Pod 的使用、控制、排程、應用配置等方面入手,全方面講解 k8s 如何釋出和管理應用。

Pod 基本用法

對長時間執行容器的要求是:其主程式需要一直在前臺執行。kubelet 建立包含這個容器的 Pod 之後執行完命令,即認為 Pod 執行結束,接著立即銷燬該 Pod ,根據 RS 中定義的 Pod 副本數量,會立即再生成一個新 Pod ,會進入無限迴圈。

屬於一個 Pod 的多個容器應用之間僅需通過 localhost 通訊,一組容器被繫結在了一個環境中。

在同一個 Pod 中的容器共享 Pod 級別的 Volume,而每個容器即可各自進行掛載,將 Volume 掛載為容器內部需要的目錄。

靜態 Pod

靜態 pod 是指由 kubelet 管理的僅存在特定 Node 上的 Pod。它們不能通過 APIServer 管理,無法與 RS 等進行關聯。

建立靜態 Pod 的方式:

靜態 pod 的建立方式有兩種,分別為配置檔案方式和 HTTP 方式。

配置檔案方式

設定 kubelet 的啟動引數 --config,指定 kubelet 需要監控的配置檔案所在目錄,kubelet 定期掃描該目錄,根據目錄中的 .yaml 或 .json 檔案建立操作。由於無法通過 APIServer 對靜態 pod 進行直接管理,在 Master 節點上嘗試刪除這個 Pod 將會將其變成 pending 狀態,不會刪除;若需要刪除該 pod 需要在其所在 Node 上,將其定義檔案從 /etc/kubelet.d 目錄下刪除。

HTTP 方式

設定 kubelet 的啟動引數 --manifest-url ,kubelet 定期從該 URL 地址下載 Pod 的定義檔案,並以 .yaml 或 .json 檔案的格式解析,然後建立 Pod。實現方式與配置檔案方式一致。

Pod 配置管理 —— ConfigMap

應用部署的一個最佳實踐是將應用所需的配置資訊與程式分離,好處是可以實現應用程式被更好的服用,通過不同的配置也能實現更靈活的功能。ConfigMap 是 k8s 統一的叢集配置管理方案。

用法

生成為容器的環境變數,設定容器啟動命令的啟動引數,以 Volume 形式掛載為容器內部的檔案或目錄,以 key:value 的形式儲存,既可以表示變數的值,也可以表示一個完整配置檔案的內容。 blog.cdn.updev.cn

ConfigMap 的建立

通過 yaml 檔案的方式:書寫好 yaml 檔案後, kubectl create -f ***.yaml 命令即可建立 ConfigMap。

直接使用 kubectl create configmap 命令列的方式:可以根據目錄、檔案或字面值建立 ConfigMap。

  1. 可以通過 --from-file 引數從目錄中建立
kubectl create configmap <map-name> --from-file=config-files-dir
複製程式碼

其中, <map-name> 代表 ConfigMap 的名字,config-files-dir 代表目錄。創建出來的 ConfigMap 的 key 即為檔名。

  1. 可以通過 --from-file 引數從檔案中建立,並自定義 key
kubectl create configmap <map-name> --from-file=<my-key-name>=<path-to-file>
複製程式碼

其中, my-key-name 為自定義 key,path-to-file 代表檔案。

  1. 可以通過 --from-literal 引數從檔案中建立,並指定字面值
kubectl create configmap <map-name> --from-literal=<key>=<value>
複製程式碼

其中, <key>=<value> 代表指定的鍵值對。

ConfigMap 的使用方式

下面就是容器中的應用如何使用 ConfigMap 的方法,主要有環境變數方式和掛載 Volume 方式。

環境變數方式

在 Deployment 的 yaml 的 container 中定義 env ,格式如下:

env:
- name: HDLS_KEY
  valueFrom:
    configMapKeyRef:
      name: special-config
      key: hdls
複製程式碼

意為:該容器中環境變數 HDLS_KEY 的值取自名為 special-config 的 ConfigMap 中,key 為 hdls

volumeMount 模式

需要在 Pod 的 yaml 的 container 中定義 volumeMounts (引用 volume 名和掛載到容器內的目錄),且在 volumes 中定義需要掛載的 volume 名和 ConfigMap 等資訊。如下:

apiVersion: v1
kind: Pod
metadata:
  name: hdls-pod
spec:
  containers:
  - name: hdls-container
    image: ...
    ports:
      - containerPort: 8080
    volumeMounts:   # 在 container 中定義 volumeMounts
    - name: hdls-server   # 引用的 volume 名
      mountPath: /configfiles   # 掛載到容器中的目錄
  volumes:
  - name: hdls-server   # pod 中掛載的 Volume 名
    configMap:
      name: special-config   # 使用 ConfigMap “special-config”
  ...
複製程式碼

ConfigMap 的限制條件

  1. 必須在 Pod 之前建立
  2. 只有處於相同 namespace 的 Pod 可以引用
  3. 沒有配額管理
  4. 靜態 Pod 無法使用 ConfigMap
  5. 在 Pod 對 ConfigMap 進行掛載時,容器內部只能掛載為目錄,不能是檔案

Pod 生命週期和重啟策略

我們在排程、管理 Pod 時,需要熟悉 Pod 在整個生命週期的各個狀態,而設定 Pod 的重啟策略也是基於對 Pod 的各種狀態的瞭解。

Pod 的狀態

Pod 的所有狀態總共有 5 種,分別如下:

Pending : APIServer 已經建立該 Pod ,但 Pod 內還有容器的映象沒有建立或正在下載; Running : Pod 中所有的容器均已建立,且至少有一個容器處於執行、正在啟動、正在重啟狀態; Succeeded : Pod 中所有容器已成功退出,且不會重啟; Failed : Pod 中所求容器均已退出,但至少有一個容器處於失敗狀態; Unknown : 由於某種原因無法獲取該 Pod 的狀態,可能由於網路不暢所致。

Pod 的重啟策略

Pod 的重啟策略有 3 種,預設值為 Always。

Always : 容器失效時,kubelet 自動重啟該容器; OnFailure : 容器終止執行且退出碼不為0時重啟; Never : 不論狀態為何, kubelet 都不重啟該容器。

kubelet 重啟失效容器的時間間隔以 sync-frequency 乘以 2n 來計算,最長延遲 5 分鐘,並在成功重啟後的 10 分鐘重置該時間。

每種控制器對 Pod 的重啟策略

Pod 的重啟策略與控制方式有關,每種控制器對 Pod 的重啟策略要求如下:

RS 和 DaemonSet:必須設定為 Always Job:OnFailure 或 Never kubelet (靜態 Pod):Pod 失效時自動重啟,且不進行健康檢查

健康檢查

Pod 的健康檢查分別兩種:存活檢查和就緒檢查,分別使用 LivenessProbe 探針和 ReadinessProbe 探針。

LivenessProbe (存活檢查)

用於判斷容器是否存活,一旦檢測到容器不健康, kubelet 即殺掉該容器,並根據重啟策略做相應處理,如果容器不包含 LivenessProbe 探針,kubelet 認為其返回值永遠是 success。

ReadinessProbe (就緒檢查)

用於判斷容器是否啟動完成,即是否 ready 狀態,一旦檢測到失敗,則 Pod 的狀態被改寫,並將該 Pod 的 Endpoint 從 Service 的轉發 Endpoint 中刪除。

探針設定方式

ExecAction :在容器內執行一個命令,如果該命令的返回碼為0,表明容器健康; TCPSocketAction :通過容器的 IP 和埠號執行 TCP 檢查,如果能建立 TCP 連線,表明容器健康; HTTPGetAction :通過容器的 IP 地址、埠號及路徑呼叫 HTTP Get 方法,如果返回碼 >=200 ,且 <400,認為容器健康。

以上每種探測方式都需要設定的引數: initialDelaySeconds:延遲檢查的時間,單位為s timeoutSeconds:健康檢查傳送後等待響應的超時時間,單位為s periodSeconds:執行週期

Pod 排程

Pod 實為 k8s 中的最小排程單元,只是容器的載體,其本身無法完成自動排程的功能。 k8s 採用了 RS、Deployment、DaemonSet、Job 等方式實現 Pod 的排程和自動控制。

RS、Deployment 全自動排程

RS 的主要功能之一就是自動部署一個容器應用的多份副本,及持續監控副本的數量。而 RS/RC 在 k8s 中一般很少單獨使用,都是在 Deployment 中使用,而 Deployment 是 k8s 引入的一個更好解決 Pod 編排問題的概念,通過 Deployment 我們可以隨時知道 Pod 的排程情況。

在 Pod 的定義中,可以採用 NodeSelector 或 NodeAffinity 兩種方式進行排程。

NodeSelector 定向排程

Pod 排程是通過 Master 上的 Scheduler 負責實現的,原理是通過 Node 標籤和 Pod 的 nodeSelector 屬性匹配。

NodeSelector 定向排程的過程為:通過 kubectl label 給目標 Node 打上標籤;在 Pod 的定義上加上 nodeSelector 的設定。需要注意的是,一旦 Pod 指定了 nodeSelector ,若叢集中不存在匹配的 Node ,即使有空閒的 Node,也不會排程。

通過 kubectl 進行打標籤的方法:

kubectl label nodes <node-name> <label-key>=<label_value>
複製程式碼

在 Pod 中指定 nodeSelector:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hdls
spec:
  template:
    metadata:
      name: hdls-pod
    spec:
      containers:
      - name: hdls-container
        image: ...
        ports:
        - containerPort: 8080
      nodeSelector:
        <label-key>: <label_value>
複製程式碼

NodeAffinity 親和性排程

NodeAffinity 意為 Node 親和性的排程策略,是替換 NodeSelector 的下一代排程策略。在 NodeSelector 的基礎上增加了 In/NotIn/Exists/DoesNotExsist/Gt/Lt 等操作。

設定親和性: requiredDuringSchedulingRequiredDuringExecution:類似於 NodeSelector ,在 Node 不滿足條件時,系統從該 Node 上移除之前排程上的 Pod ; requiredDuringSchedulingIgnoredDuringExecution:在 Node 不滿足條件時,系統不一定從該 Node 上移除之前排程上的 Pod; preferredDuringSchedulingIgnoredDuringExecution:指定在滿足條件的 Node 中,哪些 Node 更優先地排程;同時,Node 不滿足條件時,不一定從該 Node 上移除之前排程上的 Pod。

DaemonSet 特定場景排程

DaemonSet 是 Kubernetes 1.2 版本中新增的一種資源物件,用於確保全部(或指定的某些)Node 上執行一個 Pod 副本。其 Pod 排程策略與 RC 類似。

使用場景:

  1. 在每個 Node 上執行一個 GlusterFS 儲存或者 Ceph 儲存的 daemon 程式
  2. 在每個 Node 上執行一個日誌採集程式,如 fluentd 、logstach
  3. 在每個 Node 上執行一個健康程式,採集該 Node 的執行效能資料

Job 批處理排程

Job 是 Kubernetes 1.2 版本中新增的支援批處理的資源物件。批處理任務通常並行或序列啟動多個計算程式去處理一批工作項(work item),處理完後整個 Job 結束。

Job 的模式:

  1. Job Template Expansion 模式:一個 Job 對應一個 work item 。通常適合 work item 較少、每個 work item 要處理的資料量較大的場景;
  2. Queue with Pod Per Work Item 模式:採用一個任務佇列存放 work item,Job 物件去消費這些 work item 。這種模式是一個 Pod 對應一個 work item,一個 Job 啟動多個 Pod;
  3. Queue with Variable Pod Count 模式:與上面一種模式相同,唯一不同的是 Job 啟動的 Pod 數量時可變的;
  4. Single Job with Static Work Assignment 模式:也是一個 Job 產生多個 Pod 的模式,但採用的是程式靜態方式分配任務,而不是佇列模式。

Job 的型別

考慮到批處理的並行問題,Job 被分為以下幾種型別:

  1. Non-parallel Jobs :一個 Job 啟動一個 Pod;
  2. Parallel Jobs with a fixed completion count :並行 Job 啟動多個 Pod。需要設定 Job 的 .spec.completions 引數為一個正數,此為正常結束的 Pod 的上限值;.spec.parallelism 引數為並行數,即同時處理 work item 的 Pod 數;
  3. Parallel Jobs with a work queue :並行 Job 有個獨立的 queue 來存放 work item ,此時不能設定 .spec.completions 引數。

Pod 擴容和縮容

在實際生產系統中,服務擴容是個不容忽視的場景。在 k8s 中,有兩種方式來實現 Pod 的擴容和縮容,分別為 RC 的 Scale 機制和 HPA (Horizontal Pod Autoscaler)。

RC 的 Scale 機制

通過 kebectl 命令可設定 Pod 的副本數:

kubectl scale rc <rc-name> --replicas=3
複製程式碼

通過 --replicas=<num> 引數將 Pod 的副本數手動調高,即可完成 Pod 的擴容;相應的,將該引數設定為較低的數,系統將 kill 掉一些執行中的 Pod ,以實現應用叢集縮容。

HPA

HPA (Horizontal Pod Autoscaler) 是 Kubernetes v1.1 新增的控制器,用以實現基於 CPU 使用率進行自動 Pod 擴縮容的功能。HPA 基於 Master 的 kube-controller-manager 服務啟動引數 --horizontal-pod-autoscaler-sync-period 定義的時長(預設為 30 秒),週期性的檢測目標 Pod 的 CPU 使用率,並在滿足條件時對 RC 或 Deployment 中的 Pod 副本數進行調整,以符合使用者定義的平均 Pod CPU 使用率。PodCPU 使用率來源於 heapster 元件,所以需要預先安裝好 heapster。

建立 HPA 時可以使用 kubectlautoscale 命令或使用 yaml 配置檔案。在建立 HPA 之前,需要確保已經存在一個 RC 或 Deployment 物件,且該 RC 或 Deployment 中的 Pod 必須定義 resources.requests.cpu 的資源請求值。

滾動升級

在實際生產環境中,應用的升級也是一個很重要的場景。在叢集規模較大時,先全部停止再逐步升級的方式會導致較長時間內服務不可用,升級工作就成了一個不小的挑戰。 k8s 提供了滾動升級功能來解決這個問題。

滾動升級通過執行 kubectl rolling-update 命令一鍵完成。整個過程為:

  1. 建立一個新的 RC;
  2. 自動控制舊的 RC 中的 Pod 副本的數量逐漸減少到 0;
  3. 同時新 RC 中的 Pod 副本數從 0 逐步增加到到目標值,舊的 Pod 每減少 1,新的 Pod 就增加 1。

需要注意的是,新舊 RC 必須在同一 namespace 下。

採用 yaml 配置檔案

若採用 yaml 配置檔案來實現滾動升級,需要先手動建立一個新的 RC yaml,且 yaml 檔案中需要注意的是:

  1. RC 的名字不可與舊 RC 名字相同;
  2. 在 selector 在應至少有一個 Label 與舊的 RC 的 Label 不同,以標識為新的 RC ;

再執行 kubectl 命令完成滾動升級:

kubectl rolling-update <RC-name> -f <new-RC-yaml>
複製程式碼

不使用 yaml 配置檔案

若不使用 yaml 配置檔案,可直接用 kubectl rolling-update 命令,加上 --image 引數指定新版映象名。

kubectl rolling-update <RC-name> --image=<image-name>
複製程式碼

與使用配置檔案的方式不同,該方法執行的結果是舊的 RC 被刪除,新的 RC 仍使用舊的 RC 名,且完成升級後,新 RC 多一個 key 為 “deployment”(這個名字可通過 --deployment-label-key 引數進行修改) 的 Label ,值為 RC 的內容進行 Hash 計算後的值。

最後,若 Pod 需要回滾,可中斷更新操作,執行 kubectl rolling-update-rollback 完成 Pod 版本的回滾。