1. 程式人生 > >k8s pod 詳述

k8s pod 詳述

 

Kubernetes |Pod 深入理解與實踐

這篇文章參考自《Kubernete權威指南》,對其中的相關章節做了一些總結,從下面十個點對pod進行深入講解,也會有些配置的例項,希望對大家學習kubernetes帶來些許幫助。

1pod定義詳解
2pod到底是什麼
3靜態pod
4pod容器共享volume
5pod的配置管理
6pod的生命週期和重啟策略
7pod健康檢查
8玩轉pod排程
9pod的擴容和縮容
10pod的滾動升級

1pod定義詳解

下面是一個完整的yaml格式定義的檔案,注意格式,子集包含關係,不要有tab,要用空格。不是所有的元素都要寫,按照實際應用場景配置即可。

apiVersion: v1            //版本
kind: pod                 //型別,pod
metadata:                 //元資料
  name: String            //元資料,pod的名字 namespace: String //元資料,pod的名稱空間 labels: //元資料,標籤列表 - name: String //元資料,標籤的名字 annotations: //元資料,自定義註解列表 - name: String //元資料,自定義註解名字 spec: //pod中容器的詳細定義 containers: //pod中的容器列表,可以有多個容器 - name: String image: String //容器中的映象 imagesPullPolicy: [Always|Never|IfNotPresent]//獲取映象的策略 command: [String] //容器的啟動命令列表(不配置的話使用映象內部的命令) args: [String] //啟動引數列表 workingDir: String //容器的工作目錄 volumeMounts: //掛載到到容器內部的儲存卷設定 - name: String mountPath: String readOnly: boolean ports: //容器需要暴露的埠號列表 - name: String containerPort: int //容器要暴露的埠 hostPort: int //容器所在主機監聽的埠(容器暴露埠對映到宿主機的埠) protocol: String env: //容器執行前要設定的環境列表 - name: String value: String resources: //資源限制 limits: cpu: Srting memory: String requeste: cpu: String memory: String livenessProbe: //pod內容器健康檢查的設定 exec: command: [String] httpGet: //通過httpget檢查健康 path: String port: number host: String scheme: Srtring httpHeaders: - name: Stirng value: String tcpSocket: //通過tcpSocket檢查健康 port: number initialDelaySeconds: 0//首次檢查時間 timeoutSeconds: 0 //檢查超時時間 periodSeconds: 0 //檢查間隔時間 successThreshold: 0 failureThreshold: 0 securityContext: //安全配置 privileged: falae restartPolicy: [Always|Never|OnFailure]//重啟策略 nodeSelector: object //節點選擇 imagePullSecrets: - name: String hostNetwork: false //是否使用主機網路模式,預設否 volumes: //在該pod上定義共享儲存卷 - name: String meptyDir: {} hostPath: path: string secret: //型別為secret的儲存卷 secretName: String item: - key: String path: String configMap: //型別為configMap的儲存卷 name: String items: - key: String path: String 

2pod到底是什麼

kubernetes中的一切都可以理解為是一種資源物件,pod,rc,service,都可以理解是 一種資源物件。podd的組成示意圖如下:

  QQ截圖20170405161659.png

由一個叫”pause“的根容器,加上一個或多個使用者自定義的容器構造。pause的狀態帶便了這一組容器的狀態,pod裡多個業務容器共享pod的Ip和資料卷。

我是這樣理解的,在kubernetes環境下,pod是容器的載體,所有的容器都是在pod中被管理,一個或多個容器放在pod裡作為一個單元方便管理。還有就是docker和kubernetes也不是一家公司的,如果做一個編排部署的工具,你也不可能直接去管理別人公司開發的東西吧,然後就把docker容器放在了pod裡,在kubernetes的叢集環境下,我直接管理我的pod,然後對於docker容器的操作,我把它封裝在pod裡,不直接操作。

3靜態pod

靜態Pod是由kubelet進行管理的僅存在於特定Node上的pod.它們不能通過API Server進行管理,無法與ReplicationController,Ddeployment或者DaemonSet進行關聯,也無法進行健康檢查。

所以我覺得這個靜態pod沒啥用武之地啊,就不詳細的寫下去了,偷個懶,嘻嘻。

4pod容器共享volume

