Pod是kubernetes中你能夠建立和部署的最小也是最簡的單位。一個Pod表明着集羣中運行的一個進程。html
Pod中封裝着應用的容器(有的狀況下是好幾個容器),存儲、獨立的網絡IP,管理容器如何運行的策略選項。Pod表明着部署的一個單位:kubernetes中應用的一個實例,可能由一個或者多個容器組合在一塊兒共享資源。node
在Kubrenetes集羣中Pod有以下兩種使用方式:nginx
Pod中共享的環境包括Linux的namespace,cgroup和其餘可能的隔絕環境,這一點跟Docker容器一致。在Pod的環境中,每一個容器中可能還有更小的子隔離環境。web
Pod中的容器共享IP地址和端口號,它們之間能夠經過localhost
互相發現。它們之間能夠經過進程間通訊,須要明白的是同一個Pod下的容器是經過lo網卡進行通訊。例如SystemV信號或者POSIX共享內存。不一樣Pod之間的容器具備不一樣的IP地址,不能直接經過IPC通訊。docker
Pod中的容器也有訪問共享volume的權限,這些volume會被定義成pod的一部分並掛載到應用容器的文件系統中。vim
就像每一個應用容器,pod被認爲是臨時實體。在Pod的生命週期中,pod被建立後,被分配一個惟一的ID(UID),調度到節點上,並一致維持指望的狀態直到被終結(根據重啓策略)或者被刪除。若是node死掉了,分配到了這個node上的pod,在通過一個超時時間後會被從新調度到其餘node節點上。一個給定的pod(如UID定義的)不會被「從新調度」到新的節點上,而是被一個一樣的pod取代,若是指望的話甚至能夠是相同的名字,可是會有一個新的UID(查看replication controller獲取詳情)。api
Pod中能夠同時運行多個進程(做爲容器運行)協同工做。同一個Pod中的容器會自動的分配到同一個 node 上。同一個Pod中的容器共享資源、網絡環境和依賴,它們老是被同時調度。數組
注意在一個Pod中同時運行多個容器是一種比較高級的用法。只有當你的容器須要緊密配合協做的時候才考慮用這種模式。例如,你有一個容器做爲web服務器運行,須要用到共享的volume,有另外一個「sidecar」容器來從遠端獲取資源更新這些文件,以下圖所示:bash
Pod中能夠共享兩種資源:網絡和存儲。服務器
每一個Pod都會被分配一個惟一的IP地址。Pod中的全部容器共享網絡空間,包括IP地址和端口。Pod內部的容器可使用localhost
互相通訊。Pod中的容器與外界通訊時,必須分配共享網絡資源(例如使用宿主機的端口映射)。
能夠Pod指定多個共享的Volume。Pod中的全部容器均可以訪問共享的volume。Volume也能夠用來持久化Pod中的存儲資源,以防容器重啓後文件丟失。
一般把Pod分爲兩類:
每一個Pod都有一個特殊的被稱爲「根容器」的Pause 容器。 Pause容器對應的鏡像屬於Kubernetes平臺的一部分,除了Pause容器,每一個Pod還包含一個或者多個緊密相關的用戶業務容器。
Kubernetes設計這樣的Pod概念和特殊組成結構有什麼用意?????
緣由一:在一組容器做爲一個單元的狀況下,難以對總體的容器簡單地進行判斷及有效地進行行動。好比,一個容器死亡了,此時是算總體掛了麼?那麼引入與業務無關的Pause容器做爲Pod的根容器,以它的狀態表明着整個容器組的狀態,這樣就能夠解決該問題。
緣由二:Pod裏的多個業務容器共享Pause容器的IP,共享Pause容器掛載的Volume,這樣簡化了業務容器之間的通訊問題,也解決了容器之間的文件共享問題。
Pod在設計支持就不是做爲持久化實體的。在調度失敗、節點故障、缺乏資源或者節點維護的狀態下都會死掉會被驅逐。
一般,用戶不須要手動直接建立Pod,而是應該使用controller(例如Deployments),即便是在建立單個Pod的狀況下。Controller能夠提供集羣級別的自愈功能、複製和升級管理。
由於Pod做爲在集羣的節點上運行的進程,因此在再也不須要的時候可以優雅的終止掉是十分必要的(比起使用發送KILL信號這種暴力的方式)。用戶須要可以放鬆刪除請求,而且知道它們什麼時候會被終止,是否被正確的刪除。用戶想終止程序時發送刪除pod的請求,在pod能夠被強制刪除前會有一個寬限期,會發送一個TERM請求到每一個容器的主進程。一旦超時,將向主進程發送KILL信號並從API server中刪除。若是kubelet或者container manager在等待進程終止的過程當中重啓,在重啓後仍然會重試完整的寬限期。
示例流程以下:
刪除寬限期默認是30秒。 kubectl delete
命令支持 —grace-period=<seconds>
選項,容許用戶設置本身的寬限期。若是設置爲0將強制刪除pod。在kubectl>=1.5版本的命令中,你必須同時使用 --force
和 --grace-period=0
來強制刪除pod。
Pod的強制刪除是經過在集羣和etcd中將其定義爲刪除狀態。當執行強制刪除命令時,API server不會等待該pod所運行在節點上的kubelet確認,就會當即將該pod從API server中移除,這時就能夠建立跟原pod同名的pod了。這時,在節點上的pod會被當即設置爲terminating狀態,不過在被強制刪除以前依然有一小段優雅刪除週期。
Pause容器,又叫Infra容器。咱們檢查node節點的時候會發現每一個node上都運行了不少的pause容器,例如以下。
[root@k8s-node01 ~]# docker ps |grep pause 0cbf85d4af9e k8s.gcr.io/pause:3.1 "/pause" 7 days ago Up 7 days k8s_POD_myapp-848b5b879b-ksgnv_default_0af41a40-a771-11e8-84d2-000c2972dc1f_0 d6e4d77960a7 k8s.gcr.io/pause:3.1 "/pause" 7 days ago Up 7 days k8s_POD_myapp-848b5b879b-5f69p_default_09bc0ba1-a771-11e8-84d2-000c2972dc1f_0 5f7777c55d2a k8s.gcr.io/pause:3.1 "/pause" 7 days ago Up 7 days k8s_POD_kube-flannel-ds-pgpr7_kube-system_23dc27e3-a5af-11e8-84d2-000c2972dc1f_1 8e56ef2564c2 k8s.gcr.io/pause:3.1 "/pause" 7 days ago Up 7 days k8s_POD_client2_default_17dad486-a769-11e8-84d2-000c2972dc1f_1 7815c0d69e99 k8s.gcr.io/pause:3.1 "/pause" 7 days ago Up 7 days k8s_POD_nginx-deploy-5b595999-872c7_default_7e9df9f3-a6b6-11e8-84d2-000c2972dc1f_2 b4e806fa7083 k8s.gcr.io/pause:3.1 "/pause" 7 days ago Up 7 days k8s_POD_kube-proxy-vxckf_kube-system_23dc0141-a5af-11e8-84d2-000c2972dc1f_2
kubernetes中的pause容器主要爲每一個業務容器提供如下功能:
如圖:
[root@k8s-node01 ~]# docker run -d --name pause -p 8880:80 k8s.gcr.io/pause:3.1 d3057ceb54bc6565d28ded2c33ad2042010be73d76117775c130984c3718d609 [root@k8s-node01 ~]# cat <<EOF >> nginx.conf > error_log stderr; > events { worker_connections 1024; } > http { > access_log /dev/stdout combined; > server { > listen 80 default_server; > server_name example.com www.example.com; > location / { > proxy_pass http://127.0.0.1:2368; > } > } > } > EOF [root@k8s-node01 ~]# docker run -d --name nginx -v `pwd`/nginx.conf:/etc/nginx/nginx.conf --net=container:pause --ipc=container:pause --pid=container:pause nginx d04f848b7386109085ee350ebb81103e4efc7df8e48da18404efb9712f926082 [root@k8s-node01 ~]# docker run -d --name ghost --net=container:pause --ipc=container:pause --pid=container:pause ghost 332c86a722f71680b76b3072e85228a8d8e9608456c653edd214f06c2a77f112
如今訪問http://192.168.56.12:8880/就能夠看到ghost博客的界面了。
解析
pause容器將內部的80端口映射到宿主機的8880端口,pause容器在宿主機上設置好了網絡namespace後,nginx容器加入到該網絡namespace中,咱們看到nginx容器啓動的時候指定了--net=container:pause
,ghost容器一樣加入到了該網絡namespace中,這樣三個容器就共享了網絡,互相之間就可使用localhost
直接通訊,--ipc=contianer:pause --pid=container:pause
就是三個容器處於同一個namespace中,init進程爲pause
,這時咱們進入到ghost容器中查看進程狀況。
[root@k8s-node01 ~]# docker exec -it ghost /bin/bash root@d3057ceb54bc:/var/lib/ghost# ps axu USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 1012 4 ? Ss 03:48 0:00 /pause root 6 0.0 0.0 32472 780 ? Ss 03:53 0:00 nginx: master process nginx -g daemon off; systemd+ 11 0.0 0.1 32932 1700 ? S 03:53 0:00 nginx: worker process node 12 0.4 7.5 1259816 74868 ? Ssl 04:00 0:07 node current/index.js root 77 0.6 0.1 20240 1896 pts/0 Ss 04:29 0:00 /bin/bash root 82 0.0 0.1 17496 1156 pts/0 R+ 04:29 0:00 ps axu
在ghost容器中同時能夠看到pause和nginx容器的進程,而且pause容器的PID是1。而在kubernetes中容器的PID=1的進程即爲容器自己的業務進程。
Pod 可以具備多個容器,應用運行在容器裏面,可是它也可能有一個或多個先於應用容器啓動的 Init 容器。
Init 容器與普通的容器很是像,除了以下兩點:
若是 Pod 的 Init 容器失敗,Kubernetes 會不斷地重啓該 Pod,直到 Init 容器成功爲止。然而,若是 Pod 對應的 restartPolicy
爲 Never,它不會從新啓動。
Pod 的 status
在信息保存在 PodStatus 中定義,其中有一個 phase
字段。
Pod 的相位(phase)是 Pod 在其生命週期中的簡單宏觀概述。該階段並非對容器或 Pod 的綜合彙總,也不是爲了作爲綜合狀態機。
Pod 相位的數量和含義是嚴格指定的。除了本文檔中列舉的狀態外,不該該再假定 Pod 有其餘的 phase
值。
下面是 phase
可能的值:
下圖是Pod的生命週期示意圖,從圖中能夠看到Pod狀態的變化。
Pod是Kubernetes的基礎單元,瞭解其建立的過程,更有助於理解系統的運做。
①用戶經過kubectl或其餘API客戶端提交Pod Spec給API Server。
②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 engine進行啓動容器,並將容器的狀態結果返回到API Server。
⑨API Server將Pod信息存儲到etcd系統中。
⑩在etcd確認寫入操做完成,API Server將確認信息發送到相關的kubelet。
Pod 有一個 PodStatus 對象,其中包含一個 PodCondition 數組。 PodCondition 數組的每一個元素都有一個 type
字段和一個 status
字段。type
字段是字符串,可能的值有 PodScheduled、Ready、Initialized 和 Unschedulable。status
字段是一個字符串,可能的值有 True、False 和 Unknown。
在pod生命週期中能夠作的一些事情。主容器啓動前能夠完成初始化容器,初始化容器能夠有多個,他們是串行執行的,執行完成後就推出了,在主程序剛剛啓動的時候能夠指定一個post start 主程序啓動開始後執行一些操做,在主程序結束前能夠指定一個 pre stop 表示主程序結束前執行的一些操做。在程序啓動後能夠作兩類檢測 liveness probe(存活性探測) 和 readness probe(就緒性探測)。以下圖:
探針是由 kubelet 對容器執行的按期診斷。要執行診斷,kubelet 調用由容器實現的Handler。其存活性探測的方法有如下三種:
設置exec探針舉例:
apiVersion: v1 kind: Pod metadata: labels: test: liveness-exec name: liveness-exec spec: containers: - name: liveness-exec-demo image: busybox args: ["/bin/sh","-c","touch /tmp/healthy;sleep 60;rm -rf /tmp/healthy;"sleep 600] livenessProbe: exec: command: ["test","-e","/tmp/healthy"]
上面的資源清單中定義了一個Pod 對象, 基於 busybox 鏡像 啓動 一個 運行「 touch/ tmp/ healthy; sleep 60; rm- rf/ tmp/ healthy; sleep 600」 命令 的 容器, 此 命令 在 容器 啓動 時 建立/ tmp/ healthy 文件, 並於 60 秒 以後 將其 刪除。 存活 性 探針 運行「 test -e/ tmp/ healthy」 命令 檢查/ tmp/healthy 文件 的 存在 性, 若 文件 存在 則 返回 狀態 碼 0, 表示 成功 經過 測試。
設置HTTP探針舉例:
apiVersion: v1 kind: Pod metadata: labels: test: liveness-http name: liveness-http spec: containers: - name: liveness-http-demo image: nginx:1.12-alpine ports: - name: http containerPort: 80 lifecycle: postStart: exec: command: ["/bin/sh","-c","echo healthy > /usr/share/nginx/html/healthy"] livenessProbe: httpGet: path: /healthy port: http scheme: HTTP
上面 清單 文件 中 定義 的 httpGet 測試 中, 請求 的 資源 路徑 爲「/ healthy」, 地址 默認 爲 Pod IP, 端口 使用 了 容器 中 定義 的 端口 名稱 HTTP, 這也 是 明確 爲 容器 指明 要 暴露 的 端口 的 用途 之一。
設置TCP探針舉例:
apiVersion: v1 kind: Pod metadata: labels: test: liveness-tcp name: liveness-tcp spec: containers: - name: liveness-tcp-demo image: nginx:1.12-alpine ports: - name: http containerPort: 80 livenessProbe: tcpSocket: port: http
上面的資源清單文件,向Pod IP的80/tcp端口發起鏈接請求,並根據鏈接創建的狀態判斷Pod存活狀態。
每次探測都將得到如下三種結果之一:
Kubelet 能夠選擇是否執行在容器上運行的兩種探針執行和作出反應:
livenessProbe
:指示容器是否正在運行。若是存活探測失敗,則 kubelet 會殺死容器,而且容器將受到其 重啓策略 的影響。若是容器不提供存活探針,則默認狀態爲 Success
。readinessProbe
:指示容器是否準備好服務請求。若是就緒探測失敗,端點控制器將從與 Pod 匹配的全部 Service 的端點中刪除該 Pod 的 IP 地址。初始延遲以前的就緒狀態默認爲 Failure
。若是容器不提供就緒探針,則默認狀態爲 Success
。若是容器中的進程可以在遇到問題或不健康的狀況下自行崩潰,則不必定須要存活探針; kubelet 將根據 Pod 的restartPolicy
自動執行正確的操做。
若是但願容器在探測失敗時被殺死並從新啓動,那麼請指定一個存活探針,並指定restartPolicy
爲 Always 或 OnFailure。
若是要僅在探測成功時纔開始向 Pod 發送流量,請指定就緒探針。在這種狀況下,就緒探針可能與存活探針相同,可是 spec 中的就緒探針的存在乎味着 Pod 將在沒有接收到任何流量的狀況下啓動,而且只有在探針探測成功後纔開始接收流量。
若是您但願容器可以自行維護,您能夠指定一個就緒探針,該探針檢查與存活探針不一樣的端點。
請注意,若是您只想在 Pod 被刪除時可以排除請求,則不必定須要使用就緒探針;在刪除 Pod 時,Pod 會自動將自身置於未完成狀態,不管就緒探針是否存在。當等待 Pod 中的容器中止時,Pod 仍處於未完成狀態。
PodSpec 中有一個 restartPolicy
字段,可能的值爲 Always、OnFailure 和 Never。默認爲 Always。 restartPolicy
適用於 Pod 中的全部容器。restartPolicy
僅指經過同一節點上的 kubelet 從新啓動容器。失敗的容器由 kubelet 以五分鐘爲上限的指數退避延遲(10秒,20秒,40秒...)從新啓動,並在成功執行十分鐘後重置。pod一旦綁定到一個節點,Pod 將永遠不會從新綁定到另外一個節點。
通常來講,Pod 不會消失,直到人爲銷燬他們。這多是一我的或控制器。這個規則的惟一例外是成功或失敗的 phase
超過一段時間(由 master 肯定)的Pod將過時並被自動銷燬。
有三種可用的控制器:
OnFailure
或 Never
的 Pod。restartPolicy
爲 Always 的 Pod。全部這三種類型的控制器都包含一個 PodTemplate。建議建立適當的控制器,讓它們來建立 Pod,而不是直接本身建立 Pod。這是由於單獨的 Pod 在機器故障的狀況下沒有辦法自動復原,而控制器卻能夠。
若是節點死亡或與集羣的其他部分斷開鏈接,則 Kubernetes 將應用一個策略將丟失節點上的全部 Pod 的 phase
設置爲 Failed。
[root@k8s-master ~]# kubectl explain pod.spec.containers.livenessProbe KIND: Pod VERSION: v1 RESOURCE: livenessProbe <Object> exec command 的方式探測 例如 ps 一個進程
failureThreshold 探測幾回失敗 纔算失敗 默認是連續三次
periodSeconds 每次的多長時間探測一次 默認10s
timeoutSeconds 探測超市的秒數 默認1s
initialDelaySeconds 初始化延遲探測,第一次探測的時候,由於主程序未必啓動完成
tcpSocket 檢測端口的探測
httpGet http請求探測
舉個例子:定義一個liveness的pod資源類型,基礎鏡像爲busybox,在busybox這個容器啓動後會執行建立/tmp/test的文件啊,並刪除,而後等待3600秒。隨後定義了存活性探測,方式是以exec的方式執行命令判斷/tmp/test是否存在,存在即表示存活,不存在則表示容器已經掛了。
[root@k8s-master ~]# vim liveness.yaml apiVersion: v1 kind: Pod metadata: name: liveness-exec-pod namespace: default labels: name: myapp spec: containers: - name: livess-exec image: busybox:latest imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","touch /tmp/test; sleep 30; rm -f /tmp/test; sleep 3600"] livenessProbe: exec: command: ["test","-e","/tmp/test"] initialDelaySeconds: 1 periodSeconds: 3 [root@k8s-master ~]# kubectl apply -f lineness.yaml
在Docker的範疇內,咱們知道能夠對運行的容器進行請求或消耗的資源進行限制。而在Kubernetes中,也有一樣的機制,容器或Pod能夠進行申請和消耗的資源就是CPU和內存。CPU屬於可壓縮型資源,即資源的額度能夠按照需求進行收縮。而內存屬於不可壓縮型資源,對內存的收縮可能會致使沒法預知的問題。
資源的隔離目前是屬於容器級別,CPU和內存資源的配置須要Pod中的容器spec字段下進行定義。其具體字段,可使用"requests"進行定義請求的確保資源可用量。也就是說容器的運行可能用不到這樣的資源量,可是必須確保有這麼多的資源供給。而"limits"是用於限制資源可用的最大值,屬於硬限制。
在Kubernetes中,1個單位的CPU至關於虛擬機的1顆虛擬CPU(vCPU)或者是物理機上一個超線程的CPU,它支持分數計量方式,一個核心(1core)至關於1000個微核心(millicores),所以500m至關因而0.5個核心,即二分之一個核心。內存的計量方式也是同樣的,默認的單位是字節,也可使用E、P、T、G、M和K做爲單位後綴,或者是Ei、Pi、Ti、Gi、Mi、Ki等形式單位後綴。
資源需求舉例:
apiVersion: v1 kind: Pod metadata: name: nginx-pod spec: containers: - name: nginx image: nginx resources: requests: memory: "128Mi" cpu: "200m"
上面的配置清單中,nginx請求的CPU資源大小爲200m,這意味着一個CPU核心足以知足nginx以最快的方式運行,其中對內存的指望可用大小爲128Mi,實際運行時不必定會用到這麼多的資源。考慮到內存的資源類型,在超出指定大小運行時存在會被OOM killer殺死的可能性,因而該請求值屬於理想中使用的內存上限。
資源限制舉例:
容器的資源需求只是可以確保容器運行時所須要的最少資源量,可是並不會限制其可用的資源上限。當應用程序存在Bug時,也有可能會致使系統資源被長期佔用的狀況,這就須要另一個limits屬性對容器進行定義資源使用的最大可用量。CPU是屬於可壓縮資源,能夠進行自由地調節。而內存屬於硬限制性資源,當進程申請分配超過limit屬性定義的內存大小時,該Pod將會被OOM killer殺死。以下:
[root@k8s-master ~]# vim memleak-pod.yaml apiVersion: v1 kind: Pod metadata: name: memleak-pod labels: app: memleak spec: containers: - name: simmemleak image: saadali/simmemleak resources: requests: memory: "64Mi" cpu: "1" limits: memory: "64Mi" cpu: "1" [root@k8s-master ~]# kubectl apply -f memleak-pod.yaml pod/memleak-pod created [root@k8s-master ~]# kubectl get pods -l app=memleak NAME READY STATUS RESTARTS AGE memleak-pod 0/1 OOMKilled 2 12s [root@k8s-master ~]# kubectl get pods -l app=memleak NAME READY STATUS RESTARTS AGE memleak-pod 0/1 CrashLoopBackOff 2 28s
Pod資源默認的重啓策略爲Always,在memleak由於內存限制而終止會當即重啓,此時該Pod會被OOM killer殺死,在屢次重複由於內存資源耗盡重啓會觸發Kunernetes系統的重啓延遲,每次重啓的時間會不斷拉長,後面看到的Pod的狀態一般爲"CrashLoopBackOff"。
這裏還須要明確的是,在一個Kubernetes集羣上,運行的Pod衆多,那麼當節點都沒法知足多個Pod對象的資源使用時,是按照什麼樣的順序去終止這些Pod對象呢??
Kubernetes是沒法自行去判斷的,須要藉助於Pod對象的優先級進行斷定終止Pod的優先問題。根據Pod對象的requests和limits屬性,Kubernetes將Pod對象分爲三個服務質量類別:
顧名思義,最低級別,死得越快!