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的組成示意圖如下:

由一個叫”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