1. 程式人生 > >Kubernetes系列04:深入掌握Pod

Kubernetes系列04:深入掌握Pod

本節將對kubernetes如何釋出和管理應用進行說明和示例,主要包括Pod和容器的使用、Pod的控制和排程、應用配置管理等內容。

1.Pod定義詳解
yaml格式的Pod定義檔案的完整內容:
apiVersion: v1
kind: Pod
metadata:
  name: string
  namespace: string
  labels:
    - name: string
  annotations:
    - name: string
spec:
  containers:
  - name: string
    image: string
    imagePullPolicy: [Always | Never | IfNotPresent]
    command: [string]
    args: [string]
    workingDir: string
    volumeMounts:
    - name: string
      mountPath: string
      readOnly: boolean
    ports:
    - name: string
      containerPort: int
      hostPort: ing
      protocol: string
    env:
    - name: string
      value: string
    resources:
      limits:
        cpu: string
        memory: string
      requests:
        cpu: string
        memory: string
    livenessProbe:
      exec:
        command: [string]
      httpGet:
        path: string
        port: number
        host: string
        scheme: string
        httpHeaders:
        - name: string
          value: string
      tcpSocket:
        port: number
      initialDelaySeconds: 0
      timeoutSeconds: 0
      periodSeconds: 0
      successThreshold: 0
      failureThreshold: 0
      securityContext:
        privileged: false
    restartPolicy: [Always | Never | OnFailure]
    nodeSelector: object
    imagePullSecrets:
    - name: string
    hostNetwork: false
    volumes:
    - name: string
      emptyDir: {}
      hostPath:
        path: string
      secret:
        secretName: string
        items:
        - key: string
        path: string
      configMap:
        name: string
        items:
        - key: string
          path: string



2. Pod的基本用法
Pod可用由1個或多個容器組合而成。
例如名為frontend的Pod只由一個容器組成:
apiVersion: v1
kind: Pod
metadata:
  name: frontend
  labels:
    name: frontend
spec:
  containers:
  - name: frontend
    image: kubeguide/guestbook-php-frontend
    env:
    - name: GET_HOSTS_FROM
      value: env
    ports:
    - containerPort: 80
這個Pod啟動後,將啟動1個Docker容器

另一種場景是,當兩個容器為緊耦合關係,應將兩個容器打包為一個Pod,如下:


配置檔案frontend-localredis-pod.yaml如下:
apiVersion: v1
kind: Pod
metadata:
  name: redis-php
  labels:
    name: redis-php
spec:
  containers:
  - name: frontend
    image: kubeguide/guestbook-frontend:localredis
    ports:
    - containerPort: 80
  - name: redis
    image: kubeguide/redis-master
    ports:
    - containerPort: 6379

執行命令建立Pod:
#kubectl create -f frontend-localredis-pod.yaml
#kubectl get pods
NAME |Ready |status |Restarts |Age
redis-php |2/2 |Running |0 |10m
可以看到Ready資訊為2/2,表示Pod中有兩個容器在執行

檢視這個Pod的詳細資訊,可以看到兩個容器的定義及建立過程(Event事件資訊)
#kubectl describe pod redis-php

3.靜態Pod

靜態Pod是由kubectl進行管理的僅存於特定Node上的Pod。他們不能通過API Server驚醒管理,無法與ReplicationController、Deployment或者DaemonSet進行關聯,並且kubelet也無法對他們進行健康檢查。靜態Pod總是由kubectl進行建立,並且總是在kubelet所在的Node上執行。
建立Pod有兩種方式:配置檔案或HTTP方式,這裡只說常用的配置檔案方式
配置檔案方式
在目錄/etc/kubelet.d中放入static-web.yaml檔案,內容:
apiVersion: v1
kind: Pod
metadata:
  name: static-web
  labels:
    name: static-web
  spce:
    containers:
    - name: static-web
      image: nginx
      ports:
      - name: web
        containerPort: 80

等一會,檢視本機中已經啟動的容器:
#docker ps

就可以看到一個Nginx容器已經被Kubelet成功建立了出來。

到Master節點檢視Pod列表,可以看到這個static pod:
#kubectl get pods
由於靜態Pod無法通過API Server直接管理,所以在Master節點嘗試刪除這個Pod,將會使其標為Pending狀態,且不會被刪除。
#kubectl delete pod static-web-node1

刪除該Pod的操作只能是到其所在Node上,將其自定義檔案static-web.yaml從/etc/kubelet.d目錄下刪除
#rm /etc/kubelet.d/static-web.yaml
#docker ps
容器已經刪除了

4 Pod容器共享Volume
在同一個Pod中多個容器能夠共享Pod級別的儲存卷Volume,如圖:

