萬字警告 - k8s入門,理應Pod先行!

你們好,歡迎來到小菜我的 solo 學堂。在這裏,知識免費,不吝吸取!關注免費,不吝動手!
死鬼~看完記得給我來個三連哦!node

本文主要介紹 kubernetes中pod的使用nginx

若有須要,能夠參考程序員

若有幫助,不忘 點贊算法

微信公衆號已開啓,小菜良記,沒關注的同窗們記得關注哦!docker

上篇文章咱們說到如何搭建 k8s 集羣,不知道看完的小夥伴有沒有本身去嘗試一下呢!shell

不要讓貧窮扼殺了你學 k8s 的興趣數據庫

這篇咱們本着有始有終的原則,繼續帶你搞明白 k8s 中的pod ,成爲別人家的程序員~centos

咱們老樣子,先回顧下 k8s 中存在的幾種組件:api

那咱們還得了解一下 k8s 中幾種常見的資源:bash

  • Master: 集羣控制節點,每一個集羣都至少須要一個 master 節點負責集羣的管控
  • Node: 工做負載節點,由 master 分配容器到這些 node 節點上,而後 node 節點上的docker 負責容器的運行
  • Pod: kubernetes的最小控制單元,容器都是運行在 pod 中的,一個pod中能夠有 1 個或多個容器
  • Controller: 控制器,經過它來實現對 pod 的管理,好比啓動 pod,中止 pod,伸縮 pod 的數量等等
  • Service: pod 對外服務的統一入口,能夠維護同一類的多個 pod
  • Label: 標籤,用於對 pod 進行分類,同一類的 pod 會擁有相同的標籤
  • NameSpace: 命名空間,用來隔離 pod 的運行環境

這幾個概念先初步有個瞭解便可,接下來即是對每一個概念展開說明的時候~那麼,正片開始!

Kubernetes

1、資源管理

在 kubernetes 中,全部的內容都抽象爲資源,用戶須要經過操做資源來管理 kubernetes

關於對 資源管理 的理解,咱們須要瞭解如下幾個概念:

  • kubernetes 本質上是一個集羣系統,用戶能夠在集羣中部署各類服務
  • kubernetes 最小管理單元是 pod 而不是容器,因此咱們須要將容器放在 pod 中運行,而 pod 通常是由 pod控制器 進行管理的
  • pod 提供服務後,咱們須要藉助 service 這個資源來實現訪問 pod 中的服務
  • pod 也支持數據的持久化

而後咱們經過下面圖例梳理一下上面幾個概念:

經過上面那張圖咱們差很少就能夠將 kubernetes 中的重點資源理解一遍了,大概明白每一個資源在集羣中起到的做用。

咱們有三種方式能夠對資源對象進行管理:

  • 命令式對象管理

直接使用命令來操做 kubernetes 資源。例如:

kubectl run nginx --image=nginx:1.19.0 -port=80
  • 命令式對象配置

經過命令配置和配置文件來操做 kubernetes 資源。例如:

kubectl create/patch -f nginx.yml
  • 聲明式對象配置

經過 apply 命令和配置文件來操做 kubernetes 資源。例如:

kubectl apply -f nginx.yml

在 k8s 中咱們通常使用 YAML 格式的文件來建立符合咱們預期指望的 pod,這樣的 YAML 文件稱爲資源清單。咱們也比較鼓勵使用清單的方式來建立資源。

若是咱們使用 命令式對象管理,這種方式雖然比較簡單,能夠直接建立一個 pod 出來,可是隻能操做活動對象,沒法進行審計和跟蹤。

命令式對象配置聲明式對象配置 在咱們平常中在建立資源服務中是比較常常用到。

1)命令式對象管理

kubectl 這個是 kubernetes 集羣的命令行工具,經過 kubectl 可以對集羣自己進行管理,並可以在集羣上進行容器化應用的安裝部署。能夠想象咱們接下來的操做絕大部分都須要藉助這個命令工具的幫助。

咱們以前也已經使用過一次了:kubectl get nodes 。這個命令即是用來獲取集羣中各個節點狀態的,那麼不難想象,這個命令的語法:

kubectl [command] [TYPE] [NAME] [flags]
  • command:指定對資源執行的操做、例如:create、get、describe、delete...
  • TYPE: 指定資源類型。資源類型是大小寫敏感的,開發者能以單數、複數和縮寫的形式,例如:pod、pods、po
  • NAME: 指定資源的名稱。名稱也是大小寫敏感的,若是省略名稱,則會顯示全部的資源,例如 :kubectl get pods
  • flags: 指定可選的參數。例如:-s 、-server、-o ...

k8s 支持的 command 有不少,咱們能夠跟 docker 同樣使用 kubectl --help 來獲取幫助文檔:

文檔不少,固然有些是經常使用的,有些是不經常使用的,小菜在這裏給大家簡單分個類,下次有須要能夠直接查看分類中的結果!

命令分類

一、 基礎命令

名稱 描述
create 經過文件名或標準輸入建立資源
expose 將一個資源公開爲一個新的 Service
run 在集羣中運行一個特定的鏡像
set 在對象上設置特定的功能
get 顯示一個或多個資源
edit 使用默認的編輯器編輯一個資源
delete 經過文件名、標準輸入、資源名稱或標籤
explain 獲取文檔參考資料

二、部署命令

名稱 描述
rollout 管理資源的發佈
rolling-update 對給定的控制器進行滾動更新
scale 擴容或縮容 pod 數量,可對 Deployment、ReplicaSet、RC或Job 操做
autoscale 建立一個自動選擇擴容或縮容並設置 pod 數量

三、 集羣管理命令

名稱 描述
certificate 修改證書資源
cluster-info 顯示集羣信息
top 顯示資源使用狀況,須要運行 Heapster
cordon 標記節點不可調度
uncordon 標記節點可調度
drain 驅逐節點上的應用,準備下線維護
taint 修改節點的 taint 標記

四、故障\調試命令

名稱 描述
describe 顯示特定資源或資源組的詳細信息
logs 在一個 pod 中打印容器日誌,若是 pod 中只有多個容器,容器名稱是可選的
attach 附加到一個運行的容器
exec 執行一個命令到容器中
port-forward 轉發一個或多個本地端口到一個 pod
proxy 運行一個 proxy 到 kubernetes ApiServer
cp 拷貝文件或目錄到容器中
auth 檢查受權

六、高級命令

名稱 描述
apply 經過文件名或標準輸入對資源應用配置
patch 使用補丁修改、更新資源的字段
replace 經過文件名或標準輸入替換一個資源
convert 不一樣的API 版本之間轉換配置文件

七、設置命令

名稱 描述
label 更新資源上的標籤
annotate 更新資源上的標籤
completion 用於實現 kubectl 工具自動補全

八、其餘命令

名稱 描述
api-versions 打印受支持的 API 版本
config 修改 kubeconfig 文件(用於訪問 API,好比配置認證信息)
help 獲取全部命令幫助
plugin 運行一個命令行插件
version 打印客戶端和服務版本信息

咱們經過一些簡單的例子來簡單的認識一下這個命令工具:

2)資源清單

無論是 命令式對象配置 仍是 聲明式對象配置 咱們都須要藉助 yaml 資源清單建立。

咱們先來看看一個 pod controller(控制器) 的yaml 文件中有哪些內容:

上面即是一個完整的 deployment 資源配置清單。內容不少,老樣子咱們先混個眼熟,不是每一個 deployment 都須要這麼多的配置,如下即是必須存在的字段屬性介紹:

名稱 類型 描述
version String 屬於 k8s 哪個API 版本或組
kind String 資源類型,如pod、deployment、service
metadata Object 元數據對象,嵌套字段
metadata.name String 元數據對象的名字
spec Object 定義容器的規範,建立的容器應該有哪些特性
spec.container[] List 定義容器的列表
spec.container[].name String 容器的名稱
spec.container[].image String 定義要用到鏡像的名稱

3)命令式對象配置

咱們結合以上必存的字段,能夠簡單寫出一個 yaml (test.yaml) 文件:

而後咱們能夠經過 命令式對象配置 的方式建立出一個 pod:

kubectl create -f test.yaml

4)聲明式對象配置

聲明式對象配置命令式對象配置 很類似,可是這種方式都是基於 apply 這一個命令來進行操做的。

咱們這邊複用一下上面建立的 test.yaml 文件

kubectl apply -f test.yaml

這種方式不能說是雞肋,它有它的特色,好比說咱們執行完上述命令後再執行一遍:

kubectl apply -f tset.yaml

能夠發現是沒什麼改動的,可是若是咱們使用的是 create 來重複執行兩遍呢?結果是報錯