在pod中定義容器的時候可以為單個容器配置volume,然後也可以為一個pod中的多個容器定義一個共享的pod 級別的volume。 那為啥要這樣做呢,比如你在一個pod裡定義了一個web容器,然後把生成的日誌檔案放在了一個資料夾,你還定義了一個分析日誌的容器,那這個時候你就可以把這放日誌的檔案配置為共享的,這樣一個容器生產,一個容器度就好了。

下面是一個使用共享volume的配置示例

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: loganalysis
    image: loganalysis
    volumeMounts:
    - name: app-logs
      mountPath: /usr/local/tomcat/logs
  volumes:
  - name: app-logs
  emptyDir: {}
    

這個配置檔案除了“emptyDir: {}”這個地方有點詭異以為,其他地方我估計大家一看就能明白,在最下面定義了一個叫“app-logs”的volume,然後上面的兩個容器來使用它就好了。

然後現在來說說“emptyDir: {}”,其實這個地方有三種選擇

  volumes:
  - name: app-logs
  emptyDir: {}
  
  
  volumes:
  - name: app-logs
  hostPth: 
    path: "/data"
    
    
  volumes:
  - name: app-logs
  gcePersistenDisk: 
    pdName: my-data-disk  //my-data-disk需要先建立好
    fsType: ext4

emptyDir是Pod分配到Node後建立的,他的初始內容為空,pod在Node上移除以後也就被銷燬了。

hostPath是掛載到宿主機上的目錄,比較適用於需要永久儲存的資料

gcePersistenDisk 表示使用谷歌公有云提供的磁碟
建立my-data-disk: gcloud compute disks create --size=500GB --zone=us-centrall-a my-data-disk

5pod的配置管理

應用部署的一個最佳實踐,就是將應用所需的配置資訊與程式進行分離

kubernetes 提供了一種的叢集配置管理方案,即ConfigMap,就是將一些環境變數或者配置檔案定義為configmap,放在kubernetes中,可以讓其他pod 呼叫
configmap 有以下典型的用法

1 生成為容器內的環境變數

2 設定容器啟動命令的啟動引數(需設定為環境變數)

3 以volume的形式掛載為容器內部的檔案或目錄

侷限:

1ConfigMap 必須在pod之前建立

2ConfigMap也可以定於屬於某個NameSpace,只有處於相同NameSpace的pod可以應用它

3ConfigMap中的配額管理還未實現

4如果是volume的形式掛載到容器內部,只能掛載到某個目錄下,該目錄下原有的檔案會被覆蓋掉

5靜態不能用configmap(靜態pod 不受API server 管理)

下面是使用ConfigMap的示例

1定義一個ConfigMap 配置檔案 cm-appvars.yaml

apiVersion: v1
kind: ConfigMap
metadata:
 name: cm-appvars
data:
  apploglevel: info
  appdatadir: /var/date
    

2建立ConfigMap: kubectl create -f cm-appvars.yaml

3使用ConfigMap(環境變數的形式)

apiVersion: v1
kind: Pod
metadata:
 name: cm-test-pod
spec:
  containers:
  - name: cm-test
    image: busybux
    env:
    - name: APPLOGLEVEL
      vlaueFrom:
        configMapKeyRef:
          name: cm-appvars   //要和之前建立的ConfigMap的name對應
          key: apploglevel
     - name: APPDATADIR
      vlaueFrom:
        configMapKeyRef:
          name: cm-appvars   //要和之前建立的ConfigMap的name對應
          key: appdatadir

除了可以定義簡單的k-v鍵值對,還可以將整個配置檔案定義成ConfigMap
比如server.xml logging.properties(使用volumeMount的形式,掛載到容器內部)

1定義一個ConfigMap 配置檔案 cm-jdbcproperties.yaml

apiVersion: v1
kind: ConfigMap
metadata:
 name: cm-jdbcproperties
