pod結構
Pause容器
Pause容器是每個Pod都會有的一個根容器,它的作用有兩個
- 可以以它為根據,評估整個pod的健康狀態
- 可以在根容器上設置IP地址,其他容器都以此IP(Pod IP),以實現Pod內部的網絡通信,
這里是Pod內部的通訊,Pod之間的通訊采用虛擬二層網絡技術來實現,我們當前環境用的是Flannel
pod配置
apiVersion: v1 #必選,版本號,例如v1
king: Pod #必選,資源類型,例如Pod
metadata:name: string #必選,pod名稱namespace: string #pod所屬的命名空間,默認為"default"labels:- name: string
spec: #必選,pod中容器的詳細定義containers: #必選,pod中容器列表- name: string #必選,容器名稱image: string #必選,容器鏡像名稱imagePullPolicy: [Always|Never|IfNotPresent] #獲取鏡像的策略command: [string] #容器的啟動命令列表,如不指定,使用打包時使用的啟動命令args: [string] #容器的啟動命令參數列表workingDir: string #容器的工作目錄volumeMounts: #掛載到容器內部的存儲卷配置- name: string #引用pod定義的共享數據卷的名稱,需用volumes[]部分定義的卷名mountPath: string #存儲卷在容器內mount的絕對路徑,應少于512字符readOnly: boolean #是否為只讀模式ports: 3需要暴露的端口庫號列表- name: string #端口的名稱containerPort: int #容器需要監聽的端口號hostPort: int #容器所在主機需要監聽的端口號,默認與Container相同protocol: string #端口協議,支持TCP和UDP,默認TCP env: #容器運行前需要設置的環境變量列表 - name: string #環境變量名稱 value: string #環境變量的值 resources: #資源限制和請求的設置 limits: #資源限制的設置......
pod的資源配置非常繁多,因此要一個一個記住是不現實的
所以k8s提供了能夠查看每種資源的配置項的命令
kubectl explain 資源類型 #查看某種資源可以配置的一級屬性
kubectl explain 資源類型.屬性 #查看屬性的子屬性
查看pod資源的metadata的子屬性
kubectl explain pod.metadata
在k8s中所有資源的一級屬性都是一樣的,主要包含5部分:
- apiVersion 版本,由k8s內部定義,版本號可以用 kubectl api-versions查詢到
- kind 類型,由k8s內部定義,可以用 kubectl api-resources查詢到
- metadata 元數據,主要是資源標識和說明,常用的有name,namespace,labels等
- spec 描述,這是配置中最重要的一部分,里面是對各種資源配置的詳細描述
- status 狀態信息,里面的內容不需要定義,由k8s自動生成
在上面的屬性中,spect是接下來研究的重點,繼續看下它的常見子屬性:
- containers <[]Object> 容器列表,用于定義容器的詳細信息
- nodeName 根據nodename的值將pod調度到指定的Node節點上
- nodeSelector <map[]> 根據NodeSelector中定義的信息選擇將該Pod調度到包含這些label的node上
- hostNetwork 是否使用主機網絡模式,默認為false,如果設置為true,表示使用宿主機網絡
- volumes <[]Object> 存儲卷,用于定義Pod上面掛載的存儲信息
- restartPolicy 重啟策略,表示Pod在遇到故障的時候的處理策略;
pod生命周期
pod對象從創建到終止的這段時間范圍被稱為生命周期,它主要包含以下幾個過程:
- pod創建過程
- 運行初始化容器(init container)過程
- 運行主容器(main container)
- 容器啟動后鉤子(post start)、容器終止前鉤子(pre stop)
- 容器的存活性探測(liveness probe)、就緒性探測(readiness probe)
- pod終止過程
生命周期中出現的5種狀態
狀態值 | 狀態名稱 | 描述 |
---|
- Pending|掛起|apiServer已經創建了pod資源對象,但它尚未被調度完成或者仍處于下載鏡像的過程中;
- Running|運行中|pod已經被調度至某節點,并且所有容器都已經被kubelet創建完成;
- Succeeded|成功|pod中的所有容器都已經成功終止并且不會被重啟
- Failed|失敗|所有容器都已終止,但至少有一個容器終止失敗,即容器返回了非0值的退出狀態;
- Unknown|未知|apiServer無法正常獲取到pod對象的狀態信息,通常由網絡通訊失敗所導致;
pod創建過程
- 用戶通過kubectl或其他api客戶端提交需要創建的pod信息給apiServer
- apiServer開始生成pod對象的信息,并將信息存入etcd,然后返回確認信息至客戶端
- apiServer開始反映etcd中的pod對象的變化,其它組件使用watch機制來跟蹤檢查apiServer上的變動
- scheduler發現有新的pod對象要創建,開始為Pod分配主機并將結果信息更新至apiServer
- node節點上的kubelet發現有pod調度過來,嘗試調用docker啟動容器,并將結果回送至apiServer
- apiServer將接收到的pod狀態信息存入etcd中
pod終止過程
- 用戶向apiServer發送刪除pod對象的命令
- apiServcer中的pod對象信息會隨著時間的推移而更新,在寬限期內(默認30s),pod被視為dead(死亡)
- 將pod標記為terminating(正在刪除中)狀態
- kubelet在監控到pod對象轉為terminating(正在刪除中)狀態的同時啟動pod關閉過程
- 端點控制器監控到pod對象的關閉行為時將其從所有匹配到此端點的service資源的端點列表中移除
- 如果當前pod對象定義了preStop鉤子處理器,則在其標記為terminating(正在刪除中)后即會以同步的方式啟動執行
- pod對象中的容器進程收到停止信號
- 寬限期結束后,若pod中還存在仍在運行的進程,那么pod對象會收到立即終止的信號
- kubelet請求apiServer將此pod資源的寬限期設置為0從而完成刪除操作,此時pod對于用戶已不可見
初始化容器
Pod能夠具有多個容器,應用運行在容器里面,但是它也可能有一個或多個先于應用容器啟動的 Init容器
Init 容器與普通的容器非常像,除了如下兩點:
- Init 容器總是運行到成功完成為止
- 每個 Init 容器都必須在下一個 Init 容器啟動之前成功完成
如果 Pod 的 Init 容器失敗, Kubernetes 會不斷地重啟該 Pod ,直到 Init 容器成功為止。然而,如果 Pod 對應的 restartPolicy(重啟策略) 為 Never,它不會重新啟動。
init容器能夠做什么呢?
- Init 容器可以包含一些安裝過程中應用容器中不存在的實用工具或個性化代碼。
- Init 容器可以安全地運行這些工具,避免這些工具導致應用鏡像的安全性降低。
- 應用鏡像的創建者和部署者可以各自獨立工作,而沒有必要聯合構建一個單獨的應用鏡像。
- Init 容器能以不同于Pod內應用容器的文件系統視圖運行。因此,Init容器 可具有訪問 Secrets 的權限,而應用容器不能夠訪問。
- 由于 Init 容器必須在應用容器啟動之前運行完成,因此 Init 容器提供了一種機制來阻塞或延遲應用容器的啟動,直到滿足了一組先決條件。一旦前 置條件滿足,Pod內的所有的應用容器會并行啟動。
初始化容器配置
在spec下添加initContainers子項即可
spec: containers: - image: nginx:1.17.1name: nginx-containerports: - name: "port-name"containerPort: 8080protocol: TCPinitContainers:- name: init-mysqlimage: busybox:1.3.0command: ["/bin/sh","-c","while true;do echo hello;sleep 1;done"]
鉤子函數
類似spring的AOP功能,在主容器啟動后和容器終止前執行一些自定義的邏輯;
postStart
:容器創建之后執行,如果postStart鉤子函數失敗了會重啟容器;preStop
:容器終止之前執行,執行完成之后容器將成功終止,在其完成之前會阻塞刪除容器的操作
鉤子函數支持以下三種方式定義動作
第一種:exec命令
在容器內執行一次命令,這種方式使用比較頻繁,一般都是使用這種方式作為鉤子函數;
spec: containers: - image: nginx:1.17.1name: nginx-containerports: - name: "port-name"containerPort: 8080protocol: TCPlifecycle:postStart: # 主容器啟動后鉤子exec:command: ["/bin/bash","-c","echo postStart > /root/post.txt"]preStop: # 主容器終止前鉤子exec:command: ["/bin/bash","-c","echo postStart > /root/post.txt"]
也可以這樣
spec: containers: - image: nginx:1.17.1name: nginx-containerports: - name: "port-name"containerPort: 8080protocol: TCPlifecycle:postStart: # 主容器啟動后鉤子exec:command: - cat- post.txtpreStop: # 主容器終止前鉤子exec:command: - cat- post.txt
第二種:tcpSocket
以下列子是在主容器啟動后嘗試去連接8080端口,在主容器終止前去連接8081端口
spec: containers: - image: nginx:1.17.1name: nginx-containerports: - name: "port-name"containerPort: 8080protocol: TCPlifecycle:postStart: # 主容器啟動后鉤子tcpSocket: port: 8080preStop: # 主容器終止前鉤子tcpSocket: port: 8081
第三種:httpGet
以下列子是在主容器啟動后會去訪問鏈接http://192.168.1.101:8080/login
,在主容器終止前去訪問鏈接http://192.168.1.101:8080/logout
;
spec: containers: - image: nginx:1.17.1name: nginx-containerports: - name: "port-name"containerPort: 8080protocol: TCPlifecycle:postStart: # 主容器啟動后鉤子httpGet: path: /login # Url地址port: 8080 # 端口host: 192.168.1.101 # 主機地址schema: HTTP # 支持的協議,http或httpspreStop: # 主容器終止前鉤子httpGet: path: /logout # Url地址port: 8080 # 端口host: 192.168.1.101 # 主機地址schema: HTTP # 支持的協議,http或https
容器探測
容器探測用于檢測容器中的應用實例是否正常工作,是保障業務可用性的一種傳統機制,如果經過探測,實例的狀態不符合預期,那么kubernetes就會把該問題實例“摘除”,不承擔業務流量,k8s提供了兩種探針來實現容器探測
- liveness probes : 存活性探針,用于檢測應用實例當前是否處于正常運行狀態,如果不是,k8s會重啟容器
- readiness probes : 就緒性探針,用于檢測應用實例當前是否可以接收請求,如果不能,k8s不會轉發流量
liveness probes決定是否重啟容器,readiness probes覺得是否將請求轉發給容器
存活性探針和就緒性探針都支持三種探測方式,其實就是使用了鉤子函數,
第一種 exec
在容器內執行一次命令,如果命令執行的退出碼為0,則認為程序正常, 否則不正常;
仔細看看,跟上面的鉤子函數差不多,鉤子函數用的是lifecycle
,而探針用的是livenessProbe
或者readinessProbe
# 存活性探針
.....
spec:containers:- image: nginx:1.17.1name: nginx-containerlivenessProbe: # 存活性探針initialDelaySeconds: 5 # 容器啟動后等待多少秒執行第一次探測timeoutSeconds: 10 # 探測超時時間,默認1秒,默認1秒failureThreshold: 10 # 連續探測失敗多少次才被認定為失敗,默認是3,最小值是1successThreshold: 1 # 連續探測成功多少次才被認定為成功,默認是1exec:command: - cat- post.txt
......# 就緒性探針
.....
spec:containers:- image: nginx:1.17.1name: nginx-containerreadinessProbe: # 就緒性探針initialDelaySeconds: 5 # 容器啟動后等待多少秒執行第一次探測timeoutSeconds: 10 # 探測超時時間,默認1秒,默認1秒failureThreshold: 10 # 連續探測失敗多少次才被認定為失敗,默認是3,最小值是1successThreshold: 1 # 連續探測成功多少次才被認定為成功,默認是1exec:command: - cat- post.txt
......
第二種 tcpSocket
將會嘗試訪問容器的端口,如果能建立連接,則認為程序正常,否則不正常
仔細看看,跟上面的鉤子函數差不多,鉤子函數用的是lifecycle
,而探針用的是livenessProbe
或者readinessProbe
# 存活性探針
......
spec:containers:- image: nginx:1.17.1name: nginx-containerlivenessProbe: # 存活性探針initialDelaySeconds: 5 # 容器啟動后等待多少秒執行第一次探測timeoutSeconds: 10 # 探測超時時間,默認1秒,默認1秒failureThreshold: 10 # 連續探測失敗多少次才被認定為失敗,默認是3,最小值是1successThreshold: 1 # 連續探測成功多少次才被認定為成功,默認是1tcpSocket: port: 8080
......# 就緒性探針
......
spec:containers:- image: nginx:1.17.1name: nginx-containerreadinessProbe: # 就緒性探針initialDelaySeconds: 5 # 容器啟動后等待多少秒執行第一次探測timeoutSeconds: 10 # 探測超時時間,默認1秒,默認1秒failureThreshold: 10 # 連續探測失敗多少次才被認定為失敗,默認是3,最小值是1successThreshold: 1 # 連續探測成功多少次才被認定為成功,默認是1tcpSocket: port: 8080
......
第三種 httpGet
調用容器內web應用的url,如果返回的狀態碼在200 ~ 399之間,則認為程序正常,否則不正常
仔細看看,跟上面的鉤子函數差不多,鉤子函數用的是lifecycle
,而探針用的是livenessProbe
或者readinessProbe
# 存活性探針
......
spec:containers:- image: nginx:1.17.1name: nginx-container # 存活性探針livenessProbe: initialDelaySeconds: 5 # 容器啟動后等待多少秒執行第一次探測timeoutSeconds: 10 # 探測超時時間,默認1秒,默認1秒failureThreshold: 10 # 連續探測失敗多少次才被認定為失敗,默認是3,最小值是1successThreshold: 1 # 連續探測成功多少次才被認定為成功,默認是1httpGet: path: /login # Url地址port: 8080 # 端口host: 192.168.1.101 # 主機地址schema: HTTP # 支持的協議,http或https
......# 就緒性探針
......
spec:containers:- image: nginx:1.17.1name: nginx-containerreadinessProbe: # 就緒性探針initialDelaySeconds: 5 # 容器啟動后等待多少秒執行第一次探測timeoutSeconds: 10 # 探測超時時間,默認1秒,默認1秒failureThreshold: 10 # 連續探測失敗多少次才被認定為失敗,默認是3,最小值是1successThreshold: 1 # 連續探測成功多少次才被認定為成功,默認是1httpGet: path: /login # Url地址port: 8080 # 端口host: 192.168.1.101 # 主機地址schema: HTTP # 支持的協議,http或https
......
重啟策略
存活性探針對容器進行探測時,如果出現了問題,k8s就會對容器所在的pod進行重啟,這是由pod的重啟策略決定的,pod的重啟策略由三種
- Always:(默認值)總是重啟容器
- OnFailure: 容器終止運行且退出碼不為0時重啟
- Never : 不論狀態如何,都不重啟
配置重啟策略
spec:restartPolicy: Always
重啟等待時間
重啟策略適用pod中的所有容器,如果是第一次重啟,在需要重啟時將會立即重啟,如果不是第一次重啟,那么將會延長一段時間后重啟,這是防止服務器資源都用來重啟所做的一些優化,
- 第一次重啟,立即重啟
- 第二次重啟,延長10s重啟
- 第三次重啟,延長20s重啟,
- 第四次重啟,延長40s重啟
- 第五次重啟,延長80s重啟
- 第六次重啟,延長160s重啟
- 第七次或七次以上重啟,都延長300s重啟
pod調度
什么是調度
默認情況下,一個pod在哪個node節點上運行,是通過scheduler組件采用相應的算法計算出來的,這個過程是不受人工控制的;
調度規則
但是在實際使用中,我們想控制某些pod定向到達某個節點上,應該怎么做呢?其實k8s提供了四類調度規則
調度方式 | 描述 |
---|---|
自動調度 | 通過scheduler組件采用相應的算法計算得出運行在哪個節點上 |
定向調度 | 運行到指定的node節點上,通過NodeName、NodeSelector實現 |
親和性調度 | 跟誰關系好就調度到哪個節點上 1、nodeAffinity :節點親和性,調度到關系好的節點上 2、podAffinity:pod親和性,調度到關系好的pod所在的節點上 3、PodAntAffinity:pod反清河行,調度到關系差的那個pod所在的節點上 |
污點(容忍)調度 | 污點是站在node的角度上的,比如果nodeA有一個污點,大家都別來,此時nodeA會拒絕master調度過來的pod |
定向調度
指的是利用在pod上聲明nodeName或nodeSelector的方式將pod調度到指定的pod節點上,因為這種定向調度是強制性的,所以如果node節點不存在的話,也會向上面進行調度,只不過pod會運行失敗;
定向調度-> nodeName
nodeName 是將pod強制調度到指定名稱的node節點上,這種方式跳過了scheduler的調度邏輯,直接將pod調度到指定名稱的節點上,配置文件內容如下
apiVersion: v1 # 版本號
kind: Pod # 資源類型
metadata: name: pod-namenamespace: dev
spec: containers: - image: nginx:1.17.1name: nginx-containernodeName: node1 # 調度到node1節點上
定向調度 -> NodeSelector
NodeSelector是將pod調度到添加了指定label標簽的node節點上,它是通過k8s的label-selector機制實現的,也就是說,在創建pod之前,會由scheduler用matchNodeSelecto調度策略進行label標簽的匹配,找出目標node,然后在將pod調度到目標node;
要實驗NodeSelector,首先得給node節點加上label標簽
kubectl label nodes node1 nodetag=node1
配置文件內容如下
apiVersion: v1 # 版本號
kind: Pod # 資源類型
metadata: name: pod-namenamespace: dev
spec: containers: - image: nginx:1.17.1name: nginx-containernodeSelector: nodetag: node1 # 調度到具有nodetag=node1標簽的節點上