那麼咱們不難猜出 apply 這個命令就是對 createpatch 這兩個命令的結合:

  • 若是資源不存在,則執行建立 等同於 create
  • 若是資源存在,則執行更新 等同於 patch

2、實戰入門

接下來的階段即是咱們針對 k8sNameSpace 和 Pod 資源展開說明了,小夥伴們打起精神了哦!

image-20210414125544325

1)Namespace

Namespace(命名空間) 的做用即是用來實現多用戶之間的資源那個李的,經過將集羣內部的資源對象分配到不一樣的 Namespace 中,造成邏輯上的分組,便於不一樣分組在共享使用整個集羣資源的同時被分別管理。默認狀況下,kubernetes 集羣中的全部 pod 都是能夠互相訪問的,可是有些時候咱們不想出現這種狀況,那就能夠藉助於 namespace

在集羣內部有個默認的Namespace - default ,咱們建立資源的時候若是不指定 namespace,那麼就會將該資源分配到該 default 的命名空間之下。

[root@master test]# kubectl get namespace

建立 Namespace 的方式也很簡單,經過如下指令即可建立:

[root@master test]# kubectl create namespace aaa-test

這樣子,咱們就得到了一個名稱爲 aaa-test 的命名空間。或者咱們也能夠經過 命令式對象配置 的方式建立,先準備一個 yaml 文件:

apiVersion: v1
kind: Namespace # yaml文件中大小寫敏感
metadata:
  name:aaa-test  #命名空間的名稱

而後執行kubectl create -f namespace.yml, 這樣子咱們一樣也能夠得到一個名稱爲 aaa-test 的命名空間。

而後咱們就能夠在資源建立的時候使用了:

而後執行 kubectl create -f nginx.yml,這樣子咱們就能夠獲取到一個 pod 資源,只有經過指定命名空間才能查看到咱們的pod資源,這說明對其餘用戶是隔離的:

若是咱們想刪除命名空間的話,可使用指令:kubectl delete -f namespace.ymlkubectl delete ns ns名稱

注: 若是將命名空間刪除,那麼存在於該命名空間下的資源會所有被刪除

2)Pod

Pod 是 k8s 中能夠建立和管理的最小單元,是資源對象模型中由用戶穿件或部署的最小資源對象模型,也是在 k8s 上運行容器化應用的資源對象。

在使用 docker 的時候,咱們清楚程序要運行就必須部署在容器中,而在 k8s 中,咱們容器必須存在與 pod 中,pod 就能夠認爲是容器的封裝,一個 pod 能夠存在一個或多個容器。

㈠ Pod 概念
① pod 特性

1. 資源共享

在一個pod 中,多個容器之間能夠共享存儲和網絡,至關於一個邏輯意義上的主機。

2. 生命週期短暫

pod 是一個具備生命週期的組件,若是 pod 所在的節點發生故障,那麼該節點上的pod 都會被調度到其餘節點上,而調度後的pod是一個全新的 pod,與以前沒有任何關係。

3. 平坦的網絡

k8s 集羣中的全部 pod 都在同一個網絡地址空間中,也就是說每一個 pod 均可以經過其餘 pod 的IP地址來實現訪問

② pod 分類
  • 普通 pod

這種就是咱們平常中常常用到的。一旦被建立就會放入 etcd 中存儲,接着就會被調度到任一節點上運行,當 Pod 裏某個容器中止時,Kubernetes 會自動檢測到這個問題而且從新啓動這個 Pod 裏某全部容器, 若是 Pod 所在的 Node 宕機,則會將這個 Node 上的全部 Pod 從新調度到其它節點上。

  • 靜態 pod

靜態pod是由 kubelet 激進型管理的僅存在於特定 node 節點上的,它們不能經過 API server 進行管理,沒法與 controller 控制器 進行管理,而且 kubelet 也沒法對其進行健康檢測。

③ pod 聲明週期

pod中有 5 中生命週期,咱們都須要瞭解一下~

