一、pod的相關知識
1.1?Pod基礎概念
Pod是kubernetes中最小的資源管理組件,Pod也是最小化運行容器化應用的資源對象。一個Pod代表著集群中運行的一個進程。kubernetes中其他大多數組件都是圍繞著Pod來進行支撐和擴展Pod功能的,例如,用于管理Pod運行的StatefulSet和Deployment等控制器對象,用于暴露Pod應用的Service和Ingress對象,為Pod提供存儲的PersistentVolume存儲資源對象等。
1.2 k8s中pod的兩種使用方式?
(1)一個pod中運行一個容器。"每個po中一個容器"的模式是最常見的用法:在這種使用方式中,你可以把pod想象成是單個容器的封裝,kterentes管理的是Pod而不是直接管理容器。
(2)在一個Pod中同時運行多個容器。一個Pod中也可以同時封裝幾個需要緊密耦合互相協作的容器,它們之間共享資源。這些在同一個Pod中的容器可以互相協作成為一個servie單位,比如一個容器共享文件,另一個"sidecar"容器(邊車容器)來更新這些文件。Pod將這些突器的存儲資源作為一個實體來管理?
1.3 pod 容器的常規使用流程?
一個Pod下的容器必須運行于同一節點上。現代容器技術建議一個容器只運行一該進程在容器中PID命令空間中的進程號為1,可直接接收并處理信號,進程終止時容個講程,器生命固期也就結束了。若想在容器內運行多個進程,需要有一個類似Linux操作系統1進程的管控類進程,以樹狀結構完成多進程的生命周期管理。
運行于各自容器內的進程無法直接完成網絡通信,這是由于容器間的隔離機制導致,k8s中的Pod資源抽象正是解決此類問題,Pod對象是一組容器的集合,這些容器其享Network、0TS及IPC命令間,因此具有相同的域名、主機名和網絡接口,并可通過IPC直接通信。?
Pod資源中針對各容器提供網絡命令空間等共享機制的是底層基礎容器pause,基礎容器( 也可稱為父容器) pause就是為了管理Pod容器間的共享操作,這個父容器需要能夠準確地知道如何去創建共享運行環境的容器,還能管理這些容器的生命周期。為了實現這個父容器的構想,kubernetes中,用pause容器來作為一個Pod中所有容器的父容器。這個pause容器有兩個核心的功能,是它提供整個Pod的Linux命名空間的基礎。二來啟用PID命名空間,它在每個Pod中都作為PID為1進程(init進程),并回收僵尸進程。
1.4 k8s中pod結構設計的巧妙用意
(1)在一組容器作為一個單元的情況下,難以對整體的容器簡單地進行判斷及有效地進行行動。比如,一個容器死亡了,此時是算整體掛了么?那么引入與業務無關的Pause容器作為Pod的基礎容器,以它的狀態代表著整個容器組的狀態,這樣就可以解決該問題。
(2)Pod里的多個應用容器共享Pause容器的IP,共享Pause容器掛載的Volume,這樣簡化了應用容器之間的通信問題,也解決了容器之間的文件共享問題。
通常把Pod分為三類?
(1)控制器管理的Pod:由scheduler調度到node節點運行的;被控制器管理的;有自愈能力,一旦Pod掛掉了,會被控制器重新拉起;有副本管理、滾動更新等功能
? ? ? ? ? ? ? ? ?創建命令:kubectl create deployment .... ? ? 控制器有 deployment ?statefulset ? deamonset?
(2)自主獨立的Pod:由scheduler調度到node節點運行的;不被控制器管理的;沒有自愈能力,一旦Pod掛掉了,不會被重新拉起;沒有副本管理、滾動更新等功能
? ? ? ? ? ? ? ?創建:kubectl run
(3)靜態Pod:不由scheduler調度到node節點運行的,而是由kubelet自行管理的;始終與kubelet運行在同一個node節點上;通過向apiserver發送請求無法直接刪除的
? ? ? ? ?在node節點的/etc/kubernetes/manifests目錄中放置Pod的yaml配置文件,kubelet就會自動根據yaml配置文件創建靜態Pod?
二、容器的分類
?2.1 ?pause基礎容器(infrastructure?container)
- 維護整個Pod網絡和存儲空間
- 啟動一個容器時,k8s會自動啟動一個基礎容器
(1)查看pause容器的基礎鏡像
docker images
(2)配置kubelet使用阿里云的鏡像
#查看pause配置鏡像文件
cat /etc/sysconfig/kubelet(kubeadmin)cat /opt/kubernetes/cfg/kubelet (二進制)
#配置修改為阿里的官方pause鏡像源
cat > /etc/sysconfig/kubelet << EOFKUBELET_EXTRA_ARGS=--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"
EOF
pause容器的作用?
- 在pod中擔任Linux命名空間( 如網絡命令空間)共享的基礎
- 啟用PID命名空間,開啟init進程。
網絡:
每個Pod都會被分配一個唯一的IP地址。Pod中的所 有容器共享網絡空間,包括IP地址和端口。Pod內 部的容器可以使用localhost互相通信。Pod中的容器與外界通信時,必須分配共享網絡資源(例如使用宿主機的端口映射)
存儲:
可以Pod指定多個共享的Volume. Pod中 的所有容器都可以訪問共享的Volume,Volume 也可以用來持久化Pod中的存儲資源,以防容器重啟后文件丟失。
總結:
每個Pod都有一個特殊的被稱為“基礎容器"的Pause容器。Pause 容器對應的鏡像屬于Kubernetes平臺的- - 部分,除了Pause容器,每個Pod還包含一個或者多個緊密相關的用戶應用容器。?
2.2 init初始化容器
每個?pod中可以包含多個容器, 應用運行在這些容器里面,同時 Pod 也可以有一個或多個先于應用容器啟動的 Init 容器。
Init 容器與普通的容器非常像,除了如下兩點:
- 它們總是運行到完成。
- 每個都必須在下一個啟動之前成功完成。
如果 Pod 的 Init 容器失敗,kubelet 會不斷地重啟該 Init 容器直到該容器成功為止。 然而,如果 Pod 對應的?restartPolicy
?值為 "Never",并且 Pod 的 Init 容器失敗, 則 Kubernetes 會將整個 Pod 狀態設置為失敗。
為 Pod 設置 Init 容器需要在pod規則中添加?initContainers
?字段, 該字段以?container類型對象數組的形式組織,和應用的?containers
?數組同級相鄰。 參閱 API 參考的容器章節了解詳情。
Init 容器的狀態在?status.initContainerStatuses
?字段中以容器狀態數組的格式返回 (類似?status.containerStatuses
?字段)。
2.3?init容器和普通容器的區別?
Init 容器支持應用容器的全部字段和特性,包括資源限制、數據卷和安全設置。 然而,Init 容器對資源請求和限制的處理稍有不同,在下面資源節有說明。
同時 Init 容器不支持?lifecycle
、livenessProbe
、readinessProbe
?和?startupProbe
, 因為它們必須在 Pod 就緒之前運行完成。
如果為一個 Pod 指定了多個 Init 容器,這些容器會按順序逐個運行。 每個 Init 容器必須運行成功,下一個才能夠運行。當所有的 Init 容器運行完成時, Kubernetes 才會為 Pod 初始化應用容器并像平常一樣運行。
2.4?Init 容器的使用?
因為 Init 容器具有與應用容器分離的單獨鏡像,其啟動相關代碼具有如下優勢:
-
Init 容器可以包含一些安裝過程中應用容器中不存在的實用工具或個性化代碼。 例如,沒有必要僅為了在安裝過程中使用類似?
sed
、awk
、python
?或?dig
?這樣的工具而去?FROM
?一個鏡像來生成一個新的鏡像。 -
應用鏡像的創建者和部署者可以各自獨立工作,而沒有必要聯合構建一個單獨的應用鏡像。
-
與同一 Pod 中的多個應用容器相比,Init 容器能以不同的文件系統視圖運行。因此,Init 容器可以被賦予訪問應用容器不能訪問的 Secret的權限。
-
由于 Init 容器必須在應用容器啟動之前運行完成,因此 Init 容器提供了一種機制來阻塞或延遲應用容器的啟動,直到滿足了一組先決條件。 一旦前置條件滿足,Pod 內的所有的應用容器會并行啟動。
-
Init 容器可以安全地運行實用程序或自定義代碼,而在其他方式下運行這些實用程序或自定義代碼可能會降低應用容器鏡像的安全性。 通過將不必要的工具分開,你可以限制應用容器鏡像的被攻擊范圍
運行特例
- 在Pod啟動過程中,Init容器會按順序在網絡和數據卷初始化之后啟動。每個容器必須在下一個容器啟動之前成功退出。
- 如果由于運行時或失敗退出,將導致容器啟動失敗,它會根據Podl的restartPolicy指定的策略(該策略又分為?Always , Never ,OnFailure)進行重試。然而,如果Pod的restartPolicy設置為Always,Init容器失敗時會使用RestartPolicy策略。
- 在所有的Init容器沒有成功之前,Pod將不會變成Ready狀態。Init容器的端口將不會在service中進行聚集。正在初始化中的Pod處于Pending狀態,但應該會將Initializing狀態設置為true。
- 如果Pod重啟,所有Init容器必須重新執行。
- 對Init容器spec的修改被限制在容器image字段,修改其他字段都不會生效。更改Init容器的image字段,等價于重啟該Pod。
- Init容器具有應用容器的所有字段。除了readinessProbe,因為Tnit容器無法定義不同于完成(completion)的就緒(readiness)之外的其他狀態。這會在驗證過程中強制執行。
- 在Pod中的每個app和Init容器的名稱必須唯一;與任何其它容器共享同一個名稱,會在驗證時拋出錯誤。
2.5?應用容器(業務容器,Maincontainer)?
?提供應用程序業務
?應用容器是在所有init容器都成功的完成啟動退出后才會啟動;如果Pod定義了多個應用容器,它們是并行啟動的
三、模擬演練
官網模板地址:Init 容器 | Kubernetes
?編寫業務容器加初始化容器的demo:
vim nginx_init.yaml
apiVersion: v1
kind: Pod
metadata:name: myapp01namespace: default
spec:containers:- image: nginx:1.41name: nginxports:- containerPort: 80protocol: TCPinitContainers:- name: init-test1image: busybox:1.28command: ['sh', '-c', "until nslookup test1 ; do echo waiting is for test1 && sleep 5 ; done " ]- name: init-test2image: busybox:1.28command: ['sh', '-c', "until nslookup test2 ; do echo waiting is for test2 && sleep 5 ; done " ]kubectl apply -f nginx_init.yaml
kubectl describe pods myapp01
進行聲明式資源編寫:
vim svc-init.yamlapiVersion: v1
kind: Service
metadata:name: test1namespace: defaultlabels:app: nginx
spec:ports:- port: 80selector:app: nginxkubectl aaply -f svc-init.yaml
vim svc-init.yamlapiVersion: v1
kind: Service
metadata:name: test2namespace: defaultlabels:app: busybox
spec:ports:- port: 80selector:app: busyboxkubectl apply -f svc-init.yaml
四、pod的鏡像拉取策略?
4.1?鏡像拉取說明?
當你在創建容器時會針對指定的鏡像來進行容器的創建,所以pod的創建是以鏡像為基礎。當你在拉取鏡向不指定倉庫的主機名,Kubernetes 認為你在使用 Docker 公共倉庫。
在鏡像名稱之后,你可以添加一個標簽(Tag)(與使用?docker
?或?podman
?等命令時的方式相同)。 使用標簽能讓你辨識同一鏡像序列中的不同版本。
鏡像標簽可以包含小寫字母、大寫字母、數字、下劃線(_
)、句點(.
)和連字符(-
)。 關于在鏡像標簽中何處可以使用分隔字符(_
、-
?和?.
)還有一些額外的規則。 如果你不指定標簽,Kubernetes 認為你想使用標簽latest
4.2?鏡像拉取的策略?
首先在資源式聲明中存在著imagePullPolicy的字段,它的value決定著k8s創建容器時拉取鏡像的方式策略。【此字段所在位置也說明了在聲明式yaml中,imagePullPolicy是包含containers中】
kubectl explain pod.spec.containers.imagePullPolicy
如圖所示,這三種便是k8s拉取鏡像的三種策略:
imagePullPolicy(與image字段同一層級)
(1)IfNotPresent:優先使用node節點本地已存在的鏡像,如果本地沒有則從倉庫拉取鏡像。是標簽為非latest的鏡像的默認拉取策略
(2)Always:總是從倉庫拉取鏡像,無論node節點本地是否已存在鏡像。是標簽為latest或無標簽的鏡像的默認拉取策略
(3)Never:僅使用node節點本地鏡像,總是不從倉庫拉取鏡像。?
注意:如果沒有顯式設定的話, Pod 中所有容器的默認鏡像拉取策略是IfNotPresent。但是也存在著默認策略選擇Always的情況。
- 如果你省略了?
imagePullPolicy
?字段,并且容器鏡像的標簽是?:latest
,?imagePullPolicy
?會自動設置為?Always
。 - 如果你省略了?
imagePullPolicy
?字段,并且沒有指定容器鏡像的標簽,?imagePullPolicy
?會自動設置為?Always
。 - 如果你省略了?
imagePullPolicy
?字段,并且為容器鏡像指定了非?:latest
?的標簽,?imagePullPolicy
?就會自動設置為?IfNotPresent
。
此外:
在生產環境中部署容器時,你應該避免使用?:latest
?標簽,因為這使得正在運行的鏡像的版本難以追蹤,并且難以正確地回滾。(難以追溯版本,且latest一直會不斷迭代更新,給版本維護照成困擾)?
4.3?鏡像拉取策略的設置操作?
?(1)Never策略的使用
kubectl run app-test --image=nginx:1.14 --dry-run=client -o yaml > demo1.yaml
vim demo1.yaml apiVersion: v1
kind: Pod
metadata:name: app-test
spec:containers:- image: nginx:1.10name: app-testimagePullPolicy: Never
(2)IfNotPresent策略在本地無鏡像的情況下使用?
apiVersion: v1
kind: Pod
metadata:name: app-test
spec:containers:- image: nginx:1.14name: app-testimagePullPolicy: IfNotPresent
#查看詳細的pod信息,其中也有日志的作用
kubectl describe pod app-test
?
(3)?IfNotPresent策略在本地有鏡像的情況下使用
(4)再次使用Never策略進行測試??
(5)Always策略??
五、Pod容器的3種重啟策略?
(1)docker的重啟策略?
never | 默認策略,在容器退出時不重啟容器。 |
on-failure | 在容器非正常退出時(退出狀態非0),才會重啟容器。此外on-failure還可以指定重啟次數(on-failure:3,在容器非正常退出時重啟容器,最多重啟3次。) |
always | 在容器退出時總是重啟容器。 |
unless-stopped | 在容器退出時總是重啟容器,但是不考慮在Docker守護進程啟動時就已經停止了的容器。 |
(2)K8s中pod的重啟策略?
?Always | 當Pod中的容器退出時,總是重啟容器,無論容器退出狀態碼如何。默認的重啟策略 |
OnFailure | 當Pod中的容器異常退出(容器退出狀態碼非0)時,會重啟容器,正常退出(容器退出狀態碼為0)時不重啟容器 |
Never | 當Pod中的容器退出時,總是不重啟容器,無論容器退出狀態碼如何 |
restartPolicy(與containers字段同一層級)
Always:當Pod容器退出時,總是重啟容器,無論容器退出狀態碼如何。是默認的容器重啟策略
OnFailure:當Pod容器異常退出時(容器退出狀態碼為非0),才會重啟容器;正常退出的容器(容器退出狀態碼為0)不重啟
Never:當Pod容器退出時,總是不重啟容器,無論容器退出狀態碼如何
?