在下面的例子中,Pod內包含兩個容器:tomcat和busybox,在Pod級別設定Volume“app-logs”,用於tomcat向其中寫日誌檔案,busybox讀取日誌檔案
配置檔案pod-volume-applogs.yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-pod
spec:
  containers:
  - name: tomcat
    image: tomcat
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: app-logs
      mountPath: /usr/local/tomcat/logs
  - name: busybox
    image: busybox
    command: ["sh","-c","tail -f /logs/catalina*.log"]
    volumeMounts:
    - name: app-logs
      mountPath: /logs
  volumes:
  - name: app-logs
    emptyDir: {}

這裡設定的Volume名為app-logs,型別為emptyDir,掛載到tomcat容器內/usr/local/tomcat/logs目錄同時掛載到logreader容器內的/logs目錄。

通過kubectl logs命令檢視logreader容器的輸出內容:
#kubectl logs Volume-pod -c busybox

這個檔案即為tomcat生成的日誌檔案/usr/local/tomcat/logs/catalina.<date>.log的內容,登入tomcat

容器進行檢視:
#kubectl exec -it volume-pod -c tomcat -- ls /usr/local/tomcat/logs
#lubectl exec -it volume-pod -c tomcat -- tail /usr/local/tomcat/logs/ctalima.2017-07-30.log

5. Pod的配置管理

在大規模容器叢集的環境中,對多個容器進行不同的配置將變得非常複雜,kubernetes1.2版本後提供一種同一的叢集配置管理方案--ConfigMap

1)ConfigMap:容器應用的配置管理
ConfigMap典型用法如下:
a)生成為容器內的環境變數
b)設定容器啟動命令的啟動引數(需要設定為環境變數)
c)以volume的形式掛載為容器內部的檔案或者目錄

可以通過yaml配置檔案或者直接使用kubectl create configmap命令的方式來建立ConfigMap

2)ConfigMap的建立:yaml檔案方式

檔案cm-appvars.yaml描述了將幾個應用所需的變數定義為ConfigMap的用法:
cm-appvars.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: cm-appvars
data:
  apploglevel: info
  appdatadir: /var/data

執行kubectl create建立:
#kubectl create -f cm-appvars.yaml

檢視Configmap
#kubectl get configmap
NAME |DATA |AGE
cm-appvars |2 |3s

#kubectl describe configmap cm-appvars
#kubectl get configmap cm-appvars -o yaml

3)ConfigMap的建立:kubectl命令列方式
其他方式參考
http://www.cnblogs.com/ilinuxer/p/6629228.html
http://www.cnblogs.com/breezey/p/6582082.html
http://rootsongjc.github.io/blogs/kubernetes-configmap-introduction/?utm_source=tuicool&utm_medium=referral

4)ConfigMap的建立:環境變數方式

5)ConfigMap的建立:volumeMount模式

6)使用ConfigMap的限制條件
configMap必須在Pod之前建立
ConfigMap也可以定義為屬於某個Namespace,只有處於相同Namespaces中的Pod可以引用它
ConfigMap中的配額管理還未能實現
kubectl只支援可以被API Server管理的Pod使用。
在Pod對ConfigMap進行掛載操作時,目錄中將包含ConfigMap定義的每個item,如果目錄下原先還有其他檔案,則容器內的該目錄將會被掛載的ConfigMap進行覆蓋。如果應用程式需要保留原來的其他檔案,則需要進行額外的處理。通過將ConfigMap掛載到容器內部的臨時目錄,在通過啟動指令碼將配置檔案複製或者連結(cp或link)到應用所用的實際配置目錄下。

6. Pod生命週期和重啟策略

Pod在整個生命週期過程中被系統定義為各種狀態,熟悉Pod的各種狀態對於我們理解如何設定Pod的排程策略、重啟策略是很有必要的。

Pod的重啟策略包括Always、OnFailure和Never,預設值為Always
Always:當容器失效時,由kubelet自動重啟該容器
OnFailure:當容器終止執行且退出不為0時,由kubelet自動重啟該容器
Never:無論容器執行狀態如何,kubelet都不會重啟該容器

kubelet重啟失效容器的時間間隔以sync-frequency乘以2n計算,例如1、2、4、8倍等,最長延時5分鐘,並且在成功重啟後的10分鐘後重置該時間。

Pod的重啟策略與控制方式息息相關,當前可用於管理Pod的控制器包括ReplicationController、
job、DaemonSet及直接通過kubelet管理(靜態Pod)。每種控制器對Pod的重啟策略要求如下:
RC和DaemonSet:必須設定為Always,需要保證該容器持續執行
Job:OnFailure或Never,確保容器執行完成後不再重啟
kubelet:在Pod失效時自動重啟它,無論RestartPolicy設定什麼值,並且也不會對Pod進行健康檢查

7.Pod健康檢查