狀態名稱 描述
Pending API Server已經建立了 pod,但 pod 中的一個或多個容器的鏡像尚未建立,包括鏡像下載過程
Running Pod 內全部容器都已建立,且至少一個容器處於運行狀態,正在啓動狀態或正在重啓狀態
Completed Pod 內全部容器均成功執行退出,且不會再重啓
Failed Pod 內全部容器都已退出,但至少一個容器退出失敗
Unknown 因爲某種緣由沒法獲取 Pod 狀態,例如網絡不通
④ pod重啓策略
策略名稱 描述
Always 當容器失效時,有 kubelet 自動重啓該容器
OnFailure 當容器中止運行且退出碼不爲0時,由 kubelet 自動重啓該容器
Never 不論容器運行狀態如何,kubelet 都不會重啓該容器
⑤ pod 資源配置

以前在 docker 咱們有進行測試沒有對 docker 資源進行限額的時候,運行一個 elasticSearch 鏡像的時候服務器直接卡死。那麼在 docker 能作到資源限額,k8s 中天然也能夠。

Kubernetes 中能夠設置限額的計算資源有 CPUMemory 兩種。Kubernetes 咱們想要進行配額限定須要設定兩個參數:RequestLimits

  • Request:表示該資源最小的申請量,系統必須知足要求
  • Limits:表示該資源最大容許使用量,不能超出這個量,當容器試圖使用超過這個量的資源時,就會被 Kubernetes kill 掉並重啓

上面表示一個 nginx 容器最少須要 0.25個CPU和 64 MB內存,最多隻能使用 0.5個CPU和 128 MB內存。

㈡ pod 基操

如下是一份 pod 的完整資源清單:

這份清單大部分看起來會比較陌生,可是有部分關鍵屬性咱們在上面已經講過了,當咱們實際要用的時候若是記不起那麼多咱們可使用指令 kubectl explain pod.xxx 的方式來查看每一個屬性的含義,例如

① 簡單建立

咱們若是想要建立一個 pod ,只須要簡單準備一份 test.yml 文件便可:

而後經過 命令式對象配置 的指令 kubectl create -f test.yml 就能夠獲取到一個含有 nginx 和 centos 容器的pod。而後咱們經過指令kubectl get pod -n cbuc-test 查看當前 pod 的狀態。

docker 能夠用 docker exec -it 進入容器,k8s 也是相似此命令:

kubectl exec -it pod名稱 -c 容器名稱 -n 命名空間 bash

經過以上命令就能夠進入到咱們的pod中

若是 pod 中只有一個容器,-c 能夠不用指定容器名稱

② 屬性說明

上面咱們已經成功的建立了一個 pod,可是這只是一個簡單的 pod 配置,咱們能夠針對該 yaml 文件進行擴展~

1. imagePullPolicy

這個屬性用來設置鏡像拉取策略,在 k8s 中支持三種鏡像拉取策略:

  • Always: 老是從遠程倉庫拉取鏡像
  • IfNotPresent: 本地有則使用本地鏡像,本地沒有則從遠程倉庫拉取鏡像
  • Never: 只使用本地鏡像,從不去遠程倉庫拉取,本地若是不存在就會報錯

注意:

若是鏡像號爲指定版本號,則默認策略爲 :IfNotPresent

若是鏡像號爲 latest ,則默認策略爲: Always

2. command

command 是用於在 pod 中的容器初始化完畢以後運行一個命令。

咱們在上面建立了一個 centos的pod,而後在pod初始化完成後,便會執行 command 中的命令,咱們能夠經過 kubectl exec -it pod名稱 -n 命名空間 bash 而後進入pod中查看 /mnt/test.txt

或者咱們能夠在pod外部執行命令:

kubectl exec pod名稱 -n 命名空間 -c 容器名稱 -- shell命令

3. args

咱們上面說到的 command 已經能夠完成啓動命令和傳遞參數的功能,可是咱們 k8s 中還提供了一個 args 選項,用於傳遞參數。k8s 中使用 command 和 args 兩個參數能夠實現覆蓋 Dockerfile 中的 ENTRYPOINE 的功能。

注意:

  1. 若是 command 和 args 均沒有寫,那麼是使用 Dockerfile 的配置
  2. 若是 command 寫了,args 沒有寫,那麼 Dockerfile 默認的配置會被忽略,執行輸入的 command
  3. 若是 command 沒寫,args 寫了, 那麼 Dockerfile 中配置的 ENTRYPOINT 的命令會被執行,使用當前 args 的參數
  4. 若是 command 和 arg 都寫了,那麼 Dockerfile 的配置就會被忽略,執行 command 命令加上 args 參數

4. env

用於在 pod 中的容器設置環境變量

進入pod查看:

5. ports

