小編在這裏向各位博友道個歉,上篇文章確實寫的有些應付,但怎麼說,部署確實因人而異,而且很少有剛剛進公司就讓你搭建一個集羣,一般公司都有自己的集羣,所以小編覺得,側重點不應該在安裝,應該在維護!雖然有些牽強,但小編保證,這一篇絕對有質量!希望看了小編的博客,大家對pod有更深入的認識。
這篇文章,小編打算介紹關於pod的11個重要的知識點,大家要有耐心的看下去哦!雖然內容比較多,有興趣的朋友可以細細閱讀,小編會儘可能的用比較容易理解的話和圖,去介紹比較重要並且難以理解的地方。
1. pod的基本定義和用法
首先我們通過yaml定義的方式看看pod中可以定義哪些內容:
apiVersion: v1 #版本號
kind: Pod #資源對象類型
metadata: #元數據
name: string #pod的名稱
namespace: string #pod所屬的命名空間
labels: #自定義標籤列表
- name: string
annotations: #自定義註解列表
- name: string
spec: #pod的容器的詳細定義
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: int #容器所在主機需要監聽的端口
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: #通過tcpSocket
port: number
initialDelaySeconds: 0 #首次健康檢查時間
timeoutSeconds: 0 #健康檢查的超時時間
periodSeconds: 0 #每次健康檢查的時間間隔
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always|Never|OnFailure] #pod的重啓策略
nodeSelector: object #指定的運行pod的node標籤
imagePullSecrets:
- name: string
hostNetwork: false #是否使用主機網絡模式
volumes: #該pod上定義的共享存儲卷列表
- name: string
emptyDir: {} #臨時掛載
hostPath: #掛載宿主機目錄
path: string
secret: #類型爲secret存儲卷
secretName: string
items:
- key: string
path: string
configMap: #類型爲configMap的存儲卷
name: string
items:
- key: string
path: string
是不是一下子看了這麼多配置,感覺有點濛濛的,不要着急,先苦後甜,小編接下來會一一介紹如何使用這些配置,以及這些配置有什麼作用。
Pod的基本用法:
當然這裏小編要強調的是,如果自己定義的image,並且image運行的程序的腳本是後臺調度運行的例:nohup ./start.sh,類似這樣的,如果是在docker中可以使用docker run的方式創建並啓動這個容器,當時在kubernetes中,類似這樣後臺的程序,kubelet創建這個容器的pod之後,運行完該命令,就認爲pod執行結束,將立刻銷燬這個pod,如果給這個pod綁定了RC,那麼系統將會根據RC中的pod的副本數重新啓動這個pod,這樣下去會進入無限的死循環中,當然問題出現了肯定會有解決辦法,這裏小編向大家介紹一個服務supervisor,說實話,小編也不是很懂它,有時間再把它玩一玩,這裏小編先介紹一下它是如何讓這些後臺啓動的容器持續運行,並滿足kubernetes對容器啓動的要求:supervisor提供了一種可以同時啓動多個後臺進程,並保持supervisor自身在前臺執行的機制。(好吧我知道是廢話,但是很通俗易懂,能就這樣,強行安慰自己,感覺很nice)。
接下來創建幾個pod,看看效果,這裏pod可以由一個或者多個container組成,先創建一個只有一個container的:
#frontend-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend
labels:
name: frontend
spec:
containers:
- name: frontend
image: docker.io/kubeguide/guestbook-php-frontend
env:
- name: GET_HOSTS_FROM
value: env
ports:
- containerPort: 80
hostNetwork: true
[root@zy yaml_file]# kubectl create -f frontend-pod.yaml #創建這個pod
創建一個兩個container組合成一個整體的pod對外提供服務:
apiVersion: v1
kind: Pod
metadata:
name: redis-php
labels:
name: redis-php
spec:
containers:
- name: frontend
image: docker.io/kubeguide/guestbook-php-frontend:localredis
ports:
- containerPort: 80
- name: redis
image: docker.io/kubeguide/redis-master
ports:
- containerPort: 6379
這裏有一個container,死了,可能是鏡像出了問題,當然重點不在這裏,主要是演示如何運行2個容器在一個pod中有興趣的可以解決一下這個問題:
2. 靜態pod
所謂的靜態的pod就是通過kubelet管理並且僅存在於特定的node上的pod,它們不能通過API server 進行管理,也無法與RC、deployment、daemonSet進行關聯,並且kubelet也不能對其進行健康檢查。他們總是由kubelet創建,並且總在kubelet所在node上運行。其中創建靜態的pod有兩種方式:配置文件方式和HTTP方式。
① 配置文件方式
這裏我的kubelet的配置文件在/etc/kubernetes/kubelet
然後在配置文件中加入:--config=/k8s/yaml_file/static-web.yaml
#static-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-web
labels:
name: static-web
spec:
containers:
- name: static-web
image: nginx
ports:
- name: web
containerPort: 80
[root@zy yaml_file]# systemctl restart kubelet #重啓kubelet服務
[root@zy yaml_file]# docker ps #查看本機的容器:docker ps
此時這個靜態的pod就正在創建,並且使用kubectl delete pod pod_name刪除不了這個pod的,只能讓這個pod處於pending狀態,當然只要將該node上的定義這個pod的文件刪除,就能將這個pod從這個node上刪除了。
② HTTP方式:因爲簡單這裏就不在演示,只要在kubelet的配置文件中加入:--manifest-url=xxx,kubelet就會定期的從指定的URL中下載pod的定義文件(yaml|json),然後根據定義在自己的node上創建pod。
3.pod容器共享volume
這裏的配置管理,就是將程序和配置分離,使程序更加靈活,一般的我們在打包應用程序爲鏡像,可以通過環境變量或者外掛volume的方式在創建容器的時候進行配置注入,但是如果機器規模比較大的時候,對多容器進行不同的配置注入將十分複雜,所以這裏我們介紹一種便捷方式configMap。
configMap典型使用場景:
生成容器內部的環境變量
設置容器的啓動命令的參數
以volume的形式掛載爲容器內部的文件或者目錄
在同一個pod中的多個容器之間能夠共享pod級別的存儲卷volume,volume可以被定義爲各種類型,多個容器之間進行各自掛載,將一個volume掛載爲容器內部的目錄:
上圖就是一個pod中有兩個容器同時掛載一個volume共享,其中實現的功能爲:tomcat用於向其中寫日誌,busybox用於向其中讀取日誌:
#pod-volume-applogs.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-pod
spec:
containers:
- name: tomcat
imagePullPolicy: IfNotPresent
image: docker.io/tomcat
ports:
- containerPort: 8080
volumeMounts:
- name: app-logs
mountPath: /usr/local/tomcat/logs
- name: logreader
image: docker.io/busybox
imagePullPolicy: IfNotPresent
command: ["sh","-c","tail -f /logs/catalina*.log"]
volumeMounts:
- name: app-logs
mountPath: /logs
volumes:
- name: app-logs
emptyDir: {}
注意 :這裏名稱爲volume-pod的pod中的兩個容器,同時掛載了類型爲emptyDir這種臨時目錄,並且在容器logreader中打印Tomcat容器生成的日誌,我們通過命令查看:
[root@zy yaml_file]# kubectl logs volume-pod -c logreader
4. pod的配置管理
這裏的配置管理,就是將程序和配置分離,使程序更加靈活,一般的我們在打包應用程序爲鏡像,可以通過環境變量或者外掛volume的方式在創建容器的時候進行配置注入,但是如果機器規模比較大的時候,對多容器進行不同的配置注入將十分複雜,所以這裏我們介紹一種便捷方式configMap。
configMap典型使用場景:
生成容器內部的環境變量
設置容器的啓動命令的參數
以volume的形式掛載爲容器內部的文件或者目錄
configMap用法:configMap以key-value的形式定義,這裏的value可以是string也可以是一個文件內容,通過kubectl create configmap 的方式創建configMap。
這裏小編通過這個幾個方面去介紹configMap的用法:
configMap的兩種創建方式:基於yaml文件或者基於命令。
configMap的兩種使用方式:環境變量和volume掛載。
configMap的創建:
① 基於yaml文件
#cm-appvars.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-aoovars
data:
apploglevel: info
appdatadir: /var/data
[root@zy yaml_file]# kubectl create -f cm-appvars.yaml #創建configmap
[root@zy yaml_file]# kubectl get configmap #查看創建的configmap
[root@zy yaml_file]# kubectl describe configmap cm-aoovars #查看configmap定義的內容
#cm-appconfigfiles.yaml(value爲文件內容)
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-appconfigfiles
data:
key-serverxml: |
xml文件內容
key-loggingproperties: "配置文件內容"
[root@zy yaml_file]# kubectl get configmap cm-appconfigfiles -o yaml #查看詳細內容
② 基於命令
[root@zy yaml_file]# kubectl create configmap cm-figmap --from-file=server.xml
注意:這裏會將文件的名稱爲key,內容爲value,如果目錄下有多個文件,則同時創建,並且文件的名稱爲key,內容爲value。
[root@zy yaml_file]# kubectl create configmap cm-figmap --from-literal=loglevel=info --fromliteral=appdatadir=/var/data
注意:這種方式是指定具體的key-value創建configmap
configMap的使用:
① 通過環境變量的方式使用configmap
apiVersion: v1
kind: Pod
metadata:
name: cm-test-pod
spec:
containers:
- name: busybox
image: docker.io/busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","env|grep APP"]
env:
- name: APPLOGLEVEL #定義環境變量
valueFrom:
configMapKeyRef:
name: configMapNAME
key: configMap_KEY
- name: APPLOGLEVEL #定義環境變量
valueFrom:
configMapKeyRef:
name: configMapNAME
key: configMap_KEY
在kubernetes1.6之後,有一種簡單的定義env的方式:
envFrom:
- configMapRef:
name: configMapNAME
② 通過volumeMount使用configmap
上面我們定義了一個基於文件的configmap,接下來看如何使用基於文件的configmap,掛載到具體的pod的容器的目錄下:
#cm-test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: cm-test-pod
spec:
containers:
- name: busybox
image: kubeguide/tomcat-app:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
volumeMounts:
- name: serverxml #引用volumes名稱
mountPath: /configfiles #將confimap中的文件掛載到容器的目錄中
volumes:
- name: serverxml
configMap:
name: configMapName #定義的configmap的名稱
items: #需要掛載的文件的列表
- key: key-serverxml #configmap中定義的key
path: server.xml #掛載後的文件名
- key: key-loggingproperties
path: logging.properties
注意:如果在定義volume中的configmap時不指定items,那麼volumeMount會在容器的指定目錄下爲每一個items生產一個文件名爲key,內容爲value的文件。
ConfigMap的使用限制說明:
Configmap必須在pod創建之間創建
ConfigMap受到namespace的限制,只有同一個命名空間下才能引用
靜態的pod無法使用ConfigMap
在使用volumeMount掛載的時候,configMap基於items創建的文件會整體的將掛載數據卷的容器的目錄下的文件全部覆蓋
5.在容器中獲取pod的信息
在我們創建pod後,系統就會給其分配唯一的名字、IP、並且處於某個namspace下面,那麼這些信息我們如何獲取呢?通過Downward API的方式。
Downward API可以通過以下得到兩種方式將pod的信息導入到container中:
環境變量,用於單個變量,可以將pod信息和container信息注入到容器中
Volume掛載:將數組類信息生成文件掛載到容器內部。
實例:
① 環境變量的方式
#將pod信息注入爲環境變量
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c","env"]
env:
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
[root@zy yaml_file]# kubectl log dapi-test-pod #查看
#daip-test-pod-container-vars.yaml將容器資源信息注入爲環境變量
apiVersion: v1
kind: Pod
metadata:
name: daip-test-pod-container-vars
spec:
containers:
- name: test-container
image: busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c"]
args:
- while true; do
echo -en "\n";
printenv MY_CPU_REQUEST MY_CPU_LIMIT;
printenv MY_MEM_REQUEST MY_MEM_LIMIT;
sleep 60;
done;
resources:
requests:
memory: "32Mi"
cpu: "125m"
limits:
memory: "40Mi"
cpu: "130m"
env:
- name: MY_CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.cpu
- name: MY_CPU_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.cpu
- name: MY_CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: limits.cpu
- name: MY_MEM_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.memory
- name: MY_MEM_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-container
resource: limits.memory
[root@zy yaml_file]# kubectl logs daip-test-pod-container-vars
② Volume掛載方式
![](https://s1.51cto.com/images/blog/201905/18/33b1db246d451ae70c8bc2738341fea9.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)#dapi-test-pod-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod-volume
labels:
zone: us-est-coast
cluster: test-cluster
rack: rack-22
annotations:
build: two
builder: john-doe
spec:
containers:
- name: test-container
image: busybox
imagePullPolicy: IfNotPresent
command: ["/bin/sh","-c"]
args:
- while true;do
if [[ -e /etc/labels ]];then
echo -en "\n\n";cat /etc/labels; fi;
if [[ -e /etc/annotations ]];then
echo -en "\n\n";cat /etc/annotations; fi;
sleep 60;
done;
volumeMounts:
- name: podinfo
mountPath: /etc
readOnly: false
volumes:
- name: podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotations
注意:通過設置items,將會以path的名稱生成文件。
[root@zy yaml_file]# kubectl logs dapi-test-pod-volume
Downward API的作用:在某些集羣中,集羣中的節點需要將自身標識以及進程綁定的IP地址等信息預習寫入配置文件,進程啓動時讀取這些信息,然後發佈到類似於服務註冊中心中,做集羣的節點的自動發現功能。那麼Downward API就大有用處,它可以先編寫一個預啓動腳本或者init container,通過環境變量或者文件的方式獲取pod自身的名稱、IP地址等信息,然後寫入主程序配置中。
6.pod的聲明週期和重啓策略
pod在整個聲明週期中有很多狀態,瞭解其各種狀態對於集羣排錯大有幫助:
當某個pod異常退出或者健康檢查失敗的時候,kubelet會根據pod定義中的spec.RestartPolicy的設置來進行相應的操作。
Pod的重啓策略包括:
Always:當容器失效時,由kubelet自動重啓
OnFailure:當容器終止運行且退出碼不爲0時,由kubelet自動重啓
Nerver:永遠不重啓
Pod的重啓策略,與管理其的資源對象息息相關,RC、job、Daemonset以及通過kubelet直接管理的靜態的pod,每一種控制器對pod的重啓策略都有要求:
RC和Daemonset:必須設置爲Always。
Job:OnFailure或者Nerver,確保容器執行完成不在重啓
靜態pod:在pod失效時自動重啓。(注意靜態pod不會被健康檢查)
7 .Pod的健康檢查
就像HDFS中的DataNode會定時發送心跳給namenode一樣,k8s集羣中通過探針的方式給Pod定時做健康檢查,一旦符合定義的情況,就執行相應的重啓策略。
健康檢查分爲以下兩種探針:
LivenessProbe探針: 判斷容器是否存活(runnning狀態),如果探測到容器不健康,則kubelet殺死該容器,並且根據重啓策略做相應處理,如果容器中沒有LivenessProbe探針,那麼kubelet認爲該容器的LivenessProbe探針一直返回“Success”
ReadinessProbe探針: 用於判斷容器是否啓動完成(ready狀態),可以接受請求。如果ReadinessProbe探針探測到失敗,則pod的狀態被修改。並且EndPoint Controller將從service的EndPoint中刪除包含該容器所在pod的EndPoint。
接下來我們重點介紹一下LivenessProbe探針如何判斷pod是否健康,這裏有三種實現方式:
ExecAction:在容器中執行一個命令,如果該命令返回的狀態碼爲0,表示該容器正常
TCPSocketAction:通過容器的IP地址和端口執行TCP檢查,能夠建立TCP連接,表示該容器正常
HTTPGetAction:通過容器的IP和端口以及路徑調用HTTP get方法,如果相應的狀態碼大於等於200並且小於400,則認爲該容器正常
實例演示:
① ExecAction
apiVersion: v1
kind: Pod
metadata:
labels:
test:liveness
name: liveness-exec
spec:
containers:
- name: liveness
images: gcr.io/google_containers/busybox
args:
- /bin/sh
- -c
- echo ok > /tmp/health; sleep 10 ;rm -rf /tmp/health;sleep 10 ;
livenessProbe:
exec:
command:
- cat
- /tmp/health
initialDelaySeconds: 15 #初次健康檢查時間
timeoutSeconds: 1 #超時時間
這裏注意:我們設置了livenessProbe探針初次檢查時間爲15秒,但是程序中將10之後刪除檢查的文件,這裏cat /tmp/health 這個命令執行失敗,狀態碼返回不爲0,導致kubelet殺掉該進程,並根據相應的重啓策略進行操作。
② TCPSocketAction
apiVersion: v1
kind: Pod
metadata:
labels:
test:liveness
name: liveness-exec
spec:
containers:
- name: nginx
images: nginx
ports:
- containerPort: 80
livenessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 15 #初次健康檢查時間
timeoutSeconds: 1 #超時時間
③ HTTPGetAction
apiVersion: v1
kind: Pod
metadata:
labels:
test:liveness
name: liveness-exec
spec:
containers:
- name: nginx
images: nginx
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /_status/helthz
port: 80
initialDelaySeconds: 30 #初次健康檢查時間
timeoutSeconds: 1 #超時時間
這裏小編強調一下:
initialDelaySeconds:啓動容器後首次健康檢查的時間
timeoutSeconds:健康檢查發送請求後等待相應的時間
看到這裏大家一定腦子都炸了,這裏小編想說一下,後面還有很多,這裏小編把pod介紹分爲兩篇博文向大家介紹,
後續部分URL:
文章參考至《kubernetes權威指南》