data:
  key-jdbcproperties: |
    JDBC_DRIVER_CLASS_NAME=com.mysql.jdbc.Driver
    JDBC_URL=jdbc:mysql://localhost:3306/bz_argon?useUnicode=true&characterEncoding=utf8
    JDBC_USER_NAME=root
    JDBC_PASSWORD=maojiancai
    JDBC_INITIALSIZE=10
    JDBC_MAXACTIVE=20
    JDBC_MAXIDLE=20
    JDBC_MINIDLE=10
    JDBC_MAXWAIT=60000
    JDBC_VALIDATIONQUERY=SELECT 1 FROM DUAL
    JDBC_TESTONBORROW=false
    JDBC_TESTONRETURN=false
    JDBC_TESTWHILEIDLE=true
    JDBC_TIMEBETWEENEVICTIONRUNSMILLIS=6000
    JDBC_MINEVICTABLEIDLETIMEMILLIS=25200000
    JDBC_REMOVEABANDONED=true JDBC_REMOVEABANDONEDTIMEOUT=1800 JDBC_LOGABANDONED=true 

2建立ConfigMap: kubectl create -f cm-jdbcproperties.yaml

3使用ConfigMap(使用volumeMount的形式)

apiVersion: v1
kind: Pod
metadata:
 name: cm-test-app
spec:
  containers:
  - name: cm-test-app
    image: cm-test-app
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: jdbcproperties //應用下面定義的volumes名
      mountPath: /configfiles
  volumes:
  - name: jdbcproperties    //volumes名
    configMap:
      name: cm-jdbcproperties//這個名字是第二步建立的configMap
      items:
      - key: key-jdbcproperties
        path: jdbc.properties
    

再提醒一下;

如果是volume的形式掛載到容器內部,只能掛載到某個目錄下,該目錄下原有的檔案會被覆蓋掉

6pod的生命週期和重啟策略

pod一共有四種狀態

狀態值 描述
Pending APIserver已經建立該server,但pod內有一個或多個容器的映象還未建立,可能在下載中。
Running Pod內所有的容器已建立,且至少有一個容器處於執行狀態,正在啟動或重啟狀態
Failed Pod內所有容器都已退出,其中至少有一個容器退出失敗
Unknown 由於某種原因無法獲取Pod的狀態比如網路不通。
重啟策略 描述
Always 容器失效時,即重啟
OnFailure 容器終止執行,且退出碼不為0 時重啟
Never P不重啟

Pod的重啟策略應用於Pod內的所有容器,由Pod所在Node節點上的Kubelet進行判斷和重啟操作。重啟策略有以下三種:

重啟策略 描述
Always 容器失效時,即重啟
OnFailure 容器終止執行,且退出碼不為0 時重啟
Never P不重啟

7pod健康檢查

Kubernetes內部通過2種探針,實現了對Pod健康的檢查

LivenessProbe探針:判斷容器是否存活(running)
ReadinessProbe探針: 用於判斷容器是否啟動完成(ready)

LivenessProbe探針通過三種方式來檢查容器是否健康

(1)ExecAction:在容器內部執行一個命令,如果返回碼為0,則表示健康

示例:

apiVersion: v1
kind: Pod
metadata:
 name: liveness
spec:
  containers:
  - name: liveness
    image: liveness
    args: 
    - /bin/sh
    - -c
    - echo ok > /tmp/healthy: sleep 10; rm - rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/health
    initialDelaySeconds: 15
    timeoutSeconds: 1
    

(2)TcpAction:通過IP 和port ,如果能夠和容器建立連線則表示容器健康

示例:

apiVersion: v1
kind: Pod
metadata:
 name: pod-with-healthcheck
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    livenessProbe:
      tcpSocket:
        port: 80
    initialDelaySeconds: 15
    timeoutSeconds: 1 

(3)HttpGetAction:傳送一個http Get請求(ip+port+請求路徑)如果返回狀態嗎在200-400之間則表示健康

示例:

apiVersion: v1
kind: Pod
metadata:
 name: pod-with-healthcheck
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    livenessProbe:
      httpGet:
        path: /_status/healthz  //請求路徑
        port: 80 initialDelaySeconds: 15 timeoutSeconds: 1 

8玩轉pod排程

在kubernetes系統中,pod在大部分場景下都只是容器的載體而已,通常需要通過Deployment,DaemonSet,Job等物件來完成Pod的排程與自動控制功能。

(1)RC,Deployment: 全自動排程

RC的主要功能之一就是自動部署一個容器應用的多份副本,以及持續監控,保持叢集內有一定數量的副本數量(配置檔案指定了副本數量)

NodeSelector: 定向排程