ports 在 k8s 的屬性類型是 Object,咱們能夠經過 kubectl explain pod.spec.containers.ports 查看該對象下的屬性:

咱們從圖中能夠發現該對象由5個屬性:

  • containerPort: 容器要監聽的端口(0~65536)
  • hostIP: 要將外部端口綁定到主機IP(通常省略)
  • hostPort: 容器要在主機上公開的端口,若是設置,主機上只能運行容器的一個副本(通常省略)
  • name: 端口名稱,若是指定,必須保證name 在pod中是惟一的
  • protocol: 端口協議,必須是 UDP、TCP或 SCTP,默認爲 TCP

咱們簡單看個 nginx 的例子:

建立方式能夠選擇 3 中建立方式任意一種,而後建立完成後咱們能夠經過 podIp+containerPort 來訪問到 nginx 資源

6. resources

容器中運行的程序須要佔用必定的資源(CPU和內存),在運行的時候若是不對某個容器的資源進行限制,那麼它可能會耗盡服務器的大量資源,防止這種狀況的發生,k8s 中提供了 resource 屬性,對資源進行限制。這個屬性下有兩個子選項:

  • limits: 用於限制運行容器的最大佔用資源,當容器佔用資源超過 limit 時會被終止,並進行重啓
  • requests: 用於設置容器須要的最小資源,若是環境資源不夠,容器將會沒法啓動

看個使用例子:

  • cpu: core數,能夠爲整數或小數
  • memory: 內存大小,可使用 Gi, Mi, G,M 等形式
㈢ pod 擴展
① 生命週期

任何事物的建立過程都有屬於它本身的生命週期,而 pod 對象從建立到銷燬,這段的時間範圍便稱爲 pod 的生命週期。生命週期通常包含下面幾個過程:

運行初始化容器 (init container) 過程

運行主容器 (main container)

2.1 容器啓動後鉤子(post start),容器終止前鉤子(pre stop)

2.2 容器存活性檢測(liveness probe),就緒性檢測(readiness probe)

pod 終止過程

在整個生命週期中,pod 也會相應的出現 5 中狀態,以下:

  • 掛起(Pending): apiServer 已經建立 pod 資源對象,但它還沒有被調度完成或者仍處於下載鏡像的過程當中
  • 運行中(Running): pod 已經被調度至某節點,而且所用容器都已經被 kubelet 建立完成
  • 成功(Succeeded): pod 中的全部容器都已經成功終止而且不會被重啓
  • 失敗(Failed): 全部容器都已經終止,但至少有一個容器終止失敗,即容器返回了非 0 值的退出狀態
  • 未知(UnKnown): apiServer 沒法獲取到 pod 對象的狀態信息,一般是由於網絡通訊失敗致使的

    ⑴ pod 的建立過程

kubernetes 啓動後,不管是 master 節點 亦或者 node 節點,都會將自身的信息存儲到 etcd 數據庫中

  1. 用戶經過 kubectl 或其餘 api 客戶端提交須要建立的 pod 信息給 apiServer
  2. apiServer 接收到信息後會生成 pod 對象信息,並存入 etcd 數據庫中,返回確認消息給客戶端
  3. apiServer 開始反映 etcd 中 pod 對象的變化,其餘組件會使用 watch 機制來跟蹤檢查 apiServer 上的變更
  4. scheduler 發現若是有新的 pod 對象須要建立,便會爲 pod 分配主機並將結果回送至 apiServer
  5. node 節點上的 kubectl 發現有 pod 調度過來,會嘗試調用 docker 啓動容器,並將結果返回給 apiServer
  6. apiServer 將接收到的 pod 狀態信息存入 etcd

⑵ pod 的終止過程

  1. 用戶首先向 apiServer 發送刪除 pod 對象的命令
  2. apiServer 中的pod對象信息會隨着時間的推移而更新,在寬限期內(默認30s),pod 會被視爲 dead 狀態,並將 pod 標記爲 terminating 狀態
  3. kubelet 在監控到 pod 對象轉爲 terminating 狀態的同時啓動 pod 關閉過程
  4. 端點控制器監控到 pod 對象的關閉行爲時將其從全部匹配到此端點的 service 資源的端點列表中移除
  5. 若是當前 pod 對象定義了 preStop 鉤子處理器,則在其標記爲 terminating 後即會以同步的方式啓動執行
  6. pod 對象中的容器進程接收到中止信號,並中止容器
  7. 寬限期結束後,若是 pod 中還存在仍在運行的進程,那麼 pod 對象就會收到當即終止的信號
  8. kubelet 請求 apiServer 將此 pod 資源的寬限期設置爲 0 從而完成刪除操做。

