Pod中封裝着應用的容器(有的情況下是好幾個容器),存儲、獨立的網絡IP,管理容器如何運行的策略選項。Pod代表着部署的一個單位:kubernetes中應用的一個實例,可能由一個或者多個容器組合在一起共享資源。
Docker是kubernetes中最常用的容器運行時,但是Pod也支持其他容器運行時。在
Kubernetes集群中Pod有如下兩種方式:
一個Pod中運行一個容器。“每個
Pod中一個容器”的模式是最常見的用法;在這種使用方式中,你可以把Pod想象成單個容器的封裝,Kubernetes管理的是Pod而不是直接管理容器。在一個Pod中同時運行多個容器。一個
Pod也可以同時封裝幾個需要緊密耦合互相協作的容器,它們之間共享資源。這些在同一個Pod中的容器可以互相協作成為一個service單位——一個容器共享文件,另一個“sidecar”容器來更新這些文件。Pod將這些容器的存儲資源作為一個實體來管理。
Pod中共享的環境包括Linux的namespace、cgroup和其他可能的隔絕環境,這一點跟Docker容器一致。在Pod的環境中,每個容器可能還有更小的子隔離環境。
Pod中的容器共享IP地址和端口號,它們之間可以通過localhost互相發現。它們之間可以通過進程間通信,例如SystemV信號或者POSIX共享內存。不同Pod之間的容器具有不同的IP地址,不能直接通過IPC通信。
Pod中的容器也有訪問共享volume的權限,這些volume會被定義成pod的一部分並掛載到應用容器的文件系統中。就像每個應用容器,
pod被認為是臨時(非持久的)實體。在Pod的生命周期中討論過,pod被創建后,被分配一個唯一的ID(UID),調度到節點上,並一致維持期望的狀態直到被終結(根據重啟策略)或者被刪除。如果node死掉了,分配到了這個node上的pod,在經過一個超時時間后會被重新調度到其他node節點上。一個給定的pod(如UID定義的)不會被“重新調度”到新的節點上,而是被一個同樣的pod取代,如果期望的話甚至可以是相同的名字,但是會有一個新的UID。
注意在一個
Pod中同時運行多個容器是一種比較高級的用法。只有當你的容器需要緊密配合協作的時候才考慮用這種模式。例如,你有一個容器作為web服務器運行,需要用到共享的volume,有另一個“sidecar”容器來從遠端獲取資源更新這些文件,如下圖所示:
網絡:每個
pod都會被分配一個唯一的IP地址。Pod中的所有容器共享網絡空間,包括IP地址和端口。Pod內部的容器可以使用localhost互相通信。Pod中的容器與外界通信時,必須分配共享網絡資源(例如使用宿主機的端口映射)。存儲:可以為一個
Pod指定多個共享的Volume。Pod中的所有容器都可以訪問共享的volume。Volume也可以用來持久化Pod中的存儲資源,以防容器重啟后文件丟失。
注意:重啟
Pod中的容器跟重啟Pod不是一回事。Pod只提供容器的運行環境並保持容器的運行狀態,重啟容器不會造成Pod重啟。
Pod不會自愈。如果Pod運行的Node故障,或者是調度器本身故障,這個Pod就會被刪除。同樣的,如果Pod所在Node缺少資源或者Pod處於維護狀態,Pod也會被驅逐。Kubernetes使用更高級的稱為Controller的抽象層,來管理Pod實例。雖然可以直接使用Pod,但是在Kubernetes中通常是使用Controller來管理Pod的。
Controller可以創建和管理多個Pod,提供副本管理、滾動升級和集群級別的自愈能力。例如,如果一個Node故障,Controller就能自動將該節點上的Pod調度到其他健康的Node上。
無論是手動創建還是通過
Deployment等控制器創建,Pod對象總是應該處於其生命進程中以下幾個相位(phase)之一。
掛起(
Pending):API Server創建了pod資源對象已存入etcd中,但它尚未被調度完成,或者仍處於從倉庫下載鏡像的過程中。運行中(
Running):Pod已經被調度至某節點,並且所有容器都已經被kubelet創建完成。成功(
Succeeded):Pod中的所有容器都已經成功終止並且不會被重啟失敗(
Failed):Pod中的所有容器都已終止了,並且至少有一個容器是因為失敗終止。即容器以非0狀態退出或者被系統禁止。未知(
Unknown):Api Server無法正常獲取到Pod對象的狀態信息,通常是由於無法與所在工作節點的kubelet通信所致。
API Server嘗試着將Pod對象的相關信息存入etcd中,待寫入操作執行完成,API Server即會返回確認信息至客戶端。
API Server開始反映etcd中的狀態變化。所有的
kubernetes組件均使用“watch”機制來跟蹤檢查API Server上的相關的變動。
kube-scheduler(調度器)通過其“watcher”覺察到API Server創建了新的Pod對象但尚未綁定至任何工作節點。
kube-scheduler為Pod對象挑選一個工作節點並將結果信息更新至API Server。調度結果信息由
API Server更新至etcd存儲系統,而且API Server也開始反映此Pod對象的調度結果。
Pod被調度到的目標工作節點上的kubelet嘗試在當前節點上調用Docker啟動容器,並將容器的結果狀態返回送至API Server。
API Server將Pod狀態信息存入etcd系統中。在
etcd確認寫入操作成功完成后,API Server將確認信息發送至相關的kubelet,事件將通過它被接受。
1)初始化容器必須運行完成直至結束,若某初始化容器運行失敗,那么
kubernetes需要重啟它直到成功完成。(注意:如果pod的spec.restartPolicy字段值為“Never”,那么運行失敗的初始化容器不會被重啟。)2)每個初始化容器都必須按定義的順序串行運行。
容器探測(
container probe)是Pod對象生命周期中的一項重要的日常任務,它是kubelet對容器周期性執行的健康狀態診斷,診斷操作由容器的處理器(handler)進行定義。Kubernetes支持三種處理器用於Pod探測:
ExecAction:在容器內執行指定命令,並根據其返回的狀態碼進行診斷的操作稱為Exec探測,狀態碼為0表示成功,否則即為不健康狀態。
TCPSocketAction:通過與容器的某TCP端口嘗試建立連接進行診斷,端口能夠成功打開即為正常,否則為不健康狀態。
HTTPGetAction:通過向容器IP地址的某指定端口的指定path發起HTTP GET請求進行診斷,響應碼為2xx或3xx時即為成功,否則為失敗。任何一種探測方式都可能存在三種結果:
“Success”(成功)、“Failure”(失敗)、“Unknown”(未知),只有success表示成功通過檢測。
容器探測分為兩種類型:
存活性探測(livenessProbe):用於判定容器是否處於“運行”(
Running)狀態;一旦此類檢測未通過,kubelet將殺死容器並根據重啟策略(restartPolicy)決定是否將其重啟;未定義存活檢測的容器的默認狀態為“Success”。就緒性探測(readinessProbe):用於判斷容器是否准備就緒並可對外提供服務;未通過檢測的容器意味着其尚未准備就緒,端點控制器(如
Service對象)會將其IP從所有匹配到此Pod對象的Service對象的端點列表中移除;檢測通過之后,會再將其IP添加至端點列表中。
如果希望容器在探測失敗時被殺死並重新啟動,那么請指定一個存活探針,並指定
restartPolicy為Always或OnFailure。如果要僅在探測成功時才開始向
Pod發送流量,請指定就緒探針。在這種情況下,就緒探針可能與存活探針相同,但是spec中的就緒探針的存在意味着Pod將在沒有接收到任何流量的情況下啟動,並且只有在探針探測成功才開始接收流量。如果希望容器能夠自行維護,可以指定一個就緒探針,該探針檢查與存活探針不同的端點。
注意:如果只想在
Pod被刪除時能夠排除請求,則不一定需要使用就緒探針;在刪除Pod時,Pod會自動將自身置於未完成狀態,無論就緒探針是否存在。當等待Pod中的容器停止時,Pod仍處於未完成狀態。
Always:但凡
Pod對象終止就將其重啟,默認值OnFailure:僅在
Pod對象出現錯誤時方才將其重啟Never:從不重啟
[root@k8s-master ~]# vim manfests/liveness-exec.yaml apiVersion: v1 kind: Pod metadata: name: liveness-exec-pod namespace: default labels: test: liveness-exec spec: containers: - name: liveness-exec-container image: busybox:latest imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 3600"] livenessProbe: exec: command: ["test","-e","/tmp/healthy"] initialDelaySeconds: 1 periodSeconds: 3 [root@k8s-master ~]# kubectl create -f manfests/liveness-exec.yaml #創建pod pod/liveness-exec-pod created [root@k8s-master ~]# kubectl get pods #查看pod NAME READY STATUS RESTARTS AGE liveness-exec-pod 1/1 Running 0 6s #等待一段時間后再次查看其狀態 [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE liveness-exec-pod 1/1 Running 2 2m46s
host <string>:請求的主機地址,默認為Pod IP,也可以在httpHeaders中使用“Host:”來定義。 httpHeaders <[]Object>:自定義的請求報文首部。 port <string>:請求的端口,必選字段。 path <string>:請求的HTTP資源路徑,即URL path。 scheme <string>:建立連接使用的協議,僅可為HTTP或HTTPS,默認為HTTP。
[root@k8s-master ~]# vim manfests/liveness-httpget.yaml apiVersion: v1 kind: Pod metadata: name: liveness-http namespace: default labels: test: liveness spec: containers: - name: liveness-http-demo image: nginx:1.12 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 lifecycle: postStart: exec: command: ["/bin/sh", "-c", "echo Healthz > /usr/share/nginx/html/healthz"] livenessProbe: httpGet: path: /healthz port: http scheme: HTTP [root@k8s-master ~]# kubectl create -f manfests/liveness-httpget.yaml #創建pod pod/liveness-http created [root@k8s-master ~]# kubectl get pods #查看pod NAME READY STATUS RESTARTS AGE liveness-http 1/1 Running 0 7s [root@k8s-master ~]# kubectl describe pods/liveness-http #查看liveness-http詳細信息 ...... Containers: liveness-http-demo: ...... Port: 80/TCP Host Port: 0/TCP State: Running Started: Mon, 09 Sep 2019 15:43:29 +0800 Ready: True Restart Count: 0 ......
[root@k8s-master ~]# kubectl exec pods/liveness-http -it -- /bin/sh #進入到上面創建的pod中 # rm -rf /usr/share/nginx/html/healthz #刪除healthz測試頁面 # [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE liveness-http 1/1 Running 1 10m [root@k8s-master ~]# kubectl describe pods/liveness-http ...... Containers: liveness-http-demo: ...... Port: 80/TCP Host Port: 0/TCP State: Running Started: Mon, 09 Sep 2019 15:53:04 +0800 Last State: Terminated Reason: Completed Exit Code: 0 Started: Mon, 09 Sep 2019 15:43:29 +0800 Finished: Mon, 09 Sep 2019 15:53:03 +0800 Ready: True Restart Count: 1 ......
host <string>:請求連接的目標IP地址,默認為Pod IP port <string>:請求連接的目標端口,必選字段
[root@k8s-master ~]# vim manfests/liveness-tcp.yaml apiVersion: v1 kind: Pod metadata: name: liveness-tcp-pod namespace: default labels: test: liveness-tcp spec: containers: - name: liveness-tcp-demo image: nginx:1.12 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 livenessProbe: tcpSocket: port: http
[root@k8s-master ~]# kubectl explain pods.spec.containers.livenessProbe KIND: Pod VERSION: v1 RESOURCE: livenessProbe <Object> exec command 的方式探測,例如 ps 一個進程是否存在 failureThreshold 探測幾次失敗 才算失敗, 默認是連續三次 initialDelaySeconds 初始化延遲探測,即容器啟動多久之后再開始探測,默認為0秒 periodSeconds 每隔多久探測一次,默認是10秒 successThreshold 處於失敗狀態時,探測操作至少連續多少次的成功才算通過檢測,默認為1秒 timeoutSeconds 存活性探測的超時時長,默認為1秒 httpGet http請求探測 tcpSocket 端口探測
與存活性探測機制類似,就緒性探測是用來判斷容器就緒與否的周期性(默認周期為10秒鍾)操作,它用於探測容器是否已經初始化完成並可服務於客戶端請求,探測操作返回
”success“狀態時,即為傳遞容器已經”就緒“的信號。就緒性探測也支持
Exec、HTTPGet和TCPSocket三種探測方式,且各自的定義機制也都相同。但與存活性探測觸發的操作不同的是,探測失敗時,就緒探測不會殺死或重啟容器以保證其健康性,而是通知其尚未就緒,並觸發依賴於其就緒狀態的操作(例如,從Service對象中移除此Pod對象)以確保不會有客戶端請求接入此Pod對象。
設置HTTP探針示例
#終端1: [root@k8s-master ~]# vim manfests/readiness-httpget.yaml #編輯readiness-httpget測試pod的yaml文件 apiVersion: v1 kind: Pod metadata: name: readiness-http namespace: default labels: test: readiness-http spec: containers: - name: readiness-http-demo image: nginx:1.12 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 readinessProbe: httpGet: path: /index.html port: http scheme: HTTP [root@k8s-master ~]# kubectl create -f manfests/readiness-httpget.yaml #創建pod pod/readiness-http created [root@k8s-master ~]# kubectl get pods 查看pod狀態 NAME READY STATUS RESTARTS AGE liveness-tcp-pod 1/1 Running 1 7d18h readiness-http 1/1 Running 0 7s #新打開一個終端2進入到容器里面 [root@k8s-master ~]# kubectl exec pods/readiness-http -it -- /bin/sh #進入上面創建的pod # rm -f /usr/share/nginx/html/index.html #刪除nginx的主頁面文件 # ls /usr/share/nginx/html 50x.html # #回到終端1上面查看pod狀態 [root@k8s-master ~]# kubectl get pods #查看pod狀態 NAME READY STATUS RESTARTS AGE liveness-tcp-pod 1/1 Running 1 7d18h readiness-http 0/1 Running 0 2m44s