對Pod的健康狀態檢查可以通過兩類探針來檢查:LivenessProbe和ReadinessProbe

LivenessProbe探針:用於判斷容器是否存活(running狀態),如果LivenessProbe探針探測到容器不健康,則kubelet將殺掉該容器,並根據容器的重啟策略做響應的處理。如果一個容器不包含LivenessProbe探針,那麼kubelet認為該容器的LivemessProbe探針返回的值永遠是“Success”

ReadinessProbe:用於判斷容器是否啟動完成(ready狀態),可以接收請求,如果ReadinessProbe探針檢測到失敗,則Pod的狀態將被修改,Endpoint Controller將從Service的Endpoint中刪除包含該容器所在Pod的Endpoint。

kubelet定期執行LivenessProbe探針來診斷容器的健康狀態。LivenessProbe有一下三種實現方式。
(1)ExecAction
(2)TCPSocketAction
(3)HTTPGetAction

8. Pod排程
在kubernetes系統中,Pod在大部分場景下都只是容器的載體而已,通常需要通過RC、Deployment、

DaemonSet、Job等物件完成Pod的排程和自動控制功能。
1)RC、Deployment:全自動排程
RC的主要功能之一就是自動部署一個容器應用的多份副本,以及繼續監控副本的數量,在叢集內始終維持使用者指定的副本數量。
a)NodeSelector:定向排程
b)NodeAffinity:親和性排程

2)DaemonSet:特定場景排程
DaemonSet是kubernetes1.2版本新增的一種資源物件,用於管理在叢集中每個Node上僅執行一份Pod的副本例項。
DaemonSet的Pod排程策略與RC類似,除了使用系統內建的演算法在每臺Node上進行排程,也可以在Pod的定義中使用NodeSelector或NodeAffinity來指定滿足條件的Node範圍進行排程。

3)Job:批處理排程
kubernetes從1.2版本開始支援批處理型別的應用,我們可以通過kubernetes Job資源物件來定義並啟動一個批處理任務。批處理任務通常並行啟動多個計算程序去處理一批工作項,處理完成後,整個批處理任務結束。
按照批處理任務實現方式的不同,分為:
Job Template Expansion模式
Queue with Pod Per Work Item模式
Queue with Variable Pod Count模式

kubernetes將Job分以下三種類型。
1)Non-parallel Jobs
2)Parallel Jobs with a fixed completion count
3)Parallel Jobs with a work queue

9. Pod的擴容和縮容
在實際生產系統中,我們經常會遇到某個服務需要擴容的場景,也可能會遇到由於資源緊張或者工作負載降低而需要減少服務例項數量的場景。此時我們可以利用RC的Scale機制來完成這些工作。以redis-slave RC為例,已定義的最初副本數量為2,通過kubectl scale命令可以將redis-slave RC控制的Pod副本數量從初始的2更新為3:
#kubectl scale rc redis-slave --replicas=3

將--replicas設定為比當前Pod副本數量更小的數字,系統將會“kill掉”一些執行中的容器,以實現應用叢集縮容:
#kubectl scale rc redis-slave --replicas=1

除了scale方式,還有一種Horizontal Pod Autoscaler(HPA)方式

10. Pod滾動升級
當叢集中的某個服務需要升級時,我們需要停止目前與該服務相關的所有Pod,然後重新拉取映象並啟動,如果叢集規模比較大,則這個工作就變成了一個挑戰,而且先全部停止然後逐步升級的方式會導致較長時間的服務不可用。

滾動升級通過執行kubectl rolling-updata命令一鍵完成,該命令建立一個新的RC,然後自動控制就得RC中的Pod副本的數量逐漸減少到0,同時新的RC中的Pod副本的數量從0逐步增加到目標值,最終實現了Pod的升級。需要注意的是,系統要求新的RC需要與舊的RC在相同的名稱空間(Namespace)內,不能吧別人的資產偷偷的轉移到自家名下。

需要注意:
(1)RC的名字不能與舊的RC名字相同
(2)在Selector中應至少有一個Label與舊的RC的label不同,以標示其為新的RC。
執行kubectl rolling-update redis-master -f redis-masterController-v2.yaml等所有新的Pod啟動完成後,舊的Pod也被全部銷燬,這樣就完成了容器叢集的更新工作。

另一種方法,不用配置檔案,直接用kubectl rolling-update命令,加上--image引數指定新版映象名稱來完成Pod的滾動升級:
#kubectl rolling-update redis-master --image=redis-master:2.0

更新後檢視RC
#kubectl get rc

如果在更新的過程中發現配置有誤,使用者可以中斷更新操作,並通過執行kubectl rolling-update-rollback完成Pod版本的回滾:
#kubectl rolling-update redis-master --image=kubeguide/redis-master:2.0 --rollback
就可以恢復到更新前的版本了。