⑶ 初始化容器

初始化容器,看名字也大體可以猜到初始化容器是在 pod 主容器啓動以前要運行的容器,主要是作一些主容器的前置工做。

特徵:

  • 初始化容器必須運行完成直至結束,若是運行失敗便會進行重啓直至成功
  • 初始化容器必須按照順序執行,只有前一個成功後,後一個才能執行

這裏簡單看一個使用例子:

咱們在初始化容器中定義了一個 centos 容器,只有 ping 通對應的地址纔會啓動成功,已知當前網絡能通 192.168.108.101

能夠看到,在初始化容器成功啓動的狀況下,咱們的 nginx 容器也能運行成功,可是若是咱們把 ping 的地址改一下,就會致使初始化容器啓動失敗,那麼正常容器也是會啓動失敗的:

⑷ 鉤子函數

不知道你對鉤子函數這個詞是否有一些瞭解~ 鉤子函數可以感知自身生命週期中的事件,在相應的時刻到來時就會運行用戶指定的程序代碼。

k8s 提供了兩個鉤子函數,分別是啓動以後中止以前

  • post start:容器建立以後執行。若是失敗了會重啓容器
  • pre stop: 容器終止以前執行。執行完成以後容器將成功終止,在其完成以前會阻塞刪除容器的操做

那麼鉤子函數有了,咱們該如何定義這個函數呢?在 k8s 中鉤子函數支持使用三種方式定義動做:

  • exec 命令

在容器中執行一次命令,若是命令執行的退出碼爲0,則認爲程序正常,不然反之。

  • tcpSocket

將會嘗試訪問一個用戶容器的端口,若是可以創建這條鏈接,則認爲程序正常,不然不正常

  • httpGet

調用容器內Web應用的URL,若是返回的狀態碼在200和399之間,則認爲程序正常,不然不正常

② 容器探測

容器探測是用來檢測容器中的應用實例是否正常工做,是保障業務可用性的一種傳統機制。若是通過探測,實例的狀態不符合預期結果,那麼 k8s 就會把這個實例刪除。在 k8s 中也支持了兩種探針來實現容器探測:

  • liveness probes: 存活性探針,用於檢測應用實例當前是否處於正常運行狀態,若是不是,k8s 會重啓容器
  • readiness probe: 就緒性探針,用於檢測應用實例當前是否能夠接受請求,若是不能,k8s不會轉發流量

注意:

livenessProbe 決定了容器是否須要重啓

readinessProbe 決定了是否將請求轉發給容器

這兩種探針支持的檢測方式與上面生命週期檢測的方式同樣:

  • exec 命令

  • TCPSocket

  • httpGet

③ 重啓策略

容器探測 檢測出容器有問題後, k8s 就會對容器所在的 pod 進行重啓,而這些重啓的定義即是由 pod 自身的重啓策略決定的,pod 的重啓策略有以下3種:

  • Always: 容器失效時,自動重啓該容器(默認值)
  • OnFailure: 容器終止運行且退出碼不爲0時重啓
  • Never: 不論狀態爲什麼,都不重啓該容器

首次須要重啓的容器會當即進行重啓,若是隨後還須要重啓,那麼kubectl 便會延遲一段時間後才進行,反覆重啓的操做延遲時長爲 10s,20s,30s,40s,80s,160s和300s,其中300s是最大的延遲時長

㈣ pod 調度

上面說到過默認狀況下,pod 在哪一個 Node 節點上運行是由 Scheduler組件採用相應的算法計算出來的,這個過程是不受人工控制的。可是在實際的使用場景中咱們有時候想要控制某些pod到達某些節點上,而針對於這種需求,k8s 固然也是能夠知足的~ 在 k8s 中它提供了 4 中調度方式:

  • 自動調度:scheduler 組件計算運行在哪一個node節點上
  • 定向調度: 由用戶自定義,須要用到 NodeNameNodeSelector 屬性
  • 親和性調度: 由用戶自定義,須要用到 NodeAffinity、PodAffinity、PodAntiAffinity 屬性
  • 污點容忍調度: 由用戶自定義,須要用到 Taints、Toleration屬性