kubernetes中的Schduler 負責實現pode的排程,他會根據一些複雜的演算法,把pod排程到某一個Node上,如果你想指定某個Pod需要指定在某個Node上則可以通過NodeSelector定向排程

示例:

1首先通過kubectl給node打上標籤:

格式: kubectl label nodes <node-name> <label-key>=<label-value>

kubectl label nodes node1 zone=north

2在pod定義裡選擇某個node

apiVersion: v1
kind: Pod
metadata:
name: pod-with-healthcheck
spec:
containers:
- name: nginx
  image: nginx
  ports:
  - containerPort: 80
nodeSelector:
  zone: north
  

除了有定向的,還有親和性的排程 NodeAffinity,符合某種條件的,比如,某個值大於1的(可以理解為模糊匹配),NodeAffinity有In NotIn Exists DoesNotExists Gt Lt 等操作規則來選擇Node.

(2)DaemonSet: 特點場景排程

DaemonSet,用於管理在叢集中每個Node上只執行一份Pod的副本例項,比如在每節點上都執行有且只有一個fluentd

示例:配置使得在每個節點上都有一個fluentd 容器

apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
 name: fluentd-cloud-logging
 namespace: kube-system
 labels:
   k8s-app: fluentd-cloud-logging
spec:
  template:
    metadata:
       namespace: kube-system
       labels:
         k8s-app: fluentd-cloud-logging
    spec:
      containers:
      - name: fluentd-cloud-logging
        images: gcr.io/google_containers/fluentd-elasticsearch:1.17
        resources:
          limits:
            cpu: 100m memory: 200Mi env: - name: FLUENTD_ARGS value: -q volumeMounts: - name: varlog mountPath: /var/log readOnly: false - name: containers mountPath: /var/lib/docker/containers volumes: - name: containers hostPath: path: /var/lib/docker/containers - name: varlog hostPath: path: /var/log 

(3)Job: 批處理排程
我們可以通過Kubernetes job資源物件來定義並啟動一個批處理任務。批處理任務通常並行(或者序列)啟動多個計算機程序去處理一批工作項。·

9pod的擴容和縮容

1通過scale來完成擴容或縮容

假設 redis-slave 這個pod原來定義了5個副本(reolics:5)

擴容到10個,執行命令: kubectl scale rc redis-slave --replicas=10

縮容到2個,執行命令:kubectl scale rc redis-slave --replicas=2

2動態擴容縮容(HPA)

通過對cpu使用率的監控,HPA(Horizontal Pod Autoscaler),來動態的擴容或縮容。pod cpu使用率是考heapster元件來獲取的,所以要預先安裝好。

建立HPA:

在建立HPA前需要已經存在一個RC或Deployment物件,並且該RC或Deployment中的Pod必須定義 resource.request.cpu的請求值,否則無法獲取cpu使用情導致HPA 無法工作

假設現在有一個php-apache RC

1通過kubectl autoscale 命令建立

kubectl autoscale rc php-apache --min=1 --max=10 --cpu-percent=50

含義:在1-10之間調整副本數量,使CPU使用率維持在50%左右

2通過配置檔案的方式建立HPA

apiVersion: autoscaling/v1
kind: HorizaontalPodAutoscaler
metadata:
 name: php-apache
spec:
 scaleTargetRef:
   apiVersion: v1
   kind: ReplicationController
   name: php-apache
 minReplicas: 1
 maxrReplicas: 10
 targetCPUUtilizationPercentage: 50

10pod的滾動升級

滾動升級通過kubectl rolling-update 命令一鍵完成。

示例:假設現在執行的redis-master的pod是1.0版本,現在需要升級到2.0版本。

建立redis-master-controller-v2.yaml

apiVersion: v1
kind: ReplicationController
metadata:
 name: redis-master-v2
 labels:
  name: redis-master
  version: v2
spec:
  replicas: 1
  selector:
    name: redis-master
    version: v2
  template:
    metadata:
      labels:
        name: redis-master
        version: v2
    spec:
    containers:
    - name: master
      images: kubeguide/redis-master:2.0
      ports:
      - containerPort: 6379
      

更新:kubectl rolling-update redis-master -f redis-master-controller-v2.yaml

需要注意到是:

rc的名字(name)不能與舊的rc的名字相同

在selector中至少有一個Label與舊的Label不同。以標識其為新的RC