什么是pod?
官方說明:
Pod是Kubernetes應用程序的最基本執行單元—是你創建或部署Kubernetes對象模型中的最小和最簡單的單元。 Pod表示在集群上運行的進程。Pod封裝了應用程序的容器(或者在某些情況下是多個容器)、存儲資源、唯一的網絡標識(IP地址)以及控制容器應該如何運行的選項。 Pod表示一個部署單元:Kubernetes中的應用程序的單個實例,該實例可能由單個容器或少量緊密耦合並共享資源的容器組成。Docker是Kubernetes Pod中最常見的容器,但Pods也支持其他容器。Kubernetes集群中的Pod是如何管理容器的:
1)pod里運行單個容器: pod里只運行一個容器是最常見的Kubernetes使用案例。在這種情況下,你可以將Pod視為單個容器的封裝,Kubernetes直接管理Pod,而不是直接管理容器。
2)pod里運行多個需要協同工作的容器:Pod可能封裝了一個應用程序,該應用程序由緊密關聯並且需要共享資源的多個共同協作的容器組成。這些共同協作的容器可能形成一個統一的服務單元-一個容器將文件從共享卷提供給所有容器使用,而一個單獨的“ sidecar”容器則刷新或更新這些文件。Pod將這些容器和存儲資源包裝在一起,成為一個可管理的實體。
自己理解:
pod翻譯成中文是豌豆莢的意思,它是kubernetes中的最小調度單元,由一個或者多個容器組成,同一個pod中的這些容器共享存儲、網絡和命名空間,pod中的容器總是被同時調度,它們有共同的運行環境,運行在同一個共享上下文中,一個pod相當於一個邏輯主機--比方說我們想要部署一個tomcat應用,如果不用容器,我們可能會部署到物理機,虛擬機或者雲主機上,那么出現k8s之后,我們就可以把應用部署到pod中,所以pod充當的是一個邏輯主機的角色;pod的共享上下文是一組linux命名空間,cgroup,以及其他可能隔離的方面;Pod中的容器共享IP地址和端口空間,並且可以通過localhost相互訪問。他們還可以使用標准的進程間通信(如SystemV信號量或POSIX共享內存)相互通信,不同Pod中的容器具有不同的IP地址,無需特殊配置即可通過IPC進行通信;在一個Pod中的應用可以訪問共享的存儲卷,它被認為是Pod的一部分,可以被掛接至每一個應用文件系統;與獨立的應用容器一樣,Pod是一個臨時的實體,它有着自己的生命周期。在Pod被創建時,會被指派一個唯一的ID,並被調度到Node中,直到Pod被終止或刪除。如果Pod所在的Node宕機,給定的Pod(即通過UID定義)不會被重新調度。相反,它將被完全相同的Pod所替代。這所說的具有和Pod相關生命周期的情況,例如存儲卷,是說和Pod存在的時間一樣長。如果Pod被刪除,即使完全相同的副本被創建,則相關存儲卷等也會被刪除,並會為Pod創建一個新的存儲卷等。Pod本身就沒有打算作為持久化的實體,在調度失敗、Node失敗和獲取其它退出(缺少資源或者Node在維護)情況下,Pod都會被刪除。一般來說,用戶不應該直接創建Pod,即使創建單個的Pod也應該通過控制器創建。在集群范圍內,控制器為Pod提供自愈能力,以及副本和部署管理。
pod是如何管理多個容器的?
Pod中可以同時運行多個容器。同一個Pod中的容器會自動的分配到同一個 node 上。同一個Pod中的容器共享資源、網絡環境,它們總是被同時調度,在一個Pod中同時運行多個容器是一種比較高級的用法,只有當你的容器需要緊密配合協作的時候才考慮用這種模式。例如,你有一個容器作為web服務器運行,需要用到共享的volume,有另一個“sidecar”容器來從遠端獲取資源更新這些文件,如下圖所示:
一些Pods有init容器和應用容器。 在應用程序容器啟動之前,運行初始化容器。Pods為它組成的容器提供兩種共享資源:網絡和存儲。
網絡:
每個pod都被分配唯一的IP地址,POD中的每個容器共享網絡名稱空間,包括IP地址和網絡端口。 Pod內部的容器可以使用localhost相互通信。 當POD中的容器與POD之外的實體通信時,它們必須使用共享網絡資源(如端口)。
存儲:
Pod可以指定一組共享存儲卷。 POD中的所有容器都可以訪問共享卷,允許這些容器共享數據。 卷也允許Pod中的持久數據在需要重新啟動的情況下存活。 有關Kubernetes如何在POD中實現共享存儲的更多信息,可參考https://kubernetes.io/docs/concepts/storage/volumes/
Pod怎么工作?
我們很少在Kubernetes中直接創建單個Pod。這是因為Pods被設計成相對短暫的、一次性的實體。 當一個POD被創建(直接創建,或間接由控制器創建)時,它被安排在集群中的節點上運行。 在進程終止、pod對象被刪除、pod由於缺乏資源而被驅逐或節點失敗之前,POD仍然位於該節點上
注意:不要將重新啟動Pod中的容器與重新啟動Pod混淆。POD不是一個進程,而是一個運行容器的環境。Pod一直存在直到被刪除為止。
pod本身無法自我修復。如果將Pod調度到發生故障的節點,或者調度操作本身失敗,則將Pod刪除;同樣,由於缺乏資源或Node維護,Pod也被刪除。Kubernetes使用稱為控制器的更高級別的抽象來處理管理相對一次性的Pod實例的工作。因此,雖然可以直接使用Pod,但在Kubernetes中使用控制器來管理Pod更為常見。
pod和控制器關系
你可以使控制器創建和管理多個pod。控制器在pod失敗的情況下可以處理副本、更新以及自動修復。例如,如果某個節點發生故障,則控制器會注意到該節點上的Pod已停止工作,並創建了一個替換Pod。調度程序將替換的Pod放置到健康的節點上。可以使用deployment、statefulset、daemonset等控制器管理pod。
使用pod
Pod 可以用於托管垂直集成的應用程序棧(例如,LAMP),但最主要的目的是支持位於同一位置的、共同管理的程序,例如:
1.內容管理系統、文件和數據加載器、本地緩存管理器等。
2.日志和檢查點備份、壓縮、旋轉、快照等。
3.數據更改監視器、日志跟蹤器、日志和監視適配器、事件發布器等。
4.代理、橋接器和適配器
5.控制器、管理器、配置器和更新器
通常,不會用單個 Pod 來運行同一應用程序的多個實例。
pod模板***(重點)
控制器(如deployment、daemonset、statefulset等)是通過創建pod模板來創建和管理pod的,PodTemplate是用於創建pod的規范,並且包含在deployment、job和daemonset中。每個控制器使用自己內部的Pod模板來創建實際的Pod。PodTemplate是運行應用程序所需的任何控制器的一部分。下面的示例是一個簡單的Job的清單,包含一個podtemplate,這個是用來生成pod的模板。該Pod中的容器會打印一條消息,然后暫停。
cat job-template.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: hello
spec:
template:
# This is the pod template
spec:
containers:
- name: hello
image: busybox
command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
restartPolicy: OnFailure
# The pod template ends here
修改pod template或切換到新的pod tmplate對已經存在的pod沒有影響。 POD不直接接收模板更新,而是創建一個新的POD來匹配修改后的POD模板。例如,控制器可確保正在運行的Pod與當前Pod模板匹配。如果模板已更新,則控制器必須刪除現有的Pod並根據更新的模板創建新的Pod。每個控制器都實現自己的規則來處理Pod模板的更改。在節點上,kubelet不直接觀察或管理有關Pod模板和更新的任何詳細信息。
和pod相關的api對象
kubectl explain pods
上面命令可以看到和pod相關的api對象有哪些,也就是通過資源清單yaml部署一個pod時需要哪些字段
apiVersion
apiVersion定義了此對象表示的版本化模式。服務器應將已識別的模式轉換為最新的內部值,並可能拒絕無法識別的值。更多信息參考:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
查看k8s集群支持的apiVersion有哪些,可以使用下面的命令:
kubectl api-versions
顯示如下支持apiVersion信息:
admissionregistration.k8s.io/v1 admissionregistration.k8s.io/v1beta1 apiextensions.k8s.io/v1 apiextensions.k8s.io/v1beta1 apiregistration.k8s.io/v1 apiregistration.k8s.io/v1beta1 apps/v1 authentication.k8s.io/v1 authentication.k8s.io/v1beta1 authorization.k8s.io/v1 authorization.k8s.io/v1beta1 autoscaling/v1 autoscaling/v2beta1 autoscaling/v2beta2 batch/v1 batch/v1beta1 certificates.k8s.io/v1beta1 coordination.k8s.io/v1 coordination.k8s.io/v1beta1 crd.projectcalico.org/v1 discovery.k8s.io/v1beta1 events.k8s.io/v1beta1 extensions/v1beta1 metrics.k8s.io/v1beta1 networking.k8s.io/v1 networking.k8s.io/v1beta1 node.k8s.io/v1beta1 policy/v1beta1 rbac.authorization.k8s.io/v1 rbac.authorization.k8s.io/v1beta1 scheduling.k8s.io/v1 scheduling.k8s.io/v1beta1 storage.k8s.io/v1 storage.k8s.io/v1beta1 v1
kind
Kind是表示此對象表示的REST資源的字符串值。服務器可以從客戶端提交請求的端點推斷出這一點,說白了就是表示我們要創建什么資源,如deployment、statefulset、pod、service、ingress
查看更詳細信息可參考:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
metadata
標准對象的元數據。更多信息:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
spec
指定容器的所需行為。更多信息:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
status
最近觀察到的pod的狀態。此數據可能不是最新的。Status不需要在pod或者其他資源中定義,這個默認是存在的,更多信息:https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status
怎么創建pod?
1.通過定義資源清單yaml文件(就是以yaml結尾的文件)創建pod,在k8s的master節點操作
查看定義資源清單需要哪些字段
kubectl explain pods
kubectl explain pods.apiVersion
kubectl explain pods.kind
kubectl explain pods.metadata
kubectl explain pods.spec
cat pod.yaml
apiVersion: v1 kind: Pod metadata: name: web namespace: default labels: web1: tomcat spec: containers: - name: tomcat1 image: tomcat:8.5-jre8-alpine imagePullPolicy: IfNotPresent
#通過kubectl apply創建一個pod
kubectl apply -f pod.yaml
#查看pod創建的情況
kubectl get pods
顯示如下:
NAME READY STATUS RESTARTS AGE
web 0/1 ContainerCreating 0 37s
#查看pod的詳細信息
kubectl describe pods web
# pod.yaml定義的所有資源都刪除掉
kubectl delete -f pod.yaml yaml
#查看pod調度到哪個節點
kubectl get pods -o wide
顯示如下:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web 1/1 Running 0 5m30s 10.244.1.21 node1 <none> <none>
#查看pod日志
kubectl logs web
#查看pod里指定容器的日志
kubectl logs -c tomcat1 web
#進入到剛才創建的pod,剛才創建的pod名字是web
kubectl exec -it web -- /bin/bash
#假如pod里有多個容器,進入到pod里的指定容器,按如下命令:
kubectl exec -it web -c tomcat1 -- /bin/bash
kubectl get pods
可查看到剛才創建的pod
pod的持久性
一般來說,用戶不需要直接創建 Pod。他們幾乎都是使用控制器進行創建,即使對於單例的 Pod 創建也一樣使用控制器,例如Deployments控制器提供集群范圍的自修復以及副本數和滾動管理。 像StatefulSet這樣的控制器還可以提供支持有狀態的Pod。
Pod生命周期
同一個pod中可以運行多個容器,我們在創建一個pod時可以通過創建多個容器來實現pod的整個生命周期,一個pod的創建包含如下過程:
Init容器(也叫做初始化容器):
Init容器就是做初始化工作的容器。可以有一個或多個,如果多個按照定義的順序依次執行,只有所有的初始化容器執行完后,主容器才啟動。由於一個Pod里的存儲卷是共享的,所以Init Container里產生的數據可以被主容器使用到,Init Container可以在多種K8S資源里被使用到,如Deployment、DaemonSet, StatefulSet、Job等,但都是在Pod啟動時,在主容器啟動前執行,做初始化工作。
主容器:
容器鈎子:
對於pod資源來說,容器鈎子是在pods.spec.containers.lifecycle下定義的
初始化容器啟動之后,開始啟動主容器,在主容器啟動之前有一個post start hook(容器啟動后鈎子)和pre stop hook(容器結束前鈎子)
postStart:該鈎子在容器被創建后立刻觸發,通知容器它已經被創建。如果該鈎子對應的hook handler執行失敗,則該容器會被殺死,並根據該容器的重啟策略決定是否要重啟該容器,這個鈎子不需要傳遞任何參數
preStop:該鈎子在容器被刪除前觸發,其所對應的hook handler必須在刪除該容器的請求發送給Docker daemon之前完成。在該鈎子對應的hook handler完成后不論執行的結果如何,Docker daemon會發送一個SGTERN信號量給Docker daemon來刪除該容器,這個鈎子不需要傳遞任何參數
#查看postStart怎么定義的,可以用如下命令:
kubectl explain pods.spec.containers.lifecycle.postStart
#查看preStop怎么定義的,可以用如下命令:
kubectl explain pods.spec.containers.lifecycle.preStop
容器探針:
livenessProbe:
指示容器是否正在運行。如果存活探測失敗,則 kubelet 會殺死容器,並且容器將受到其重啟策略的影響。如果容器不提供存活探針,則默認狀態為Success。
readinessProbe:指示容器是否准備好服務請求。如果就緒探測失敗,端點控制器將從與 Pod 匹配的所有Service 的端點中刪除該 Pod 的 IP 地址。初始延遲之前的就緒狀態默認為Failure。如果容器不提供就緒探針,則默認狀態為Success
#查看livenessProbe幫助命令:
kubectl explain pods.spec.containers.livenessProbe
#查看readinessProbe幫助命令:
kubectl explain pods.spec.containers.readinessProbe
整個圖如下:
從上面可以看出,我們pod在從創建到結束之前,會一直處於某種狀態之中,有一些狀態:
常見的pod狀態
(1)Pending:掛起,我們在請求創建pod時,條件不滿足,調度沒有完成,沒有任何一個節點能滿足調度條件。已經創建了但是沒有適合它運行的節點叫做掛起,調度沒有完成。
(2)Running:運行狀態
(3)Failed:表示失敗
(4)Succeeded:表示成功狀態
(5)Unknown:未知狀態,所謂pod是什么狀態是apiserver和運行在pod節點的kubelet進行通信獲取狀態信息的,如果節點之上的kubelet本身出故障,那么apiserver就連不上kubelet,得不到信息了,就會看Unknown
創建pod時大概經歷哪些階段:
初始化容器-->主容器
pod重啟策略
Always:只要容器掛了就重啟
OnFailure:只有容器狀態為錯誤的時候才重啟
Never:從不重啟容器
默認重啟策略就是Always
#查看重啟策略restartPolicy怎么定義的:
kubectl explain pods.spec.restartPolicy
名稱空間-namespace
namespace叫做命名空間,可以把k8s集群划分成多個名稱空間,然后對不同的名稱空間的資源做隔離,可以控制各個名稱空間的入棧,出棧策略,是一種在多個用戶之間划分群集資源的方法
#查看k8s集群當前有哪些名稱空間:
kubectl get namespace
pod label
(1)什么是標簽?
標簽其實就一對 key/value ,被關聯到對象上,比如Pod,標簽的使用我們傾向於能夠標示對象的特殊特點,並且對用戶而言是有意義的(就是一眼就看出了這個Pod是干什么的),標簽可以用來划分特定組的對象(比如版本,服務類型等),標簽可以在創建一個對象的時候直接給與,也可以在后期隨時修改,每一個對象可以擁有多個標簽,但是,key值必須是唯一的
(2)查看所有pod資源對象的標簽
kubectl get pods --show-labels
(3)查看帶有指定標簽的pod
kubectl get pods -L web1
顯示所有資源對象下web1這個標簽的標簽值
(4)kubectl get pods -l web1 --show-labels
查看擁有web1這個標簽的資源對象,並且把標簽顯示出來
(5)想修改資源的標簽,比方說想給web加上個release標簽
給資源對象打標簽要使用label命令,指定給某個類型下的某個資源打標簽,資源中的key/value可以是多個,因此在web(pod名字)這個資源下再打個標簽release,用如下命令
kubectl label pods web release=new
查看標簽是否打成功:
kubectl get pods --show-labels
顯示如下,顯示如下,說明標簽達成功了;
NAME READY STATUS RESTARTS AGE LABELS
web 1/1 Running 1 21h release=new,web1=tomcat
(6)k8s的標簽選擇器:
與name和UID不同,label不提供唯一性。通常,我們會看到很多對象有着一樣的label。通過標簽選擇器,客戶端/用戶能方便辨識出一組對象。
API目前支持兩種標簽選擇器:
- 基於等值的標簽選擇器
- 基於集合的標簽選擇器
一個label選擇器可以由多個必須條件組成,由逗號分隔。在多個必須條件指定的情況下,所有的條件都必須滿足,因而逗號起着AND邏輯運算符的作用。
一個空的label選擇器(即有0個必須條件的選擇器)會選擇集合中的每一個對象。
一個null型label選擇器(僅對於可選的選擇器字段才可能)不會返回任何對象。
基於等值關系的標簽選擇器:
=,==,!=
基於相等性或者不相等性的條件允許用label的鍵或者值進行過濾。匹配的對象必須滿足所有指定的label約束,盡管他們可能也有額外的label。有三種運算符是允許的,“=”,“==”和“!=”。前兩種代表相等性(他們是同義運算符),后一種代表非相等性。例如:
environment = production tier != frontend
第一個選擇所有鍵等於 environment 值為 production 的資源。后一種選擇所有鍵為 tier 值不等於 frontend 的資源,和那些沒有鍵為 tier 的label的資源。
要過濾所有處於 production 但不是 frontend 的資源,可以使用逗號操作符, environment=production,tier!=frontend 。
基於集合的標簽選擇器:
基於集合的label條件允許用一組值來過濾鍵。支持三種操作符: in , notin ,和 exists(僅針對於key符號) 。例如:
environment in (production, qa)
tier notin (frontend, backend)
第一個例子,選擇所有鍵等於 environment ,且value等於 production 或者 qa 的資源。 第二個例子,選擇所有鍵等於tier且值是除了frontend 和 backend 之外的資源,和那些沒有label的鍵是 tier 的資源。 類似的,逗號操作符相當於一個AND操作符。因而要使用一個 partition 鍵(不管值是什么),並且 environment 不是 qa 過濾資源可以用 partition,environment notin (qa) 。
基於集合的選擇器是一個相等性的寬泛的形式,因為 environment=production 相當於environment in (production) ,與 != and notin 類似。
基於集合的條件可以與基於相等性 的條件混合。例如, partition in (customerA,customerB),environment != qa 。
標簽選擇器根據定義的標簽可以選擇匹配到的資源對象
更多詳細信息可參考:
https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
node label
(1)查看nodes節點的標簽
kubectl get nodes --show-labels
(2)給node節點打標簽:
kubectl label nodes node1 node011=haha
kubectl get nodes --show-labels
可以看到node01上有node011這個標簽了
(3)節點選擇器nodeSelector
#查看nodeSelector幫助命令
kubectl explain pods.spec.nodeSelector
nodeSelector <map[string]string>
NodeSelector is a selector which must be true for the pod to fit on a node.
Selector which must match a node's labels for the pod to be scheduled on
that node. More info:
https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
上面有一個nodeSelector,這個是節點標簽選擇器,可以限制pod運行在哪個節點上
kubectl get pods -o wide
從上面可以看到web運行在node1上,如果我們想要讓它運行在master1上,就需要用到節點選擇器
nodeSelector:
node011: haha
#這個node011是我們給node1節點打的標簽,在上面已經操作過
cat pod.yaml 看到完整的文件如下:
apiVersion: v1
kind: Pod
metadata:
name: web
namespace: default
labels:
web1: tomcat
spec:
containers:
- name: tomcat1
image: tomcat:8.5-jre8-alpine
nodeSelector:
node011:haha
kubectl delete -f pod.yaml
kubectl apply -f pod.yaml
kubectl get pods -o wide
顯示pod運行在node1上
如果node1和node2都有node011這個標簽,那么nodeSelector則根據調度策略調度pod到相應的node節點上。
更多詳細信息可參考:
https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
節點名稱
nodeName:指定pod節點運行在哪個具體node上,不存在調度說法
查看 nodeName幫助命令:
kubectl explain pods.spec.nodeName