① 定向調度

咱們能夠利用 nodeName 或者 nodeSelector 來標記 pod 須要調度到指望的 node 節點上。這裏的標記是強制性,無論 node 節點有沒有宕機,都會往這個節點上面調度,所以若是node節點宕機的話,就會致使 pod 運行失敗。

  • NodeName

這個屬性用於強制約束將 Pod 調度到指定名稱的 node節點上,這種方式,其實就是直接跳過 scheduler 的調度邏輯。

上面已經準備了一個 pod 的yaml文件,咱們建立看下是否可以調度到咱們想要的節點上

能夠看到 pod 節點已經成功的調度到名稱爲 node02 的節點上了

  • NodeSelector

這個屬性是用於將 pod 調度到添加了指定標籤上的 node 節點上(k8s 中資源能夠打標籤,咱們同樣能夠對 node 節點打標籤)。它是經過 k8s 的 label-selector 機制實現的,就是說在 pod 建立以前,會由 scheduler 的使用 MatchNodeSelector 的調度策略進行 label 匹配,找出目標 node,而後將 pod 調度到目標節點,該匹配規則也是屬於強制約束。

測試:

首先對 node 節點打上標籤:

kubectl label nodes node02 app=node-dev

查看是否打成功:

而後準備一份 pod yaml文件:

而後咱們建立後查看:

② 親和度調度

上面介紹的定向調度是屬於強制性約束,若是沒有知足的node節點供運行的話,pod 就是啓動失敗,這樣子就很大地限制了它的使用場景。因此咱們接下來介紹的 親和度調度 (Affinity) 即是用來解決這種問題的。

它是經過配置的形式,實現優先選擇知足條件的 Node 進行調度,若是有就調度到對應節點,若是沒有,也能夠調度到不知足條件的節點上,這樣可使調度更加靈活

Affinity分爲三大類:

  • nodeAffinity(node親和性)

node爲目標,解決 pod 能夠調度到哪些 node 的問題

這個屬性中又存在 requiredDuringSchedulingIgnoredDuringExecution (硬限制)preferredDuringSchedulingIgnoredDuringExecution (軟限制) 兩種

Ⅰ、requiredDuringSchedulingIgnoredDuringExecution (硬限制)

這個限制和上面說到的定向調度有點像,只選擇知足條件的 node 節點進行調度,使用例子以下:

上面咱們建立了一個 pod,會在標籤 keyapp,且valuenode-pro 或 node-test 的節點上選擇,可是並不存在具有這個標籤的節點,所以這個pod 一直處於掛起的狀態~

咱們上面看到了一個新的屬性 matchExpressions,這個是用來編寫關係表達式的,具體使用方法以下:

- matchExpressions:
  - key: app # 匹配存在標籤的key爲 app 的節點
    operator: Exists
  - key: app # 匹配標籤的key爲 app ,且value是"xxx"或"yyy"的節點
    operator: In
    values: ["xxx","yyy"]
  - key: app # 匹配標籤的key爲 app, 且value大於"xxx"的節點
    operator: Gt
    values: "xxx"

Ⅱ、 preferredDuringSchedulingIgnoredDuringExecution (軟限制)

上面已經瞭解到了 硬限制 的使用,軟限制 的使用以下,咱們直接來看 yaml 文件:

這邊能夠看到雖然不存在知足條件的node,可是也是能夠成功運行pod 的,只是調度到了不知足條件的 node 上!

咱們來總結一下硬限制和軟限制的用法:

  • podAffinity(pod 親和性)

以 pod 爲目標,解決pod能夠和哪些已存在的pod部署在同一個拓撲域中的問題。

podAffinity 一樣也存在 硬限制 和 軟限制 ,咱們接下來直接看下如何配置:

image-20210423130432962

上面即是 podAffinity 硬限制的yaml文件,除了眼熟的屬性以外,咱們還看到了一個新的屬性 topologyKey,那麼這個屬性是用來幹嗎的呢?

topologyKey 用於指定調度時做用域:

  • 若是值爲 kubernetes.io/hostname ,說明是以 node 節點爲區分範圍
  • 若是值爲 kubernetes.io/os, 則以 node 節點的操做系統來區分

瞭解完硬限制的編寫,軟限制也是與上面 node親和度的用法類似,這裏再也不贅訴~

  • podAntiAffinity(pod反親和性)

