Pod基礎概念:
Pod是kubernetes中最小的資源管理組件,Pod也是最小化運行容器化應用的資源對象。一個Pod代表着集群中運行的一個進程。kubernetes中其他大多數組件都是圍繞着Pod來進行支撐和擴展Pod功能的,例如,用於管理Pod運行的StatefulSet和Deployment等控制器對象,用於暴露Pod應用的Service和Ingress對象,為Pod提供存儲的PersistentVolume存儲資源對象等。
在Kubrenetes集群中Pod有如下兩種使用方式:
一個Pod中運行一個容器
“每個Pod中一個容器”的模式是最常見的用法;在這種使用方式中,你可以把Pod想象成是單個容器的封裝,kuberentes管理的是Pod而不是直接管理容器。
在一個Pod中同時運行多個容器
一個Pod中也可以同時封裝幾個需要緊密耦合互相協作的容器,它們之間共享資源。這些在同一個Pod中的容器可以互相協作成為一個service單位,比如一個容器共享文件,另一個“sidecar”容器來更新這些文件。Pod將這些容器的存儲資源作為一個實體來管理。
一個Pod下的容器必須運行於同一節點上。現代容器技術建議一個容器只運行一個進程,該進程在容器中PID命令空間中的進程號為1,可直接接收並處理信號,進程終止時容器生命周期也就結束了。若想在容器內運行多個進程,需要有一個類似Linux操作系統init進程的管控類進程,以樹狀結構完成多進程的生命周期管理。運行於各自容器內的進程無法直接完成網絡通信,這是由於容器間的隔離機制導致,k8s中的Pod資源抽象正是解決此類問題,Pod對象是一組容器的集合,這些容器共享Network、UTS及IPC命令空間,因此具有相同的域名、主機名和網絡接口,並可通過IPC直接通信。
Pod資源中針對各容器提供網絡命令空間等共享機制的是底層基礎容器pause,基礎容器(也可稱為父容器)pause就是為了管理Pod容器間的共享操作,這個父容器需要能夠准確地知道如何去創建共享運行環境的容器,還能管理這些容器的生命周期。為了實現這個父容器的構想,kubernetes中,用pause容器來作為一個Pod中所有容器的父容器。這個pause容器有兩個核心的功能,一是它提供整個Pod的Linux命名空間的基礎。二來啟用PID命名空間,它在每個Pod中都作為PID為1進程(init進程),並回收僵屍進程。
pasue容器使得Pod中的所有容器可以共享兩種資源:
網絡:
每個Pod都會被分配一個唯一的IP地址。Pod中的所有容器共享網絡空間,包括IP地址和端口。Pod內部的容器可以使用localhost互相通信。Pod中的容器與外界通信時,必須分配共享網絡資源(例如使用宿主機的端口映射)。
存儲:
可以Pod指定多個共享的Volume。Pod中的所有的容器都可以訪問共享的Volume。Volume也可以用來持久化Pod中的存儲資源,以防容器重啟后文件丟失。
總結:
每個Pod都有一個特殊的被稱為“基礎容器”的Pause容器。Pause容器對應的鏡像屬於Kubernetes平台的一部分,除了Pause容器,每個Pod還包含一個或者多個緊密相關的用戶應用容器。
kubernetes中的pause容器主要為每個容器提供以下功能:
- 在pod中擔任Linux命名空間(如網絡命令空間)共享的基礎
- 啟用PID命名空間,開啟init進程
Kubernetes設計這樣的Pod概念和特殊組成結構有什么用意?
- 原因一:在一組容器作為一個單元的情況下,難以對整體的容器簡單的進行判斷及有效地進行行動。比如,一個容器死亡了,此時是算整體掛了嗎?那么引入與業務無關的Pause容器作為Pod的基礎容器,以他的狀態代表着整個容器組的狀態,這樣就可以解決該問題。
- 原因二:Pod里的 多個應用容器共享Pause容器的IP,共享Pause容器掛載的Volume,這樣簡化了應用容器之間的通信問題,也解決了容器之間的文件共享問題。
通常把Pod分為兩類:
自主式Pod:
這種Pod本身是不能自我修復的,當當Pod被創建后(不論是由你直接創建還是被其他Controller),都會被Kuberentes調度到集群的Node上。直到Pod的進程終止、被刪掉、因為缺少資源而被驅逐、或者Node故障之前這個Pod都會一直保持在那個Node上。Pod不會自愈。如果Pod運行的Node故障,或者是調度器本身故障,這個Pod就會被刪除。同樣的,如果Pod所在Node缺少資源或者Pod處於維護狀態,Pod也會被驅逐。
控制器管理的Pod
Kubernetes使用更高級的稱為Controller的抽象層,來管理Pod實例。Controller可以創建和管理多個Pod,提供副本管理、滾動升級和集群級別的自愈能力。例如,如果一個Node故障,Controller就能自動將該節點上的Pod調度到其他健康的Node上。雖然可以直接使用Pod,但是在Kubernetes中通常是使用Controller來管理Pod的。
Pod容器的分類
1、基礎容器
- 維護整個Pod網絡和存儲空間
- node節點中操作
- 啟動一個容器時,k8s會自動啟動一個基礎容器
- 每次創建Pod時候就會創建,運行的每一個容器都有一個pause-amd64的基礎容器自動會運行,對於用戶是透明的
2、初始化容器(initcontainers)
Init容器必須在應用程序容器啟動之前運行完成,而應用程序容器是並行運行的,所以Init容器能夠提供了一種簡單的阻塞或延遲應用容器的啟動的方法。
Init容器與普通的容器肥成像,除了一下兩點:
- Init容器總是運行到成功完成為止
- 每個Init容器都必須在下一個Init容器啟動之前成功完成啟動和退出:如果Pod的Init容器失敗,k8s會不斷地重啟該Pod,直到Init容器成功為止。然而,如果Pod對象的重啟策略(restartPolicy)為Never,它不會重新啟動
Init的容器的作用
因為init容器具有與應用容器分離的單獨鏡像,其啟動相關代碼具有如下優勢:
- Init容器可以包含一些安裝過程應用容器中不存在的實用工具或個性化代碼。例如,沒有必要僅為了在安裝過程中使用類似sed、awk、python或dig這樣的工具而去FROM一個鏡像來生成一個新的鏡像。
- Init 容器可以安全地運行這些工具,避免這些工具導致應用鏡像的安全性降低。
- 應用鏡像的創建者和部署者可以各自獨立工作,而沒有必要聯合構建一個單獨的應用鏡像。
- Init 容器能以不同於Pod內應用容器的文件系統視圖運行。因此,Init容器可具有訪問 Secrets 的權限,而應用容器不能夠訪問。
-
由於 Init 容器必須在應用容器啟動之前運行完成,因此 Init 容器提供了一種機制來阻塞或延遲應用容器的啟動,
直到滿足了一組先決條件。一旦前置條件滿足,Pod內的所有的應用容器會並行啟動。
3、應用容器(Maincontainer)
##並行啟動
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
這個例子是定義了一個具有 2 個 Init 容器的簡單 Pod。 第一個等待 myservice 啟動, 第二個等待 mydb 啟動。 一旦這兩個 Init容器都啟動完成,Pod 將啟動 spec 中的應用容器。
特別說明:
- 在Pod啟動過程中,Init容器會按順序在網絡和數據卷初始化之后啟動。每個容器必須在下一個容器啟動之前成功退出。
- 如果由於運行時或失敗退出,將導致容器啟動失敗,它會根據Pod的restartPolicy指定的策略進行重試。然而,如果Pod的restartPolicy設置為Always,Init容器失敗時會使用RestartPolicy策略。
- 在所有的Init容器沒有成功之前,Pod將不會變成Ready狀態。Init容器的端口將不會在Service中進行聚集。正在初始化中的Pod處於Pending狀態,但應該會將Initializing狀態設置為true。
- 如果Pod重啟,所有Init容器必須重新執行。
- 對Init容器spec的修改被限制在容器image字段,修改其他字段都不會生效。更改Init容器的image字段,等價於重啟該Pod。
- Init容器具有應用容器的所有字段。除了readinessProbe,因為Init容器無法定義不同於完成(completion)的就緒(readiness)之外的其他狀態。這會在驗證過程中強制執行。
- 在Pod中的每個app和Init容器的名稱必須唯一;與任何其它容器共享同一個名稱,會在驗證時拋出錯誤。
鏡像拉取策略(image PullPolicy):
Pod 的核心是運行容器,必須指定容器引擎,比如 Docker,啟動容器時,需要拉取鏡像,k8s 的鏡像拉取策略可以由用戶指定:
- IfNotPresent:在鏡像已經存在的情況下,kubelet 將不再去拉取鏡像,僅當本地缺失時才從倉庫中拉取,默認的鏡像拉取策略
- Always:每次創建 Pod 都會重新拉取一次鏡像;
- Never:Pod 不會主動拉取這個鏡像,僅使用本地鏡像。
注意:對於標簽為“:latest”的鏡像文件,其默認的鏡像獲取策略即為“Always”;而對於其他標簽的鏡像,其默認策略則為“IfNotPresent”。
修改文件
總結:
pod 運行方式: 自主式pod:沒有自愈能力 控制器管理pod:有自愈能力(pod被刪除后會重啟拉起新的pod)
pod三種容器:
- 基礎容器(pause):初始化容器環境,開啟pid=1的Init進程來管理其他容器的生命周期:提供網絡和存儲空間的共享環境基礎
- init容器:是在基礎容器之后,應用容器之前運行的容器,多個init容器是串行運行,Init容器必須在上一個init容器成功運行和退出后才會運行
- 應用容器(main c):運行業務的容器,在Init容器都成功運行和退出后運行的,多個應用器是並行運行的
注:在一個pod中,init容器和應用容器的名稱都是惟一的
pod鏡像拉取策略imagePullPolicy配置containers字段下面一層
- IfNotPresent:是帶有指定標簽的鏡像的默認拉取策略。本地有則用本地進行,本地沒有則從倉庫拉取鏡像
- Always:是沒有標簽的鏡像或者使用latest標簽的鏡像的默認拉取策略。創建Pod總是從倉庫拉取鏡像
- Never:不從倉庫拉取鏡像,僅使用本地鏡像
pod重啟策略restartPolicy配置跟containers字段同一層
- Always:默認的重啟策略,容器退出時,總是重啟容器
- Nerver:容器退出,從不重啟容器
- OnFailure:只有容器異常退出(非0狀態碼退出)時,才會重啟容器
Pod進階:
資源限制:
當定義Pod時可以選擇性的偽每個容器設定所需要的資源數量,最常見的可設定資源是CPU和內存大小,以及其他類型的資源。
當為Pod中的容器指定request資源時,調度器就使用該信息來決定將Pod調度到哪個節點上。當還為容器指定了limit資源時,kubelet就會確保運行的容器不會使用超出所設的limit資源量。kubelet還會為容器預留所設定的request資源量,供該容器使用。
如果Pod運行所在的節點具有足夠的可用資源,容器可以使用超出所設置的request資源量。不過,容器不可以使用超出所設置的limit資源量。
如果給容器設置了內存的limit值,但未設置內存的request值,Kubernetes會自動為其設置與內存limit相匹配的request值。類似的,如果給容器設置了CPU的limit值但未設置CPU的request值,則Kubernetes自動為其設置CPU的request值,並使之與CPU的limit值匹配。
CPU 資源單位
CPU資源的request和limit以cpu為單位。Kubernetes中的一個cpu相當於1個VCPU (1個超線程)
Kubernetes也支持帶小數CPU的請求。spec.containers [].resources.requests.cpu為0.5的容器能夠獲得一個cpu的一半CPU資源(類似於cgroup對CPU資源的時間分片)。表達式0.1等價於表達式100m (毫核) ,表示每1000毫秒內容器可以使用的CPU時間總量為0.1*1000毫秒。
內存資源單位
內存的request和limit以字節為單位。可以以整數表示,或者以10為底數的指數的單位(E、P,T,G,M,K)來表示,或者以2為底數的指數的單位(Ei, Pi,Ti,Gi、Mi, Ki)來表示。
如: 1KB-10^3-1000, 1MB-10^6-1000000-1000KB, 1GB=10^9-1000000000-1000MB
1KiB-2^10-1024, 1MiB-2 20-1048576-1024KiB
PS:在買硬盤的時候,操作系統報的數量要比產品標出或商家號稱的小一些,主要原因是標出的是以MB, GB為單位的, 1GB
就是1,000,000, 000Bte ,而操作系統是以2進制為處理單位的,因此檢查硬盤容量時是以MiB, GiB為單位, 1GB-2^30-1,073, 741, 824,相比較而言,1GiB要比1GB多出1,073, 741, 824-1, 000, 000, 000-73, 741, 824Byte,所以檢測實際結果要比標出的少一些。
Pod 和 容器的資源請求和限制
spec.containers[].resources. requests.cpu #定義創建容器時預分配的CPU資源
spec.containers[].resources.requests.memory #定義創建容器時預分配的內存資源
spec.containers[].resources.limits.cpu #定義 cpu 的資源上限
spec.containers[].resources.limits.memory #定義內存的資源上限
示例
示例1∶exec方式
- initialDelaySeconds∶指定 kubelet 在執行第一次探測前應該等待5秒,即第一次探測是在容器啟動后的第6秒才開始執行。默認是 0 秒,最小值是 0。
- periodSeconds∶指定了 kubelet 應該每 5 秒執行一次存活探測。默認是 10 秒。最小值是 1。
- failureThreshold∶當探測失敗時,Kubernetes 將在放棄之前重試的次數。存活探測情況下的放棄就意味着重新啟動容器。就緒探測情況下的放棄 Pod 會被打上未就緒的標簽。默認值是 3。最小值是 1。
- timeoutSeconds∶探測超時后等待多少秒。默認值是 1 秒。最小值是 1。(在 Kubernetes 1.20 版本之前,exec 探針會忽略timeoutSeconds 探針會無限期地持續運行,甚至可能超過所配置的限期,直到返回結果為止。)
可以看到 Pod 中只有一個容器。kubelet 在執行第一次探測前需要等待 5 秒,kubelet 會每 5 秒執行一次存活探測。kubelet在容器內執行命令 cat /tmp/healthy 來進行探測。
如果命令執行成功並且返回值為 0,kubelet 就會認為這個容器是健康存活的。當到達第31 秒時,這個命令返回非 0 值,kubelet會殺死這個容器並重新啟動它。
示例2∶httpGet方式
在這個配置文件中, 可以看到 Pod 也只有一個容器。initialDelaySeconds 字段告訴 kubelet 在執行第一次探測前應該等待 3秒。periodSeconds 字段指定了 kubelet 每隔 3 秒執行一次存活探測。 timeoutSeconds字段指定了超時等待時間為10S,kubelet 會向容器內運行的服務(服務會監聽 80端口)發送一個HTTP GET 請求來執行探測。如果服務器上/index.html路徑下的處理程序返回成功代碼,則 kubelet 認為容器是健康存活的。如果處理程序返回失敗代碼,則 kubelet 會殺死這個容器並且重新啟動它。
任何大於或等於 200 並且小於 400 的返回代碼標示成功,其它返回代碼都標示失敗。
示例3∶tcpSocket方式
啟動退出動作:
整個pod生命周期當中,init容器是先運行的,等init容器運行退出后,業務容器才會啟動,業務容器會發送postStart(啟動動作事件),也不會影響容器的運行狀態,當容器退出之前,k8s也會發出一個poststop事件,容器才能退出。
探針:
3種探針
- livenessProbe(存活探針):判斷容器是否正常運行,如果失敗則殺掉容器(不是Pod),再根據重啟策略是否重啟容器
- readinessProbe(就緒探針):判斷容器是否能夠進入ready狀態,探針失敗則進入noready狀態,並從service的endpoints中剔除此容器
- startupProbe:判斷容器內的應用是否啟動成功,在success狀態前,其它探針都處於無效狀態
3種檢查方式:
- exec:使用command字段設置命令,在容器中執行此命令。如果命令返回狀態碼為0,則認為探測成功
- httpget:通過訪問指定端口和url路徑執行http get訪問。如果返回的http狀態碼為大於等於200且小於400則認為成功
- tcpsocket:通過tcp連接pod(IP)和指定端口,如果端口無誤且tcp連接成功,則認為探測成功
探針可選參數
- initialDelaySeconds:容器啟動多少秒后開始執行探測
- periodSeconds:探測的周期盤頻率,每多少秒執行一次探測
- failureThreshold:探測失敗后,允許再試幾次
- timeoutSeconds:探測等待超時的時間