以pod 爲目標,解決pod不能和哪些已存在的pod部署在同一個拓撲域中的問題。

這個使用就是和上面基本一致了,就是和 podAffinity 要求反着來就是了,屬性名換個就完事了~

這個yaml文件表明的含義即是選擇不和標籤帶有 app=test01app=test02 的pod "共處一室"。一樣存在硬限制和軟限制的配置

親和性反親和性 的使用場景

親和性: 若是兩個應用交互頻繁,那就有必要利用親和性讓兩個應用盡量的靠近,能夠減小由於網絡通訊而帶來的性能損耗

反親和性: 當應用採用多副本部署的時候,有必要採用反親和性讓各個應用實例打散分佈在各個 node 上,這樣能夠提升服務的高可用性

③ 污點(Taint)

咱們先來看下目前 pod 存在於每一個節點的狀況,

是否發現了一個問題,那就是 pod 基本都分佈在了 node 節點上,而 master 節點卻沒有運行任何pod。而這個緣由即是和咱們要講到的污點 有關係了!

咱們前面說到的調度都是站在 pod 的角度,讓 pod 選擇 node 進行運行,而污點很好的進行了反轉。讓node節點決定讓哪些pod能夠調度過來!

Node 能夠設置 污點 ,設置上 污點 以後,就會和 pod 之間造成了一種排斥關係。這種關係存在的意義即是能夠拒絕 pod 調度進來,也能夠將已經存在的 pod 驅逐出去。

污點格式: key=value:effect

keyvalue 是污點的標籤,而 effect 則是用來描述污點的做用,支持三種功能定義:

  • PreferNoSchedule

    k8s將盡可能避免把 Pod 調度到具備該污點的 node 節點上,除非沒有其餘節點能夠調度。(儘可能不要來,除非沒辦法)

  • NoScheduler

    k8s 將不會把 Pod 調度到具備該污點的 node 節點上,但不會影響當前 Node 上已經存在的 pod。(新的不要來,在這的就別動了)

  • NoExecute

    k8s 將不會把 Pod 調度到具備該污點的 node 節點上,同時也會將 Node 上已經存在的 Pod 驅逐。(新的不要來,在這的趕忙走)

設置污點命令以下:

# 設置污點
kubectl taint nodes node01 key=value:effect

# 去除污點
kubectl taint nodes node01 key:effect-

# 去除全部污點
kubectl taint nodes node01 key-

而 k8s中的 master節點之因此沒有運行任何pod,那即是由於 master 節點上已經存在了污點:

④ 容忍(Toleration)

上面說到若是 node 節點存在污點,那麼pod就會沒法調度。那若是 pod 有時候就是想 "厚着臉皮",哪怕你存在污點,也不嫌棄的想要調度進去有沒有辦法解決呢?

k8s 也是想到了這種狀況的存在,所以便有了一個 容忍 的屬性!

污點就是拒絕,容忍就是忽略,Node 經過污點來拒絕 pod 調度上去,pod 經過容忍忽略拒絕

咱們先給 node01 打上 NoExecute 的污點,而後咱們再給 pod 添加容忍,看下是否可以成功調度上去

pod yaml:

經過添加容忍後,咱們能夠發現pod 在 node01 的節點上成功運行了,說明容忍成功~

容忍的配置信息以下:

tolerations:
- key         # 對應着要容忍的污點的鍵,空意味着匹配全部的鍵
  value        # 對應着要容忍的污點值
  operator    # key-value 的運算符,支持 Equal 和 Exists(默認)
  effect    # 對應污點的effect,空意味着匹配全部的影響
  tolerationSeconds  # 容忍時間,當 effect 爲NoExecute 時生效,表示 pod 在Node上的停留時間

END

關於 k8s 中 pod 的介紹到這裏就結束啦~我的以爲仍是挺詳細的,若是可以認真看下來,相信對 pod 已經有足夠了解了。可是你認爲 k8s 到這裏就結束了嗎?那確定不會的,礙於篇幅,因此其餘資源組件留到下一節介紹~請動動小手,點點關注不迷路。路漫漫,小菜與你一同求索!

今天的你多努力一點,明天的你就能少說一句求人的話!

我是小菜,一個和你一塊兒學習的男人。 💋

微信公衆號已開啓,小菜良記,沒關注的同窗們記得關注哦!

相關文章
相關標籤/搜索