主頁 > 軟體設計 > linux12k8s --> 06Pod詳解

linux12k8s --> 06Pod詳解

2021-08-08 07:26:56 軟體設計

文章目錄

    • Pod詳解
      • 一、Pod介紹
        • 1、pod的結構
        • 2、Pod定義
          • 1、下面是Pod的資源清單:
          • 2、查看每種資源的可配置項
          • 3、案例
            • 1、案例1 -- 部署nginx、tomcat
            • 2、案例2 -- wordpress
          • 4、kubernetes沒有提供單獨運行Pod的命令,都是通過Pod控制器來實作的
            • 1、 **查看pod資訊**
            • 2、訪問Pod
            • 3、洗掉指定Pod
            • 3、配置操作
        • 3、Pod存在的意義
        • 4、Pod實作機制
      • 二、Pod配置
        • 1、基本配置
        • 2、鏡像拉取
          • 1、三種拉取策略(重啟策略)
        • 3、啟動命令
          • 1、創建pod-command.yaml檔案,內容如下:
          • 2、command,用于在pod中的容器初始化完畢之后運行一個命令,
          • 3、總結說明
        • 4、環境變數
          • 1、創建pod-env.yaml檔案,內容如下:
          • 2、env,環境變數,用于在pod中的容器設定環境變數,
        • 5、埠設定
          • 1、首先看下ports支持的子選項:
          • 2、撰寫一個測驗案例,創建pod-ports.yaml
        • 6、資源配額
          • 1、撰寫一個測驗案例,創建pod-resources.yaml
          • 2、在這對cpu和memory的單位做一個說明:
        • 三、Pod生命周期
          • 1、pod的生命周期
          • 2、在整個生命周期中,Pod會出現5種**狀態**(**相位**),
        • 3、創建和終止
          • 1、pod的創建程序
          • 2、pod的終止程序
          • 3、初始化容器
            • 1、創建pod-initcontainer.yaml,內容如下:
          • 4、鉤子函式
        • 4、容器探測
          • **方式一:Exec**
            • 1、創建pod-liveness-exec.yaml
            • 2、 創建pod,觀察效果
          • **方式二:TCPSocket**
            • 1、創建pod-liveness-tcpsocket.yaml
            • 2、創建pod,觀察效果
          • **方式三:HTTPGet**
          • 1、創建pod-liveness-httpget.yaml
          • 2、創建pod,觀察效果
        • 5、重啟策略
          • 1、創建pod-restartpolicy.yaml:
          • 2、運行Pod測驗
          • 3、Pod是如何管理多個容器的
          • 4、Pod中資料持久性
      • 四、Pod調度
        • 1、定向調度
          • 1、NodeName
          • 2、NodeSelector
            • 1 首先分別為node節點添加標簽
            • 2 創建一個pod-nodeselector.yaml檔案,并使用它創建Pod
        • 2、親和性調度
          • 3、NodeAffinity
            • 1、接下來首先演示一下`requiredDuringSchedulingIgnoredDuringExecution` ,
            • 2、接下來再演示一下`requiredDuringSchedulingIgnoredDuringExecution`
          • 4、PodAffinity
            • 1、首先來看一下`PodAffinity`的可配置項
            • 2、接下來,演示下`requiredDuringSchedulingIgnoredDuringExecution`,
          • 5、PodAntiAffinity
            • 1、繼續使用上個案例中目標pod
            • 2、創建pod-podantiaffinity-required.yaml,內容如下:
        • 3、污點和容忍
          • 1、污點(Taints)
          • 2、容忍(Toleration)
            • 1、創建pod-toleration.yaml,內容如下
            • 2、下面看一下容忍的詳細配置:
      • 五、 Pod控制器詳解
        • 1、Pod控制器介紹
        • 2、ReplicaSet(RS)
          • **1、創建ReplicaSet**
          • **2、擴縮容**
          • **3、鏡像升級**
          • **4、洗掉ReplicaSet**
        • 3、Deployment(Deploy)
          • **1、創建deployment**
          • **2、擴縮容**
          • **3、鏡像更新**
          • 4、重建更新
          • 5、滾動更新
          • 6、滾動更新的程序:
          • **7、版本回退**
          • **8、金絲雀發布**
        • 4、Horizontal Pod Autoscaler(HPA)
          • **1 、安裝metrics-server**
          • **2、 準備deployment和servie**
          • **3 、部署HPA**
          • **4 、測驗**
        • 5、DaemonSet(DS)
        • 6、Job
          • 7、CronJob(CJ)
          • 1、CronJob的資源清單檔案:
          • 2、需要重點解釋的幾個選項:
          • 3、創建pc-cronjob.yaml,內容如下:
          • 4、查看

Pod詳解

一、Pod介紹

1、pod的結構

在這里插入圖片描述

每個Pod中都可以包含一個或者多個容器,這些容器可以分為兩類:

# 主容器 pause 
# 業務容器  user container1 user container2 
  • 用戶程式所在的容器,數量可多可少

  • Pause容器,這是每個Pod都會有的一個根容器,它的作用有兩個:

    • 可以以它為依據,評估整個Pod的健康狀態
  • 可以在根容器上設定Ip地址,其它容器都此Ip(Pod IP),以實作Pod內部的網路通信

這里是Pod內部的通訊,Pod的之間的通訊采用虛擬二層網路技術來實作,我們當前環境用的是Flannel,

2、Pod定義

1、k8s集群中部署的最小單元

2、Pod最主要的功能管理是將一個業務或者一個呼叫鏈的所有服務(容器)

3、包含多個容器(一組容器的集合)

4、一個Pod中容器共享網路命名空間,Pod是短暫的

Pod是在集群中運行部署應用或服務的最小單元,他是可以支持很多容器的,Pod的設計理念是支持多個容器在一個Pod中共享網路地址和檔案系統,可以通過行程間通信和檔案共享這種簡單高效的方式組合完成服務,

比如:你運行一個作業系統發行版的軟體倉庫,一個nginx容器用來發布軟體,另一個容器專門用來從源倉庫做同步,這兩個容器的鏡像不太可能是一個團隊開發的,但是他們一塊作業才能提供一個微服務,這種情況下,不同的團隊各自開發構建自己的容器鏡像,在部署的時候組合成一個微服務對外提供服務,這就是k8s中的Pod,
目前k8s中業務主要可以分為長期伺服型(long-running)、批處理型(batch)、節點后臺支撐型(node-daemon)和有狀態應用型(stateful application);分別對應的小機器人控制器為Deployment、Job、DaemonSet 和 StatefulSet,

# Pod是k8s中最小部署單元,用來管理一個呼叫鏈的容器,它之中的主容器(pause)為整個呼叫鏈的容器提供基礎網路,共享存盤,監控業務容器的運行狀態

1、k8s中的命名規范

1、必須小寫
2、必須以字母開頭
3、名稱當中只能夠包含字母、數字和中劃線(-)

1、下面是Pod的資源清單:
apiVersion: v1     #必選,版本號,例如v1
kind: Pod         #必選,資源型別,例如 Pod
metadata:         #必選,元資料
  name: string     #必選,Pod名稱
annotations:       #選做,描述資訊
  nginx: nginx
  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: #需要暴露的埠庫號串列
    - name: string        #埠的名稱
      containerPort: 80  #容器需要監聽的埠號
      hostPort: int       #容器所在主機需要監聽的埠號,默認與Container相同
      protocol: string    #埠協議,支持TCP和UDP,默認TCP
    env:   #容器運行前需設定的環境變數串列
    - name: string  #環境變數名稱
      value: string #環境變數的值
    resources: #資源限制和請求的設定
      limits:  #資源限制的設定
        cpu: string     #Cpu的限制,單位為core數,將用于docker run --cpu-shares引數
        memory: string  #記憶體限制,單位可以為Mib/Gib,將用于docker run --memory引數
      requests: #資源請求的設定
        cpu: string    #Cpu請求,容器啟動的初始可用數量
        memory: string #記憶體請求,容器啟動的初始可用數量
    lifecycle: #生命周期鉤子
		postStart: #容器啟動后立即執行此鉤子,如果執行失敗,會根據重啟策略進行重啟
		preStop: #容器終止前執行此鉤子,無論結果如何,容器都會終止
    livenessProbe:  #對Pod內各容器健康檢查的設定,當探測無回應幾次后將自動重啟該容器
      exec:         #對Pod容器內檢查方式設定為exec方式
        command: [string]  #exec方式需要制定的命令或腳本
      httpGet:       #對Pod內個容器健康檢查方法設定為HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     #對Pod內個容器健康檢查方式設定為tcpSocket方式
         port: number
       initialDelaySeconds: 0       #容器啟動完成后首次探測的時間,單位為秒
       timeoutSeconds: 0          #對容器健康檢查探測等待回應的超時時間,單位秒,默認1秒
       periodSeconds: 0           #對容器監控檢查的定期探測時間設定,單位秒,默認10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged: false
  restartPolicy: [Always | Never | OnFailure]  #Pod的重啟策略
  nodeName: <string> #設定NodeName表示將該Pod調度到指定到名稱的node節點上
  nodeSelector: obeject #設定NodeSelector表示將該Pod調度到包含這個label的node上
  imagePullSecrets: #Pull鏡像時使用的secret名稱,以key:secretkey格式指定
  - name: string
  hostNetwork: false   #是否使用主機網路模式,默認為false,如果設定為true,表示使用宿主機網路
  volumes:   #在該pod上定義共享存盤卷串列
  - name: string    #共享存盤卷名稱 (volumes型別有很多種)
    emptyDir: {}       #型別為emtyDir的存盤卷,與Pod同生命周期的一個臨時目錄,為空值
    hostPath: string   #型別為hostPath的存盤卷,表示掛載Pod所在宿主機的目錄
      path: string                #Pod所在宿主機的目錄,將被用于同期中mount的目錄
    secret:          #型別為secret的存盤卷,掛載集群與定義的secret物件到容器內部
      scretname: string  
      items:     
      - key: string
        path: string
    configMap:         #型別為configMap的存盤卷,掛載預定義的configMap物件到容器內部
      name: string
      items:
      - key: string
        path: string
2、查看每種資源的可配置項
#	在這里,可通過一個命令來查看每種資源的可配置項
#   kubectl explain 資源型別         查看某種資源可以配置的一級屬性
#	kubectl explain 資源型別.屬性     查看屬性的子屬性
[root@k8s-m-01 ~]# kubectl explain pod
KIND:     Pod
VERSION:  v1
FIELDS:
   apiVersion   <string>
   kind <string>
   metadata     <Object>
   spec <Object>
   status       <Object>

[root@k8s-m-01 ~]# kubectl explain pod.metadata
KIND:     Pod
VERSION:  v1
RESOURCE: metadata <Object>
FIELDS:
   annotations  <map[string]string>
   clusterName  <string>
   creationTimestamp    <string>
   deletionGracePeriodSeconds   <integer>
   deletionTimestamp    <string>
   finalizers   <[]string>
   generateName <string>
   generation   <integer>
   labels       <map[string]string>
   managedFields        <[]Object>
   name <string>
   namespace    <string>
   ownerReferences      <[]Object>
   resourceVersion      <string>
   selfLink     <string>
   uid  <string>
3、案例
1、案例1 – 部署nginx、tomcat
# kubectl explain Pod  #查apiVersion版本號 v1
[root@k8s-m-01 ~]# vim pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
    - name: nginx
      image: nginx
    - name: tomcat
      image: tomcat
2、案例2 – wordpress
# 1、nginx  PHP  MySQL
# 2、 制作鏡像
# 3、創建nginx組態檔,然后構建鏡像
# 4、撰寫配置清單,部署
[root@k8s-m-01 ~]# vim wordpress.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: wordpress
spec:
  containers:
    - name: nginx
      image: nginx
    - name: php
      image: alvinos/php:v2-fpm-mysql
    - name: mysql
      image: mysql:5.7
      env:
        - name: MYSQL_ROOT_PASSWORD
          value: "123"

# k8s部署一個yaml的應用:kubectl apply -f [配置清單]
[root@k8s-m-01 ~]# kubectl apply -f pod.yaml 
pod/test-pod create

ImgPullErr :         # 鏡像拉取失敗
ContainerCreating : # 容器創建中

# 擴展 1、進入不是默認空間的容器
[root@k8s-m-01 ~]# kubectl get pod -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-5c767764f5-fq47c   1/1     Running   2          78m
[root@k8s-m-01 ~]# kubectl exec -it pc-deployment-5c767764f5-fq47c -n dev -c nginx -- bash
root@pc-deployment-5c767764f5-fq47c:/# curl localhost
<h1>Welcome to nginx!</h1>

# 2、權限問題
[root@k8s-m-01 ~]# ll -a
drwxr-xr-x   3 root root   33 Jul 30 14:43 .kube
# 必須要有這個檔案,否則無法創建洗掉pod

在kubernetes中基本所有資源的一級屬性都是一樣的,主要包含5部分:

  • apiVersion <string> 版本,由kubernetes內部定義,版本號必須可以用 kubectl api-versions 查詢到

  • kind <string> 型別,由kubernetes內部定義,版本號必須可以用 kubectl api-resources 查詢到

  • metadata <Object> 元資料,主要是資源標識和說明,常用的有name、namespace、labels等

  • spec <Object> 描述,這是配置中最重要的一部分,里面是對各種資源配置的詳細描述

  • status <Object> 狀態資訊,里面的內容不需要定義,由kubernetes自動生成

在上面的屬性中,spec是接下來研究的重點,繼續看下它的常見子屬性:

  • containers <[]Object> 容器串列,用于定義容器的詳細資訊
  • nodeName <String> 根據nodeName的值將pod調度到指定的Node節點上
  • nodeSelector <map[]> 根據NodeSelector中定義的資訊選擇將該Pod調度到包含這些label的Node 上
  • hostNetwork <boolean> 是否使用主機網路模式,默認為false,如果設定為true,表示使用宿主機網路
  • volumes <[]Object> 存盤卷,用于定義Pod上面掛在的存盤資訊
  • restartPolicy <string> 重啟策略,表示Pod在遇到故障的時候的處理策略
4、kubernetes沒有提供單獨運行Pod的命令,都是通過Pod控制器來實作的
# 命令格式: kubectl run (pod控制器名稱) [引數] 
# --image  指定Pod的鏡像
# --port   指定埠
# --namespace  指定namespace
[root@k8s-m-01 ~]# kubectl run nginx --image=nginx:latest --port=80 --namespace dev 
deployment.apps/nginx created
1、 查看pod資訊
# 1、查看Pod基本資訊
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          43s

# 2、查看Pod的詳細資訊
[root@k8s-m-01 ~]# kubectl describe pod nginx -n dev
Name:         nginx
Namespace:    dev
Priority:     0
Node:         node1/192.168.5.4
Start Time:   Wed, 08 May 2021 09:29:24 +0800
Labels:       pod-template-hash=5ff7956ff6
              run=nginx
Annotations:  <none>
Status:       Running
IP:           10.244.1.23
IPs:
  IP:           10.244.1.23
Controlled By:  ReplicaSet/nginx
Containers:
  nginx:
    Container ID:   docker://4c62b8c0648d2512380f4ffa5da2c99d16e05634979973449c98e9b829f6253c
    Image:          nginx:latest
    Image ID:       docker-pullable://nginx@sha256:485b610fefec7ff6c463ced9623314a04ed67e3945b9c08d7e53a47f6d108dc7
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Wed, 08 May 2021 09:30:01 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-hwvvw (ro)
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  default-token-hwvvw:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-hwvvw
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason     Age        From               Message
  ----    ------     ----       ----               -------
  Normal  Scheduled  <unknown>  default-scheduler  Successfully assigned dev/nginx-5ff7956ff6-fg2db to node1
  Normal  Pulling    4m11s      kubelet, node1     Pulling image "nginx:latest"
  Normal  Pulled     3m36s      kubelet, node1     Successfully pulled image "nginx:latest"
  Normal  Created    3m36s      kubelet, node1     Created container nginx
  Normal  Started    3m36s      kubelet, node1     Started container nginx
2、訪問Pod
# 1、獲取pod IP
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME    READY   STATUS    RESTARTS   AGE    IP             NODE    ... 
nginx   1/1     Running   0          190s   10.244.1.23   node1   ...

# 2、訪問POD
[root@k8s-m-01 ~]# curl http://10.244.1.23:80
<!DOCTYPE html>
<html>
<head>
	<title>Welcome to nginx!</title>
</head>
<body>
	<p><em>Thank you for using nginx.</em></p>
</body>
</html>
3、洗掉指定Pod
# 1、洗掉指定Pod
[root@k8s-m-01 ~]# kubectl delete pod nginx -n dev
pod "nginx" deleted

# 2、此時,顯示洗掉Pod成功,但是再查詢,發現又新產生了一個 
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          21s

# 這是因為當前Pod是由Pod控制器創建的,控制器會監控Pod狀況,一旦發現Pod死亡,會立即重建
# 此時要想洗掉Pod,必須洗掉Pod控制器

# 3、先來查詢一下當前namespace下的Pod控制器
[root@k8s-m-01 ~]# kubectl get deploy -n  dev
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           9m7s

# 4、接下來,洗掉此PodPod控制器
[root@k8s-m-01 ~]# kubectl delete deploy nginx -n dev
deployment.apps "nginx" deleted

# 5、稍等片刻,再查詢Pod,發現Pod被洗掉了
[root@k8s-m-01 ~]# kubectl get pods -n dev
No resources found in dev namespace.
3、配置操作

創建一個pod-nginx.yaml,內容如下:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
spec:
  containers:
  - image: nginx:latest
    name: pod
    ports:
    - name: nginx-port
      containerPort: 80
      protocol: TCP

然后就可以執行對應的創建和洗掉命令了:

# 創建:kubectl create -f pod-nginx.yaml

# 洗掉:kubectl delete -f pod-nginx.yaml

3、Pod存在的意義

# 1、創建容器使用docker,一個docker對應一個容器,一個容器有行程,一個容器運行一個應用程式
# 2、pod是多行程,運行多個應用程式
# 3、一個Pod有多個容器,每個容器里面運行一個應用程式
# 4、Pod存在未來親密性應用

 1、兩個應用之間進行互動
 2、網路之間呼叫
 3、兩個應用需要頻繁呼叫

4、Pod實作機制

1、共享網路 === 》 容器本身之間相互隔離的

2、共享存盤

# 1、共享網路
通過Pause容器,把其他業務容器加入Pause容器里面,讓所有業務中在同一個名稱空間中,可以實作網路共享
# 2、共享存盤
引入資料卷概念volumes,用資料卷進行持久化資料存盤

二、Pod配置

主要來研究pod.spec.containers屬性,這也是pod配置中最為關鍵的一項配置,

[root@k8s-m-01 ~]# kubectl explain pod.spec.containers
KIND:     Pod
VERSION:  v1
RESOURCE: containers <[]Object>   # 陣列,代表可以有多個容器
FIELDS:
   name  <string>     # 容器名稱
   image <string>     # 容器需要的鏡像地址
   imagePullPolicy  <string> # 鏡像拉取策略 
   command  <[]string> # 容器的啟動命令串列,如不指定,使用打包時使用的啟動命令
   args     <[]string> # 容器的啟動命令需要的引數串列
   env      <[]Object> # 容器環境變數的配置
   ports    <[]Object>     # 容器需要暴露的埠號串列
   resources <Object>      # 資源限制和資源請求的設定

1、基本配置

創建pod-base.yaml檔案,內容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-base
  namespace: dev
  labels:
    user: heima
spec:
  containers:
  - name: nginx
    image: nginx
  - name: busybox
    image: busybox:1.30

上面定義了一個比較簡單Pod的配置,里面有兩個容器:

  • nginx:用nginx版本的nginx鏡像創建, (nginx是一個輕量級web容器)
  • busybox:用1.30版本的busybox鏡像創建,(busybox是一個小巧的linux命令集合)
# 1、創建Pod
[root@master pod]# kubectl apply -f pod-base.yaml
pod/pod-base created

# 2、查看Pod狀況
# READY 1/2 : 表示當前Pod中有2個容器,其中1個準備就緒,1個未就緒
# RESTARTS  : 重啟次數,因為有1個容器故障了,Pod一直在重啟試圖恢復它

[root@master pod]# kubectl get pod -n dev
NAME       READY   STATUS    RESTARTS   AGE
pod-base   1/2     Running   4          95s

# 3、可以通過describe查看內部的詳情
# 此時已經運行起來了一個基本的Pod,雖然它暫時有問題
[root@master pod]# kubectl describe pod pod-base -n dev

2、鏡像拉取

創建pod-imagepullpolicy.yaml檔案,內容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-imagepullpolicy
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: Always # 用于設定鏡像拉取策略
  - name: busybox
    image: busybox:1.30
1、三種拉取策略(重啟策略)

imagePullPolicy,用于設定鏡像拉取策略,kubernetes支持配置三種拉取策略:

# 1、IfNotPresent:(默認值)
本地有則使用本地鏡像,本地沒有則從遠程倉庫拉取鏡像(本地有就本地,本地沒遠程下載)
# 2. Always:
創建Pod都會重新從遠程倉庫拉取一次鏡像(一直遠程下載)
# 3. Never:
只使用本地鏡像,從不去遠程倉庫拉取,本地沒有就報錯 (一直使用本地)
# 1、20版本后默認的是Onfailure :當容器終止且退出碼部位0,則kubetle則重新啟動容器

默認值說明:

? 如果鏡像tag為具體版本號, 默認策略是:IfNotPresent

? 如果鏡像tag為:latest(最終版本) ,默認策略是always

# 1、創建Pod
[root@master pod]# kubectl create -f pod-imagepullpolicy.yaml
pod/pod-imagepullpolicy created

# 2、查看Pod詳情
# 此時明顯可以看到nginx鏡像有一步Pulling image "nginx"的程序
[root@master pod]# kubectl describe pod pod-imagepullpolicy -n dev
......
Events:
  Type     Reason     Age               From               Message
  ----     ------     ----              ----               -------
  Normal   Scheduled  <unknown>         default-scheduler  Successfully assigned dev/pod-imagePullPolicy to k8s-n-01
  Normal   Pulling    32s               kubelet, k8s-n-01     Pulling image "nginx"
  Normal   Pulled     26s               kubelet, k8s-n-01     Successfully pulled image "nginx"
  Normal   Created    26s               kubelet, k8s-n-01     Created container nginx
  Normal   Started    25s               kubelet, k8s-n-01     Started container nginx
  Normal   Pulled     7s (x3 over 25s)  kubelet, k8s-n-01     Container image "busybox:1.30" already present on machine
  Normal   Created    7s (x3 over 25s)  kubelet, k8s-n-01     Created container busybox
  Normal   Started    7s (x3 over 25s)  kubelet, k8s-n-01     Started container busybox

3、啟動命令

   # 在前面的案例中,一直有一個問題沒有解決,就是的busybox容器一直沒有成功運行,那么到底是什么原因導致這個容器的故障呢?
   原來busybox并不是一個程式,而是類似于一個工具類的集合,kubernetes集群啟動管理后,它會自動關閉,
   
   # 解決方法就是讓其一直在運行,這就用到了command配置,
1、創建pod-command.yaml檔案,內容如下:
apiVersion: v1
kind: Pod
metadata:
  name: pod-command
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;"]
 
 # 注:
    "/bin/sh","-c",  使用sh執行命令
   touch /tmp/hello.txt;   創建一個/tmp/hello.txt 檔案
   while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;  每隔3秒向檔案中寫入當前時間
2、command,用于在pod中的容器初始化完畢之后運行一個命令,
# 1、創建Pod
[root@master pod]# kubectl create  -f pod-command.yaml
pod/pod-command created

# 2、查看Pod狀態
# 此時發現兩個pod都正常運行了
[root@master pod]# kubectl get pods pod-command -n dev
NAME          READY   STATUS   RESTARTS   AGE
pod-command   2/2     Runing   0          2s

# 3、進入pod中的busybox容器,查看檔案內容

# 補充一個命令: kubectl exec  pod名稱 -n 命名空間 -it -c 容器名稱 /bin/sh  在容器內部執行命令
# 使用這個命令就可以進入某個容器的內部,然后進行相關操作了
# 可以查看txt檔案的內容
[root@master pod]# kubectl exec pod-command -n dev -it -c busybox /bin/sh
/ # tail -f /tmp/hello.txt
13:35:35
13:35:38
13:35:41
3、總結說明
通過上面發現command已經可以完成啟動命令和傳遞引數的功能,為什么這里還要提供一個args選項,用于傳遞引數呢?這其實跟docker有點關系,kubernetes中的command、args兩項其實是實作覆寫Dockerfile中ENTRYPOINT的功能,
 # 1 如果command和args均沒有寫,那么用Dockerfile的配置,
 # 2 如果command寫了,但args沒有寫,那么Dockerfile默認的配置會被忽略,執行輸入的command
 # 3 如果command沒寫,但args寫了,那么Dockerfile中配置的ENTRYPOINT的命令會被執行,使用當前args的引數
 # 4 如果command和args都寫了,那么Dockerfile的配置被忽略,執行command并追加上args引數

4、環境變數

1、創建pod-env.yaml檔案,內容如下:
apiVersion: v1
kind: Pod
metadata:
  name: pod-env
  namespace: dev
spec:
  containers:
  - name: busybox
    image: busybox:1.30
    command: ["/bin/sh","-c","while true;do /bin/echo $(date +%T);sleep 60; done;"]
    env: # 設定環境變數串列
    - name: "username"
      value: "admin"
    - name: "password"
      value: "123456"
2、env,環境變數,用于在pod中的容器設定環境變數,
# 1、創建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-env.yaml
pod/pod-env created

# 2、進入容器,輸出環境變數
[root@k8s-m-01 ~]# kubectl exec pod-env -n dev -c busybox -it /bin/sh
/ # echo $username
admin
/ # echo $password
123456

這種方式不是很推薦,推薦將這些配置單獨存盤在組態檔中,這種方式將在后面介紹,

5、埠設定

埠設定就是containers的ports選項

1、首先看下ports支持的子選項:
[root@k8s-m-01 ~]# kubectl explain pod.spec.containers.ports
KIND:     Pod
VERSION:  v1
RESOURCE: ports <[]Object>
FIELDS:
   name         <string>  # 埠名稱,如果指定,必須保證name在pod中是唯一的		
   containerPort<integer> # 容器要監聽的埠(0<x<65536)
   hostPort     <integer> # 容器要在主機上公開的埠,如果設定,主機上只能運行容器的一個副本(一般省略) 
   hostIP       <string>  # 要將外部埠系結到的主機IP(一般省略)
   protocol     <string>  # 埠協議,必須是UDP、TCP或SCTP,默認為“TCP”,
2、撰寫一個測驗案例,創建pod-ports.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-ports
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx
    ports: # 設定容器暴露的埠串列
    - name: nginx-port
      containerPort: 80
      protocol: TCP
# 1、創建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-ports.yaml
pod/pod-ports created

# 2、查看pod
# 在下面可以明顯看到配置資訊
[root@k8s-m-01 ~]# kubectl get pod pod-ports -n dev -o yaml
......
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: nginx
    ports:
    - containerPort: 80
      name: nginx-port
      protocol: TCP
......

訪問容器中的程式需要使用的是podIp:containerPort

6、資源配額

容器中的程式要運行,肯定是要占用一定資源的,比如cpu和記憶體等,如果不對某個容器的資源做限制,那么它就可能吃掉大量資源,導致其它容器無法運行,
針對這種情況,kubernetes提供了對記憶體和cpu的資源進行配額的機制,這種機制主要通過resources選項實作,他有兩個子選項:
  • limits:用于限制運行時容器的最大占用資源,當容器占用資源超過limits時會被終止,并進行重啟

  • requests :用于設定容器需要的最小資源,如果環境資源不夠,容器將無法啟動

可以通過上面兩個選項設定資源的上下限,

1、撰寫一個測驗案例,創建pod-resources.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-resources
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx
    resources: # 資源配額
      limits:  # 限制資源(上限)
        cpu: "2" # CPU限制,單位是core數
        memory: "10Gi" # 記憶體限制
      requests: # 請求資源(下限)
        cpu: "1"  # CPU限制,單位是core數
        memory: "10Mi"  # 記憶體限制
2、在這對cpu和memory的單位做一個說明:

cpu:core數,可以為整數或小數

memory: 記憶體大小,可以使用Gi、Mi、G、M等形式

# 1、運行Pod
[root@k8s-m-01 ~]# kubectl create  -f pod-resources.yaml
pod/pod-resources created

# 2、查看發現pod運行正常
[root@k8s-m-01 ~]# kubectl get pod pod-resources -n dev
NAME            READY   STATUS    RESTARTS   AGE  
pod-resources   1/1     Running   0          39s   

# 3、停止(洗掉)Pod
[root@k8s-m-01 ~]# kubectl delete  -f pod-resources.yaml
pod "pod-resources" deleted

# 4、編輯pod,修改resources.requests.memory的值為10Gi
[root@k8s-m-01 ~]# vim pod-resources.yaml

# 5、再次啟動pod
[root@k8s-m-01 ~]# kubectl create  -f pod-resources.yaml
pod/pod-resources created

# 6、查看Pod狀態,發現Pod啟動失敗
[root@k8s-m-01 ~]# kubectl get pod pod-resources -n dev -o wide
NAME            READY   STATUS    RESTARTS   AGE          
pod-resources   0/2     Pending   0          20s    

# 7、查看pod詳情會發現,如下提示
[root@k8s-m-01 ~]# kubectl describe pod pod-resources -n dev
......
Warning  FailedScheduling  <unknown>  default-scheduler  0/2 nodes are available: 2 Insufficient memory.(記憶體不足)

三、Pod生命周期

1、pod的生命周期

我們一般將pod物件從創建至終的這段時間范圍稱為pod的生命周期,它主要包含下面的程序:

  • pod創建程序

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

  • 運行主容器(main container)

    • 容器啟動后鉤子(post start)、容器終止前鉤子(pre stop)

    • 容器的存活性探測(liveness probe)、就緒性探測(readiness probe)

  • pod終止程序
    在這里插入圖片描述

在這里插入圖片描述

1、創建pod,并調度到合適的節點上
2、創建pause基礎主容器,提供共享名稱空間 # (info容器) == 根容器 == 主容器
3、從上到下依次創建業務容器
4、啟動業務容器,啟動那一刻會同時運行主容器上定義的Poststart鉤子事件
5、持續存活狀態監測、就緒狀態監測
6、結束時,執行prestop鉤子事件
7、終止業務容器,在終止主容器
8、銷毀Pod
2、在整個生命周期中,Pod會出現5種狀態相位),
 # 1、掛起(Pending):
 API Server 創建了 pod 資源物件已存入 etcd 中,但它尚未被調度完成,或者仍處于從倉庫下載鏡像的程序中,
 # 2、運行中(Running):
 Pod 已經被調度至某節點,并且所有容器都已經被 kubelet 創建完成
 # 3、成功(Succeeded):
 Pod 中的所有容器都已經成功終止并且不會被重啟,
 # 4、失敗(Failed):
 Pod 中的所有容器都已終止了,并且至少有一個容器是因為失敗終止,即容器以非 0 狀態退出或者被系統禁止,
 # 5、未知(Unknown):
 Api Server 無法正常獲取到 Pod 物件的狀態資訊,通常是由于無法與所在作業節點的kubelet 通信所致,
 
 ===================================================================================================
 # 6、ImgPullErr : (不常用)
 鏡像拉取失敗
 # 7、ContainerCreating : (不常用)
 容器創建中

kubernetes在集群啟動之后,集群中的各個組件也都是以Pod方式運行的,可以通過下面命令查看:

[root@k8s-m-01 ~]# kubectl get pod -n kube-system
NAMESPACE     NAME                             READY   STATUS    RESTARTS   AGE
kube-system   coredns-6955765f44-68g6v         1/1     Running   0          2d1h
kube-system   coredns-6955765f44-cs5r8         1/1     Running   0          2d1h
kube-system   etcd-master                      1/1     Running   0          2d1h
kube-system   kube-apiserver-master            1/1     Running   0          2d1h
kube-system   kube-controller-manager-master   1/1     Running   0          2d1h
kube-system   kube-flannel-ds-amd64-47r25      1/1     Running   0          2d1h
kube-system   kube-flannel-ds-amd64-ls5lh      1/1     Running   0          2d1h
kube-system   kube-proxy-685tk                 1/1     Running   0          2d1h
kube-system   kube-proxy-87spt                 1/1     Running   0          2d1h
kube-system   kube-scheduler-master            1/1     Running   0          2d1h

3、創建和終止

1、pod的創建程序
1. 用戶通過kubectl或其他api客戶端提交需要創建的Pod資訊給apiServer
2. apiServer開始生成Pod物件的資訊,并將資訊存入etcd,然后回傳確認資訊至客戶端
3. apiServer開始反映etcd中的Pod物件的變化,其它組件使用watch機制來跟蹤檢查apiServer上的變動
4. scheduler發現有新的Pod物件要創建,開始為Pod分配主機并將結果資訊更新至apiServer
5. node節點上的kubelet發現有pod調度過來,嘗試呼叫docker啟動容器,并將結果回送至apiServer
6. apiServer將接收到的pod狀態資訊存入etcd中

在這里插入圖片描述

2、pod的終止程序
1. 用戶向apiServer發送洗掉pod物件的命令
2. apiServcer中的pod物件資訊會隨著時間的推移而更新,在寬限期內(默認30s),pod被視為dead
3. 將pod標記為terminating狀態(正在洗掉狀態)
4. kubelet在監控到pod物件轉為terminating狀態的同時啟動pod關閉程序
5. 端點控制器監控到pod物件的關閉行為時將其從所有匹配到此端點的service資源的端點串列中移除
6. 如果當前pod物件定義了preStop鉤子處理器,則在其標記為terminating后即會以同步的方式啟動執行
7. pod物件中的容器行程收到停止信號
8. 寬限期結束后,若pod中還存在仍在運行的行程,那么pod物件會收到立即終止的信號
9. kubelet請求apiServer將此pod資源的寬限期設定為0從而完成洗掉操作,此時pod對于用戶已不可見
3、初始化容器

初始化容器是在pod的主容器啟動之前要運行的容器,主要是做一些主容器的前置作業,它具有兩大特征:

1. 初始化容器必須運行完成直至結束,若某初始化容器運行失敗,那么kubernetes需要重啟它直到成功完成
2. 初始化容器必須按照定義的順序執行,當且僅當前一個成功之后,后面的一個才能運行

初始化容器有很多的應用場景,下面列出的是最常見的幾個:

1、提供主容器鏡像中不具備的工具程式或自定義代碼
2、初始化容器要先于應用容器串行啟動并運行完成,因此可用于延后應用容器的啟動直至其依賴的條件得到滿足

案例,模擬下面這個需求:

? 假設要以主容器來運行nginx,但是要求在運行nginx之前先要能夠連接上mysql和redis所在服務器

? 為了簡化測驗,事先規定好mysql(192.168.15.201)和redis(192.168.15.202)服務器的地址

1、創建pod-initcontainer.yaml,內容如下:
apiVersion: v1
kind: Pod
metadata:
  name: pod-initcontainer
  namespace: dev
spec:
  containers:
  - name: main-container
    image: nginx:1.17.1
    ports: 
    - name: nginx-port
      containerPort: 80
  initContainers:
  - name: test-mysql
    image: busybox:1.30
    command: ['sh', '-c', 'until ping 192.168.15.201 -c 1 ; do echo waiting for mysql...; sleep 2; done;']
  - name: test-redis
    image: busybox:1.30
    command: ['sh', '-c', 'until ping 192.168.15.202 -c 1 ; do echo waiting for reids...; sleep 2; done;']
# 1、創建pod
[root@k8s-m-01 ~]# kubectl create -f pod-initcontainer.yaml
pod/pod-initcontainer created

# 2、查看pod狀態
# 發現pod卡在啟動第一個初始化容器程序中,后面的容器不會運行
root@master ~]# kubectl describe pod  pod-initcontainer -n dev
........
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  49s   default-scheduler  Successfully assigned dev/pod-initcontainer to k8s-n-01
  Normal  Pulled     48s   kubelet, k8s-n-01     Container image "busybox:1.30" already present on machine
  Normal  Created    48s   kubelet, k8s-n-01     Created container test-mysql
  Normal  Started    48s   kubelet, k8s-n-01     Started container test-mysql

# 3、動態查看pod
[root@k8s-m-01 ~]# kubectl get pods pod-initcontainer -n dev -w
NAME                             READY   STATUS     RESTARTS   AGE
pod-initcontainer                0/1     Init:0/2   0          15s
pod-initcontainer                0/1     Init:1/2   0          52s
pod-initcontainer                0/1     Init:1/2   0          53s
pod-initcontainer                0/1     PodInitializing   0          89s
pod-initcontainer                1/1     Running           0          90s

# 4、接下來新開一個shell,為當前服務器新增兩個ip,觀察pod的變化
[root@k8s-m-01 ~]# ifconfig eth0:1 192.168.15.201 netmask 255.255.255.0 up
[root@k8s-m-01 ~]# ifconfig eth0:2 192.168.15.202 netmask 255.255.255.0 up
4、鉤子函式

鉤子函式能夠感知自身生命周期中的事件,并在相應的時刻到來時運行用戶指定的程式代碼,

kubernetes在主容器的啟動之后和停止之前提供了兩個鉤子函式:

1、post start: # 容器創建之后執行,如果失敗了會重啟容器
2、pre stop  : # 容器終止之前執行,執行完成之后容器將成功終止,在其完成之前會阻塞洗掉容器的操作

鉤子處理器支持使用下面三種方式定義動作:

  • Exec命令:在容器內執行一次命令

    ……
      lifecycle:
        postStart: 
          exec:
            command:
            - cat
            - /tmp/healthy
    ……
    
  • TCPSocket:在當前容器嘗試訪問指定的socket

    ……      
      lifecycle:
        postStart:
          tcpSocket:
            port: 8080
    ……
    
  • HTTPGet:在當前容器中向某url發起http請求

    ……
      lifecycle:
        postStart:
          httpGet:
            path: / #URI地址
            port: 80 #埠號
            host: 192.168.15.100 #主機地址
            scheme: HTTP #支持的協議,http或者https
    ……
    

接下來,以exec方式為例,演示下鉤子函式的使用,創建pod-hook-exec.yaml檔案,內容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-hook-exec
  namespace: dev
spec:
  containers:
  - name: main-container
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    lifecycle:
      postStart: 
        exec: # 在容器啟動的時候執行一個命令,修改掉nginx的默認首頁內容
          command: ["/bin/sh", "-c", "echo postStart... > /usr/share/nginx/html/index.html"]
      preStop:
        exec: # 在容器停止之前停止nginx服務
          command: ["/usr/sbin/nginx","-s","quit"]
# 1、創建pod
[root@k8s-m-01 ~]# kubectl create -f pod-hook-exec.yaml
pod/pod-hook-exec created

# 2、查看pod
[root@k8s-m-01 ~]# kubectl get pods  pod-hook-exec -n dev -o wide
NAME           READY   STATUS     RESTARTS   AGE    IP            NODE    
pod-hook-exec  1/1     Running    0          29s    10.244.2.48   k8s-n-02   

# 3、訪問pod
[root@k8s-m-01 ~]# curl 10.244.2.48
postStart...

4、容器探測

容器探測用于檢測容器中的應用實體是否正常作業,是保障業務可用性的一種傳統機制,如果經過探測,實體的狀態不符合預期,那么kubernetes就會把該問題實體" 摘除 ",不承擔業務流量,kubernetes提供了兩種探針來實作容器探測,分別是:

# 1、存活性檢查 :
容器是否正常啟動,探測失敗,立即洗掉容器
# 2、就緒性檢查 : 
容器是否能夠正常提供服務,探測失敗,立即移除負載均衡
  • liveness probes: 存活性探針,用于檢測應用實體當前是否處于正常運行狀態,如果不是,k8s會重啟容器

  • readiness probes:就緒性探針,用于檢測應用實體當前是否可以接收請求,如果不能,k8s不會轉發流量

livenessProbe 決定是否重啟容器,readinessProbe 決定是否將請求轉發給容器,

上面兩種探針目前均支持三種探測方式:

  • Exec命令:在容器內執行一次命令,如果命令執行的退出碼為0,則認為程式正常,否則不正常

    ……
      livenessProbe:
        exec:
          command:
          - cat
          - /tmp/healthy
    ……
    
  • TCPSocket:將會嘗試訪問一個用戶容器的埠,如果能夠建立這條連接,則認為程式正常,否則不正常

    ……      
      livenessProbe:
        tcpSocket:
          port: 8080
    ……
    
  • HTTPGet:呼叫容器內Web應用的URL,如果回傳的狀態碼在200和399之間,則認為程式正常,否則不正常

    ……
      livenessProbe:
        httpGet:
          path: / #URI地址
          port: 80 #埠號
          host: 127.0.0.1 #主機地址
          scheme: HTTP #支持的協議,http或者https
    ……
    

下面以liveness probes為例,做幾個演示:

方式一:Exec
1、創建pod-liveness-exec.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-exec
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports: 
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      exec:
        command: ["/bin/cat","/tmp/hello.txt"] # 執行一個查看檔案的命令
2、 創建pod,觀察效果
# 1、創建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-liveness-exec.yaml
pod/pod-liveness-exec created

# 2、查看Pod詳情
[root@k8s-m-01 ~]# kubectl describe pods pod-liveness-exec -n dev
......
  Normal   Created    20s (x2 over 50s)  kubelet, k8s-n-01     Created container nginx
  Normal   Started    20s (x2 over 50s)  kubelet, k8s-n-01     Started container nginx
  Normal   Killing    20s                kubelet, k8s-n-01     Container nginx failed liveness probe, will be restarted
  Warning  Unhealthy  0s (x5 over 40s)   kubelet, k8s-n-01     Liveness probe failed: cat: can't open '/tmp/hello11.txt': No such file or directory
  
# 觀察上面的資訊就會發現nginx容器啟動之后就進行了健康檢查
# 檢查失敗之后,容器被kill掉,然后嘗試進行重啟(這是重啟策略的作用,后面講解)
# 稍等一會之后,再觀察pod資訊,就可以看到RESTARTS不再是0,而是一直增長
[root@k8s-m-01 ~]# kubectl get pods pod-liveness-exec -n dev
NAME                READY   STATUS             RESTARTS   AGE
pod-liveness-exec   0/1     CrashLoopBackOff   2          3m19s

# 當然接下來,可以修改成一個存在的檔案,比如/tmp/hello.txt,再試,結果就正常了......
# command: ["/bin/ls","/tmp/"] #正確配置(查看檔案的命令)
方式二:TCPSocket
1、創建pod-liveness-tcpsocket.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-tcpsocket
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports: 
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      tcpSocket:
        port: 8080 # 嘗試訪問8080埠
2、創建pod,觀察效果
# 1、創建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-liveness-tcpsocket.yaml
pod/pod-liveness-tcpsocket created

# 2、查看Pod詳情
[root@k8s-m-01 ~]# kubectl describe pods pod-liveness-tcpsocket -n dev
......
  Normal   Scheduled  31s                            default-scheduler  Successfully assigned dev/pod-liveness-tcpsocket to k8s-n-02
  Normal   Pulled     <invalid>                      kubelet, k8s-n-02     Container image "nginx:1.17.1" already present on machine
  Normal   Created    <invalid>                      kubelet, k8s-n-02     Created container nginx
  Normal   Started    <invalid>                      kubelet, k8s-n-02     Started container nginx
  Warning  Unhealthy  <invalid> (x2 over <invalid>)  kubelet, k8s-n-02     Liveness probe failed: dial tcp 10.244.2.44:8080: connect: connection refused
  
# 觀察上面的資訊,發現嘗試訪問8080埠,但是失敗了
# 稍等一會之后,再觀察pod資訊,就可以看到RESTARTS不再是0,而是一直增長
[root@k8s-m-01 ~]# kubectl get pods pod-liveness-tcpsocket  -n dev
NAME                     READY   STATUS             RESTARTS   AGE
pod-liveness-tcpsocket   0/1     CrashLoopBackOff   2          3m19s

# 當然接下來,可以修改成一個可以訪問的埠,比如80,再試,結果就正常了......
# port: 80 (正確配置)
方式三:HTTPGet
1、創建pod-liveness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-httpget
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      httpGet:  # 其實就是訪問http://127.0.0.1:80/hello  
        scheme: HTTP #支持的協議,http或者https
        port: 80 #埠號
        path: /hello #URI地址
2、創建pod,觀察效果
# 1、創建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-liveness-httpget.yaml
pod/pod-liveness-httpget created

# 2、查看Pod詳情
[root@k8s-m-01 ~]# kubectl describe pod pod-liveness-httpget -n dev
.......
  Normal   Pulled     6s (x3 over 64s)  kubelet, k8s-n-01     Container image "nginx:1.17.1" already present on machine
  Normal   Created    6s (x3 over 64s)  kubelet, k8s-n-01     Created container nginx
  Normal   Started    6s (x3 over 63s)  kubelet, k8s-n-01     Started container nginx
  Warning  Unhealthy  6s (x6 over 56s)  kubelet, k8s-n-01     Liveness probe failed: HTTP probe failed with statuscode: 404
  Normal   Killing    6s (x2 over 36s)  kubelet, k8s-n-01     Container nginx failed liveness probe, will be restarted
  
# 3、觀察上面資訊,嘗試訪問路徑,但是未找到,出現404錯誤
# 稍等一會之后,再觀察pod資訊,就可以看到RESTARTS不再是0,而是一直增長
[root@k8s-m-01 ~]# kubectl get pod pod-liveness-httpget -n dev
NAME                   READY   STATUS    RESTARTS   AGE
pod-liveness-httpget   1/1     Running   5          3m17s

# 當然接下來,可以修改成一個可以訪問的路徑path,比如/,再試,結果就正常了......
#  path: / (正確配置)

? 至此,已經使用liveness Probe演示了三種探測方式,但是查看livenessProbe的子屬性,會發現除了這三種方式,還有一些其他的配置,在這里一并解釋下:

[root@k8s-m-01 ~]# kubectl explain pod.spec.containers.livenessProbe
FIELDS:
   exec <Object>  
   tcpSocket    <Object>
   httpGet      <Object>
   initialDelaySeconds  <integer>  # 容器啟動后等待多少秒執行第一次探測
   timeoutSeconds       <integer>  # 探測超時時間,默認1秒,最小1秒
   periodSeconds        <integer>  # 執行探測的頻率,默認是10秒,最小1秒
   failureThreshold     <integer>  # 連續探測失敗多少次才被認定為失敗,默認是3,最小值是1
   successThreshold     <integer>  # 連續探測成功多少次才被認定為成功,默認是1

下面稍微配置兩個,演示下效果即可:

[root@k8s-m-01 ~]# more pod-liveness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-liveness-httpget
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      httpGet:
        scheme: HTTP
        port: 80 
        path: /
      initialDelaySeconds: 30 # 容器啟動后30s開始探測
      timeoutSeconds: 5 # 探測超時時間為5s

5、重啟策略

  • Always :容器失效時,自動重啟該容器,這也是默認值,
  • OnFailure : 容器終止運行且退出碼不為0時重啟
  • Never : 不論狀態為何,都不重啟該容器
# 1. Always: (默認)
當容器失效時,由 kubelet 自動重啟該容器,
# 2. OnFailure:
當容器終止運行且退出碼不為 0 時,由 kubelet 自動重啟該容器
# 3. Never:
不論容器運行狀態如何,kubelet 都不會重啟該容器,
   kubelet 重啟失效容器的時間間隔以 sync-frequency 乘以 2n 來計算;例如 1、2、4、8 倍等,最長延時5min ,并且在成功重啟后的 10 min 后重置該時間,
   Pod 的重啟策略與控制方式息息相關,當前可用于管理 Pod 的控制器包括 ReplicationController、Job、DaemonSet 及直接通過 kubelet 管理(靜態 Pod),每種控制器對 Pod 的重啟策略要求如下:
   # 1.RC 和 DaemonSet:必須設定為 Always,需要保證該容器持續運行,
   # 2.Job 和 CronJob:OnFailure 或 Never,確保容器執行完成后不再重啟,
   # 3.kubelet:在 Pod 失效時自動重啟它,不論將 RestartPolicy 設定為什么值,也不會對 Pod 進行健康檢查,
重啟策略適用于pod物件中的所有容器,首次需要重啟的容器,將在其需要時立即進行重啟,隨后再次需要重啟的操作將由kubelet延遲一段時間后進行,且反復的重啟操作的延遲時長以此為10s、20s、40s、80s、160s和300s,300s是最大延遲時長,
Pod 重啟策略( RestartPolicy )應用于 Pod 內的所有容器,井且僅在 Pod 所處的 Node 上由 kubelet 進行判斷和重啟操作,
當某個容器例外退出或者健康檢查失敗時, kubelet 將根據 RestartPolicy 設定來進行相應的操作,Pod 的重啟策略包括:Always、OnFailure 和 Never,默認值為 Always
1、創建pod-restartpolicy.yaml:
apiVersion: v1
kind: Pod
metadata:
  name: pod-restartpolicy
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
    livenessProbe:
      httpGet:
        scheme: HTTP
        port: 80
        path: /hello
  restartPolicy: Never # 設定重啟策略為Never (默認Always)
2、運行Pod測驗
# 1、創建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-restartpolicy.yaml
pod/pod-restartpolicy created

# 2、查看Pod詳情,發現nginx容器失敗
[root@k8s-m-01 ~]# kubectl  describe pods pod-restartpolicy  -n dev
......
  Warning  Unhealthy  15s (x3 over 35s)  kubelet, k8s-n-01     Liveness probe failed: HTTP probe failed with statuscode: 404
  Normal   Killing    15s                kubelet, k8s-n-01     Container nginx failed liveness probe
  
# 3、多等一會,再觀察pod的重啟次數,發現一直是0,并未重啟   
[root@k8s-m-01 ~]# kubectl  get pods pod-restartpolicy -n dev
NAME                   READY   STATUS    RESTARTS   AGE
pod-restartpolicy      0/1     Running   0          5min42s
3、Pod是如何管理多個容器的
Pod中可以同時運行多個行程(作為容器運行)協同作業,
同一個 Pod 中的容器會自動的分配到同一個 node上,同一個 Pod 中的容器共享資源、網路環境和依賴,所以它們總是被同時調度,在一個 Pod 中同時運行多個容器是一種比較高級的用法,只有當你的容器需要緊密配合協作的時候才考慮用這種模式,
4、Pod中資料持久性
Pod 在設計?持就不是作為持久化物體的,在調度失敗、節點故障、缺少資源或者節點維護的狀態下都會死
掉會被驅逐,通常,我們是需要借助類似于 Docker 存盤卷這樣的資源來做 Pod 的資料持久

四、Pod調度

在默認情況下,一個Pod在哪個Node節點上運行,是由Scheduler組件采用相應的演算法計算出來的,這個程序是不受人工控制的,但是在實際使用中,這并不滿足的需求,因為很多情況下,我們想控制某些Pod到達某些節點上,那么應該怎么做呢?這就要求了解kubernetes對Pod的調度規則,kubernetes提供了四大類調度方式:
  • 自動調度:運行在哪個節點上完全由Scheduler經過一系列的演算法計算得出
  • 定向調度:NodeName、NodeSelector
  • 親和性調度:NodeAffinity、PodAffinity、PodAntiAffinity
  • 污點(容忍)調度:Taints、Toleration

1、定向調度

定向調度,指的是利用在pod上宣告nodeName或者nodeSelector,以此將Pod調度到期望的node節點上,注意,這里的調度是強制的,這就意味著即使要調度的目標Node不存在,也會向上面進行調度,只不過pod運行失敗而已,
1、NodeName

? NodeName用于強制約束將Pod調度到指定的Name的Node節點上,這種方式,其實是直接跳過Scheduler的調度邏輯,直接將Pod調度到指定名稱的節點,

創建一個pod-nodename.yaml檔案

[root@k8s-m-01 ~]# kubectl get nodes
NAME       STATUS   ROLES                  AGE     VERSION
k8s-m-01   Ready    control-plane,master   4d18h   v1.21.3
k8s-n-01   Ready    <none>                 4d18h   v1.21.3
k8s-n-02   Ready    <none>                 4d18h   v1.21.3

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeName: k8s-n-01 # 指定調度到k8s-n-01節點上(node的主機名稱)
# 1、創建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-nodename.yaml
pod/pod-nodename created

# 2、查看Pod調度到NODE屬性,確實是調度到了k8s-n-01節點上
[root@k8s-m-01 ~]# kubectl get pods pod-nodename -n dev -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP            NODE      ......
pod-nodename   1/1     Running   0          56s   10.244.1.87   k8s-n-01     ......   

# 3、接下來,洗掉pod,修改nodeName的值為node3(并沒有node3節點)
[root@k8s-m-01 ~]# kubectl delete -f pod-nodename.yaml
pod "pod-nodename" deleted
[root@k8s-m-01 ~]# vim pod-nodename.yaml
[root@k8s-m-01 ~]# kubectl create -f pod-nodename.yaml
pod/pod-nodename created

# 4、再次查看,發現已經向Node3節點調度,但是由于不存在node3節點,所以pod無法正常運行
[root@k8s-m-01 ~]# kubectl get pods pod-nodename -n dev -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP       NODE    ......
pod-nodename   0/1     Pending   0          6s    <none>   node3   ......           
2、NodeSelector
NodeSelector用于將pod調度到添加了指定標簽的node節點上,它是通過kubernetes的label-selector機制實作的,也就是說,在pod創建之前,會由scheduler使用MatchNodeSelector調度策略進行label匹配,找出目標node,然后將pod調度到目標節點,該匹配規則是強制約束,
1 首先分別為node節點添加標簽
[root@k8s-m-01 ~]# kubectl label nodes k8s-n-01 nodeenv=pro
node/k8s-n-02 labeled
[root@k8s-m-01 ~]# kubectl label nodes k8s-n-02 nodeenv=test
node/k8s-n-02 labeled
2 創建一個pod-nodeselector.yaml檔案,并使用它創建Pod
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselector
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeSelector: 
    nodeenv: pro # 指定調度到具有nodeenv=pro標簽的節點上
# 1、創建Pod
[root@k8s-m-01 ~]# kubectl create -f pod-nodeselector.yaml
pod/pod-nodeselector created

# 2、查看Pod調度到NODE屬性,確實是調度到了k8s-n-01節點上
[root@k8s-m-01 ~]# kubectl get pods pod-nodeselector -n dev -o wide
NAME               READY   STATUS    RESTARTS   AGE     IP          NODE    ......
pod-nodeselector   1/1     Running   0          47s   10.244.1.87   k8s-n-01   ......

# 3、接下來,洗掉pod,修改nodeSelector的值為nodeenv: xxxx(不存在打有此標簽的節點)
[root@k8s-m-01 ~]# kubectl delete -f pod-nodeselector.yaml
pod "pod-nodeselector" deleted
[root@k8s-m-01 ~]# vim pod-nodeselector.yaml
[root@k8s-m-01 ~]# kubectl create -f pod-nodeselector.yaml
pod/pod-nodeselector created

# 4、再次查看,發現pod無法正常運行,Node的值為none
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME               READY   STATUS    RESTARTS   AGE     IP       NODE    
pod-nodeselector   0/1     Pending   0          2m20s   <none>   <none>

# 5、查看詳情,發現node selector匹配失敗的提示
[root@k8s-m-01 ~]# kubectl describe pods pod-nodeselector -n dev
.......
Events:
  Type     Reason            Age        From               Message
  ----     ------            ----       ----               -------
  Warning  FailedScheduling  <unknown>  default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.
  Warning  FailedScheduling  <unknown>  default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.

2、親和性調度

   上一節,介紹了兩種定向調度的方式,使用起來非常方便,但是也有一定的問題,那就是如果沒有滿足條件的Node,那么Pod將不會被運行,即使在集群中還有可用Node串列也不行,這就限制了它的使用場景,
   
   基于上面的問題,kubernetes還提供了一種親和性調度(Affinity),它在NodeSelector的基礎之上的進行了擴展,可以通過配置的形式,實作優先選擇滿足條件的Node進行調度,如果沒有,也可以調度到不滿足條件的節點上,使調度更加靈活,

Affinity主要分為三類:

  • nodeAffinity(node親和性): 以node為目標,解決pod可以調度到哪些node的問題

  • podAffinity(pod親和性) : 以pod為目標,解決pod可以和哪些已存在的pod部署在同一個拓撲域中的問題

  • podAntiAffinity(pod反親和性) : 以pod為目標,解決pod不能和哪些已存在pod部署在同一個拓撲域中的問題

關于親和性(反親和性)使用場景的說明:

親和性:如果兩個應用頻繁互動,那就有必要利用親和性讓兩個應用的盡可能的靠近,這樣可以減少因網路通信而帶來的性能損耗,

反親和性:當應用的采用多副本部署時,有必要采用反親和性讓各個應用實體打散分布在各個node上,這樣可以提高服務的高可用性,

3、NodeAffinity

首先來看一下NodeAffinity的可配置項:

pod.spec.affinity.nodeAffinity
  requiredDuringSchedulingIgnoredDuringExecution  Node節點必須滿足指定的所有規則才可以,相當于硬限制
    nodeSelectorTerms  節點選擇串列
      matchFields   按節點欄位列出的節點選擇器要求串列
      matchExpressions   按節點標簽列出的節點選擇器要求串列(推薦)
        key    鍵
        values 值
        operator 關系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
  preferredDuringSchedulingIgnoredDuringExecution 優先調度到滿足指定的規則的Node,相當于軟限制 (傾向)
    preference   一個節點選擇器項,與相應的權重相關聯
      matchFields   按節點欄位列出的節點選擇器要求串列
      matchExpressions   按節點標簽列出的節點選擇器要求串列(推薦)
        key    鍵
        values 值
        operator 關系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt
	weight 傾向權重,在范圍1-100,
關系符的使用說明:

- matchExpressions:
  - key: nodeenv              # 匹配存在標簽的key為nodeenv的節點
    operator: Exists
  - key: nodeenv              # 匹配標簽的key為nodeenv,且value是"xxx"或"yyy"的節點
    operator: In
    values: ["xxx","yyy"]
  - key: nodeenv              # 匹配標簽的key為nodeenv,且value大于"xxx"的節點
    operator: Gt
    values: "xxx"
1、接下來首先演示一下requiredDuringSchedulingIgnoredDuringExecution ,

創建pod-nodeaffinity-required.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #親和性設定
    nodeAffinity: #設定node親和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        nodeSelectorTerms:
        - matchExpressions: # 匹配env的值在["xxx","yyy"]中的標簽
          - key: nodeenv
            operator: In
            values: ["xxx","yyy"]
# 1、創建pod
[root@k8s-m-01 ~]# kubectl create -f pod-nodeaffinity-required.yaml
pod/pod-nodeaffinity-required created

# 2、查看pod狀態 (運行失敗)
[root@k8s-m-01 ~]# kubectl get pods pod-nodeaffinity-required -n dev -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP       NODE    ...... 
pod-nodeaffinity-required   0/1     Pending   0          16s   <none>   <none>  ......

# 3、查看Pod的詳情
# 發現調度失敗,提示node選擇失敗
[root@k8s-m-01 ~]# kubectl describe pod pod-nodeaffinity-required -n dev
......
  Warning  FailedScheduling  <unknown>  default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.
  Warning  FailedScheduling  <unknown>  default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.

# 4、接下來,停止pod
[root@k8s-m-01 ~]# kubectl delete -f pod-nodeaffinity-required.yaml
pod "pod-nodeaffinity-required" deleted

# 5、修改檔案,將values: ["xxx","yyy"]------> ["pro","yyy"]
[root@k8s-m-01 ~]# vim pod-nodeaffinity-required.yaml

# 6、再次啟動
[root@k8s-m-01 ~]# kubectl create -f pod-nodeaffinity-required.yaml
pod/pod-nodeaffinity-required created

# 7、此時查看,發現調度成功,已經將pod調度到了k8s-n-01上
[root@k8s-m-01 ~]# kubectl get pods pod-nodeaffinity-required -n dev -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP            NODE  ...... 
pod-nodeaffinity-required   1/1     Running   0          11s   10.244.1.89   k8s-n-01 ......
2、接下來再演示一下requiredDuringSchedulingIgnoredDuringExecution

創建pod-nodeaffinity-preferred.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-preferred
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #親和性設定
    nodeAffinity: #設定node親和性
      preferredDuringSchedulingIgnoredDuringExecution: # 軟限制
      - weight: 1
        preference:
          matchExpressions: # 匹配env的值在["xxx","yyy"]中的標簽(當前環境沒有)
          - key: nodeenv
            operator: In
            values: ["xxx","yyy"]
# 1、創建pod
[root@k8s-m-01 ~]# kubectl create -f pod-nodeaffinity-preferred.yaml
pod/pod-nodeaffinity-preferred created

# 2、查看pod狀態 (運行成功)
[root@k8s-m-01 ~]# kubectl get pod pod-nodeaffinity-preferred -n dev
NAME                         READY   STATUS    RESTARTS   AGE
pod-nodeaffinity-preferred   1/1     Running   0          40s
NodeAffinity規則設定的注意事項:
# 1 、如果同時定義了nodeSelector和nodeAffinity,那么必須兩個條件都得到滿足,Pod才能運行在指定的Node上
# 2 、如果nodeAffinity指定了多個nodeSelectorTerms,那么只需要其中一個能夠匹配成功即可
# 3 、如果一個nodeSelectorTerms中有多個matchExpressions ,則一個節點必須滿足所有的才能匹配成功
# 4 、如果一個pod所在的Node在Pod運行期間其標簽發生了改變,不再符合該Pod的節點親和性需求,則系統將忽略此變化
4、PodAffinity

PodAffinity主要實作以運行的Pod為參照,實作讓新創建的Pod跟參照pod在一個區域的功能,

1、首先來看一下PodAffinity的可配置項
pod.spec.affinity.podAffinity
  requiredDuringSchedulingIgnoredDuringExecution  硬限制
    namespaces       指定參照pod的namespace
    topologyKey      指定調度作用域
    labelSelector    標簽選擇器
      matchExpressions  按節點標簽列出的節點選擇器要求串列(推薦)
        key    鍵
        values 值
        operator 關系符 支持In, NotIn, Exists, DoesNotExist.
      matchLabels    指多個matchExpressions映射的內容
  preferredDuringSchedulingIgnoredDuringExecution 軟限制
    podAffinityTerm  選項
      namespaces      
      topologyKey
      labelSelector
        matchExpressions  
          key    鍵
          values 值
          operator
        matchLabels 
    weight 傾向權重,在范圍1-100
topologyKey用于指定調度時作用域,例如:
    如果指定為kubernetes.io/hostname,那就是以Node節點為區分范圍
    如果指定為beta.kubernetes.io/os,則以Node節點的作業系統型別來區分
2、接下來,演示下requiredDuringSchedulingIgnoredDuringExecution,

1、首先創建一個參照Pod,pod-podaffinity-target.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-target
  namespace: dev
  labels:
    podenv: pro #設定標簽
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeName: k8s-n-01 # 將目標pod名確指定到k8s-n-01上
# 啟動目標pod
[root@k8s-m-01 ~]# kubectl create -f pod-podaffinity-target.yaml
pod/pod-podaffinity-target created

# 查看pod狀況
[root@k8s-m-01 ~]# kubectl get pods  pod-podaffinity-target -n dev
NAME                     READY   STATUS    RESTARTS   AGE
pod-podaffinity-target   1/1     Running   0          4s

2、創建pod-podaffinity-required.yaml,內容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #親和性設定
    podAffinity: #設定pod親和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
      - labelSelector:
          matchExpressions: # 匹配env的值在["xxx","yyy"]中的標簽
          - key: podenv
            operator: In
            values: ["xxx","yyy"]
        topologyKey: kubernetes.io/hostname

上面配置表達的意思是:新Pod必須要與擁有標簽nodeenv=xxx或者nodeenv=yyy的pod在同一Node上,顯然現在沒有這樣pod,接下來,運行測驗一下,

# 1、啟動pod
[root@k8s-m-01 ~]# kubectl create -f pod-podaffinity-required.yaml
pod/pod-podaffinity-required created

# 2、查看pod狀態,發現未運行
[root@k8s-m-01 ~]# kubectl get pods pod-podaffinity-required -n dev
NAME                       READY   STATUS    RESTARTS   AGE
pod-podaffinity-required   0/1     Pending   0          9s

# 3、查看詳細資訊
[root@k8s-m-01 ~]# kubectl describe pods pod-podaffinity-required  -n dev
......
Events:
  Type     Reason            Age        From               Message
  ----     ------            ----       ----               -------
  Warning  FailedScheduling  <unknown>  default-scheduler  0/3 nodes are available: 2 node(s) didn't match pod affinity rules, 1 node(s) had taints that the pod didn't tolerate.

# 4、接下來修改  values: ["xxx","yyy"]----->values:["pro","yyy"]
# 意思是:新Pod必須要與擁有標簽nodeenv=xxx或者nodeenv=yyy的pod在同一Node上
[root@k8s-m-01 ~]# vim pod-podaffinity-required.yaml

# 5、然后重新創建pod,查看效果
[root@k8s-m-01 ~]# kubectl delete -f  pod-podaffinity-required.yaml
pod "pod-podaffinity-required" deleted
[root@k8s-m-01 ~]# kubectl create -f pod-podaffinity-required.yaml
pod/pod-podaffinity-required created

# 6、發現此時Pod運行正常
[root@k8s-m-01 ~]# kubectl get pods pod-podaffinity-required -n dev
NAME                       READY   STATUS    RESTARTS   AGE   LABELS
pod-podaffinity-required   1/1     Running   0          6s    <none>

關于PodAffinitypreferredDuringSchedulingIgnoredDuringExecution,這里不再演示,

5、PodAntiAffinity

PodAntiAffinity主要實作以運行的Pod為參照,讓新創建的Pod跟參照pod不在一個區域中的功能,

它的配置方式和選項跟PodAffinty是一樣的,這里不再做詳細解釋,直接做一個測驗案例,

1、繼續使用上個案例中目標pod
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide --show-labels
NAME                     READY   STATUS    RESTARTS   AGE     IP            NODE    LABELS
pod-podaffinity-required 1/1     Running   0          3m29s   10.244.1.38   k8s-n-01   <none>     
pod-podaffinity-target   1/1     Running   0          9m25s   10.244.1.37   k8s-n-01   podenv=pro
2、創建pod-podantiaffinity-required.yaml,內容如下:
apiVersion: v1
kind: Pod
metadata:
  name: pod-podantiaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #親和性設定
    podAntiAffinity: #設定pod親和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
      - labelSelector:
          matchExpressions: # 匹配podenv的值在["pro"]中的標簽
          - key: podenv
            operator: In
            values: ["pro"]
        topologyKey: kubernetes.io/hostname

上面配置表達的意思是:新Pod必須要與擁有標簽nodeenv=pro的pod不在同一Node上,運行測驗一下,

# 創建pod
[root@k8s-m-01 ~]# kubectl create -f pod-podantiaffinity-required.yaml
pod/pod-podantiaffinity-required created

# 查看pod
# 發現調度到了k8s-n-02上
[root@k8s-m-01 ~]# kubectl get pods pod-podantiaffinity-required -n dev -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP            NODE   .. 
pod-podantiaffinity-required   1/1     Running   0          30s   10.244.1.96   k8s-n-02  ..

3、污點和容忍

1、污點(Taints)
   前面的調度方式都是站在Pod的角度上,通過在Pod上添加屬性,來確定Pod是否要調度到指定的Node上,其實我們也可以站在Node的角度上,通過在Node上添加**污點**屬性,來決定是否允許Pod調度過來,

 Node被設定上污點之后就和Pod之間存在了一種相斥的關系,進而拒絕Pod調度進來,甚至可以將已經存在的Pod驅逐出去,

污點的格式為:key=value:effect, key和value是污點的標簽,effect描述污點的作用,支持如下三個選項:

  • PreferNoSchedule:kubernetes將盡量避免把Pod調度到具有該污點的Node上,除非沒有其他節點可調度
  • NoSchedule:kubernetes將不會把Pod調度到具有該污點的Node上,但不會影響當前Node上已存在的Pod
  • NoExecute:kubernetes將不會把Pod調度到具有該污點的Node上,同時也會將Node上已存在的Pod驅離

在這里插入圖片描述

使用kubectl設定和去除污點的命令示例如下:

# 1、設定污點
kubectl taint nodes k8s-n-01 key=value:effect

# 2、去除污點
kubectl taint nodes k8s-n-01 key:effect-

# 3、去除所有污點
kubectl taint nodes k8s-n-01 key-

接下來,演示下污點的效果:

  1. 準備節點k8s-n-01(為了演示效果更加明顯,暫時停止k8s-n-02節點)
  2. 為k8s-n-01節點設定一個污點: tag=heima:PreferNoSchedule;然后創建pod1( pod1 可以 )
  3. 修改為k8s-n-01節點設定一個污點: tag=heima:NoSchedule;然后創建pod2( pod1 正常 pod2 失敗 )
  4. 修改為k8s-n-01節點設定一個污點: tag=heima:NoExecute;然后創建pod3 ( 3個pod都失敗 )
# 1、為k8s-n-01設定污點(PreferNoSchedule)
[root@k8s-m-01 ~]# kubectl taint nodes k8s-n-01 tag=heima:PreferNoSchedule

# 2、創建pod1
[root@k8s-m-01 ~]# kubectl run taint1 --image=nginx:1.17.1 -n dev
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP           NODE   
taint1-7665f7fd85-574h4   1/1     Running   0          2m24s   10.244.1.59   k8s-n-01    

# 3、為k8s-n-01設定污點(取消PreferNoSchedule,設定NoSchedule)
[root@k8s-m-01 ~]# kubectl taint nodes k8s-n-01 tag:PreferNoSchedule-
[root@k8s-m-01 ~]# kubectl taint nodes k8s-n-01 tag=heima:NoSchedule

# 4、創建pod2
[root@k8s-m-01 ~]# kubectl run taint2 --image=nginx:1.17.1 -n dev
[root@k8s-m-01 ~]# kubectl get pods taint2 -n dev -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP            NODE
taint1-7665f7fd85-574h4   1/1     Running   0          2m24s   10.244.1.59   k8s-n-01 
taint2-544694789-6zmlf    0/1     Pending   0          21s     <none>        <none>   

# 5、為k8s-n-01設定污點(取消NoSchedule,設定NoExecute)
[root@k8s-m-01 ~]# kubectl taint nodes k8s-n-01 tag:NoSchedule-
[root@k8s-m-01 ~]# kubectl taint nodes k8s-n-01 tag=heima:NoExecute

# 6、創建pod3
[root@k8s-m-01 ~]# kubectl run taint3 --image=nginx:1.17.1 -n dev
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED 
taint1-7665f7fd85-htkmp   0/1     Pending   0          35s   <none>   <none>   <none>    
taint2-544694789-bn7wb    0/1     Pending   0          35s   <none>   <none>   <none>     
taint3-6d78dbd749-tktkq   0/1     Pending   0          6s    <none>   <none>   <none>     
總結:
    使用kubeadm搭建的集群,默認就會給master節點添加一個污點標記,所以pod就不會調度到master節點上.
2、容忍(Toleration)

? 上面介紹了污點的作用,我們可以在node上添加污點用于拒絕pod調度上來,但是如果就是想將一個pod調度到一個有污點的node上去,這時候應該怎么做呢?這就要使用到容忍

在這里插入圖片描述

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

下面先通過一個案例看下效果:

  1. 上一小節,已經在k8s-n-01節點上打上了NoExecute的污點,此時pod是調度不上去的
  2. 本小節,可以通過給pod添加容忍,然后將其調度上去
1、創建pod-toleration.yaml,內容如下
apiVersion: v1
kind: Pod
metadata:
  name: pod-toleration
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  tolerations:      # 添加容忍
  - key: "tag"        # 要容忍的污點的key
    operator: "Equal" # 運算子
    value: "heima"    # 容忍的污點的value
    effect: "NoExecute"   # 添加容忍的規則,這里必須和標記的污點規則相同
# 添加容忍之前的pod
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED 
pod-toleration   0/1     Pending   0          3s    <none>   <none>   <none>           

# 添加容忍之后的pod
[root@k8s-m-01 ~]# kubectl get pods -n dev -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED
pod-toleration   1/1     Running   0          3s    10.244.1.62   k8s-n-01   <none>        
2、下面看一下容忍的詳細配置:
[root@k8s-m-01 ~]# kubectl explain pod.spec.tolerations
......
FIELDS:
   key       # 對應著要容忍的污點的鍵,空意味著匹配所有的鍵
   value     # 對應著要容忍的污點的值
   operator  # key-value的運算子,支持Equal和Exists(默認)
   effect    # 對應污點的effect,空意味著匹配所有影響
   tolerationSeconds   # 容忍時間, 當effect為NoExecute時生效,表示pod在Node上的停留時間

五、 Pod控制器詳解

1、Pod控制器介紹

Pod是kubernetes的最小管理單元,在kubernetes中,按照pod的創建方式可以將其分為兩類:

# 自主式pod:
kubernetes直接創建出來的Pod,這種pod洗掉后就沒有了,也不會重建
# 控制器創建的pod:
kubernetes通過控制器創建的pod,這種pod洗掉了之后還會自動重建   

什么是Pod控制器

Pod控制器是管理pod的中間層,使用Pod控制器之后,只需要告訴Pod控制器,想要多少個什么樣的Pod就可以了,它會創建出滿足條件的Pod并確保每一個Pod資源處于用戶期望的目標狀態,如果Pod資源在運行中出現故障,它會基于指定策略重新編排Pod,

在kubernetes中,有很多型別的pod控制器,每種都有自己的適合的場景,常見的有下面這些:

# 1、ReplicationController:
比較原始的pod控制器,已經被廢棄,由ReplicaSet替代

# 2、ReplicaSet:
保證副本數量一直維持在期望值,并支持pod數量擴縮容,鏡像版本升級

# 3、Deployment:
通過控制ReplicaSet來控制Pod,并支持滾動升級、回退版本

# 4、Horizontal Pod Autoscaler:
可以根據集群負載自動水平調整Pod的數量,實作削峰填谷

# 5、DaemonSet:
在集群中的指定Node上運行且僅運行一個副本,一般用于守護行程類的任務

# 6、Job:
它創建出來的pod只要完成任務就立即退出,不需要重啟或重建,用于執行一次性任務

# 7、Cronjob:
它創建的Pod負責周期性任務控制,不需要持續后臺運行

# 8、StatefulSet:
管理有狀態應用

2、ReplicaSet(RS)

? ReplicaSet的主要作用是保證一定數量的pod正常運行,它會持續監聽這些Pod的運行狀態,一旦Pod發生故障,就會重啟或重建,同時它還支持對pod數量的擴縮容和鏡像版本的升降級

在這里插入圖片描述

ReplicaSet的資源清單檔案:

apiVersion: apps/v1 # 版本號
kind: ReplicaSet # 型別       
metadata: # 元資料
  name: # rs名稱 
  namespace: # 所屬命名空間 
  labels: #標簽
    controller: rs
spec: # 詳情描述
  replicas: 3 # 副本數量
  selector: # 選擇器,通過它指定該控制器管理哪些pod
    matchLabels:      # Labels匹配規則
      app: nginx-pod
    matchExpressions: # Expressions匹配規則
      - {key: app, operator: In, values: [nginx-pod]}
  template: # 模板,當副本數量不足時,會根據下面的模板創建pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

在這里面,需要新了解的配置項就是spec下面幾個選項:

  • replicas:指定副本數量,其實就是當前rs創建出來的pod的數量,默認為1

  • selector:選擇器,它的作用是建立pod控制器和pod之間的關聯關系,采用的Label Selector機制

    ? 在pod模板上定義label,在控制器上定義選擇器,就可以表明當前控制器能管理哪些pod了

  • template:模板,就是當前控制器創建pod所使用的模板板,里面其實就是前一章學過的pod的定義

1、創建ReplicaSet

創建pc-replicaset.yaml檔案,內容如下:

apiVersion: apps/v1
kind: ReplicaSet   
metadata:
  name: pc-replicaset
  namespace: dev
spec:
  replicas: 3
  selector: 
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx
# 1、創建rs
[root@k8s-m-01 ~]# kubectl create -f pc-replicaset.yaml
replicaset.apps/pc-replicaset created

# 2、查看rs
# DESIRED:期望副本數量  
# CURRENT:當前副本數量  
# READY:已經準備好提供服務的副本數量
[root@k8s-m-01 ~]# kubectl get rs pc-replicaset -n dev -o wide
NAME          DESIRED   CURRENT READY AGE   CONTAINERS   IMAGES             SELECTOR
pc-replicaset 3         3       3     22s   nginx        nginx       app=nginx-pod

# 查看當前控制器創建出來的pod
# 這里發現控制器創建出來的pod的名稱是在控制器名稱后面拼接了-xxxxx隨機碼
[root@k8s-m-01 ~]# kubectl get pod -n dev
NAME                          READY   STATUS    RESTARTS   AGE
pc-replicaset-6vmvt   1/1     Running   0          54s
pc-replicaset-fmb8f   1/1     Running   0          54s
pc-replicaset-snrk2   1/1     Running   0          54s
2、擴縮容
# 1、編輯rs的副本數量,修改spec:replicas: 6即可
[root@k8s-m-01 ~]# kubectl edit rs pc-replicaset -n dev
replicaset.apps/pc-replicaset edited

# 2、查看pod
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME                          READY   STATUS    RESTARTS   AGE
pc-replicaset-6vmvt   1/1     Running   0          114m
pc-replicaset-cftnp   1/1     Running   0          10s
pc-replicaset-fjlm6   1/1     Running   0          10s
pc-replicaset-fmb8f   1/1     Running   0          114m
pc-replicaset-s2whj   1/1     Running   0          10s
pc-replicaset-snrk2   1/1     Running   0          114m

# 當然也可以直接使用命令實作
# 3、使用scale命令實作擴縮容, 后面--replicas=n直接指定目標數量即可
[root@k8s-m-01 ~]# kubectl scale rs pc-replicaset --replicas=2 -n dev
replicaset.apps/pc-replicaset scaled

# 命令運行完畢,立即查看,發現已經有4個開始準備退出了
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME                       READY   STATUS        RESTARTS   AGE
pc-replicaset-6vmvt   0/1     Terminating   0          118m
pc-replicaset-cftnp   0/1     Terminating   0          4m17s
pc-replicaset-fjlm6   0/1     Terminating   0          4m17s
pc-replicaset-fmb8f   1/1     Running       0          118m
pc-replicaset-s2whj   0/1     Terminating   0          4m17s
pc-replicaset-snrk2   1/1     Running       0          118m

# 4、稍等片刻,就只剩下2個了
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME                       READY   STATUS    RESTARTS   AGE
pc-replicaset-fmb8f   1/1     Running   0          119m
pc-replicaset-snrk2   1/1     Running   0          119m
3、鏡像升級
# 1、編輯rs的容器鏡像 - image: nginx:1.17.2
[root@k8s-m-01 ~]# kubectl edit rs pc-replicaset -n dev
replicaset.apps/pc-replicaset edited

# 2、再次查看,發現鏡像版本已經變更了
[root@k8s-m-01 ~]# kubectl get rs -n dev -o wide
NAME                DESIRED  CURRENT   READY   AGE    CONTAINERS   IMAGES        ...
pc-replicaset       2        2         2       140m   nginx         nginx:1.17.2  ...

# 同樣的道理,也可以使用命令完成這個作業
# kubectl set image rs rs名稱 容器=鏡像版本 -n namespace
[root@k8s-m-01 ~]# kubectl set image rs pc-replicaset nginx=nginx  -n dev
replicaset.apps/pc-replicaset image updated

# 3、再次查看,發現鏡像版本已經變更了
[root@k8s-m-01 ~]# kubectl get rs -n dev -o wide
NAME                 DESIRED  CURRENT   READY   AGE    CONTAINERS   IMAGES            ...
pc-replicaset        2        2         2       145m   nginx        nginx ... 
4、洗掉ReplicaSet
# 1、使用kubectl delete命令會洗掉此RS以及它管理的Pod
# 在kubernetes洗掉RS前,會將RS的replicasclear調整為0,等待所有的Pod被洗掉后,在執行RS物件的洗掉
[root@k8s-m-01 ~]# kubectl delete rs pc-replicaset -n dev
replicaset.apps "pc-replicaset" deleted
[root@k8s-m-01 ~]# kubectl get pod -n dev -o wide
No resources found in dev namespace.

# 2、如果希望僅僅洗掉RS物件(保留Pod),可以使用kubectl delete命令時添加--cascade=false選項(不推薦),
[root@k8s-m-01 ~]# kubectl delete rs pc-replicaset -n dev --cascade=false
replicaset.apps "pc-replicaset" deleted
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME                  READY   STATUS    RESTARTS   AGE
pc-replicaset-cl82j   1/1     Running   0          75s
pc-replicaset-dslhb   1/1     Running   0          75s

# 3、也可以使用yaml直接洗掉(推薦)
[root@k8s-m-01 ~]# kubectl delete -f pc-replicaset.yaml
replicaset.apps "pc-replicaset" deleted

3、Deployment(Deploy)

1、deployment是通過標簽去管理pod的
2、deployment控制器會無限接近理想狀態

# 1、Deployment:一般用來部署長期運行的、無狀態的應用
	特點:集群之中,隨機部署(每一次請求都不依賴歷史資料,也無資料持久化需求)
	
精確匹配: # matchLabels
模糊匹配: # matchExpressions

? 為了更好的解決服務編排的問題,kubernetes在V1.2版本開始,引入了Deployment控制器,值得一提的是,這種控制器并不直接管理pod,而是通過管理ReplicaSet來簡介管理Pod,即:Deployment管理ReplicaSet,ReplicaSet管理Pod,所以Deployment比ReplicaSet功能更加強大,

在這里插入圖片描述

Deployment主要功能有下面幾個:

  • 支持ReplicaSet的所有功能
  • 支持發布的停止、繼續
  • 支持滾動升級和回滾版本

Deployment的資源清單檔案:

apiVersion: apps/v1 # 版本號
kind: Deployment # 型別       
metadata: # 元資料
  name: # rs名稱 
  namespace: # 所屬命名空間 
  labels: #標簽
    controller: deploy
spec: # 詳情描述
  replicas: 3 # 副本數量
  revisionHistoryLimit: 3 # 保留歷史版本
  paused: false # 暫停部署,默認是false
  progressDeadlineSeconds: 600 # 部署超時時間(s),默認是600
  strategy: # 策略
    type: RollingUpdate # 滾動更新策略
    rollingUpdate: # 滾動更新
      maxSurge: 30% # 最大額外可以存在的副本數,可以為百分比,也可以為整數
      maxUnavailable: 30% # 最大不可用狀態的 Pod 的最大值,可以為百分比,也可以為整數
  selector: # 選擇器,通過它指定該控制器管理哪些pod
    matchLabels:      # Labels匹配規則
      app: nginx-pod
    matchExpressions: # Expressions匹配規則
      - {key: app, operator: In, values: [nginx-pod]}
  template: # 模板,當副本數量不足時,會根據下面的模板創建pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

在這里插入圖片描述

1、創建deployment

創建pc-deployment.yaml,內容如下:

apiVersion: apps/v1
kind: Deployment      
metadata:
  name: pc-deployment
  namespace: dev
spec: 
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx

# 1、創建deployment
[root@k8s-m-01 ~]# kubectl create -f pc-deployment.yaml --record=true
deployment.apps/pc-deployment created

# 2、查看deployment
# UP-TO-DATE 最新版本的pod的數量
# AVAILABLE  當前可用的pod的數量
[root@k8s-m-01 ~]# kubectl get deploy pc-deployment -n dev
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
pc-deployment   3/3     3            3           15s

# 3、查看rs
# 發現rs的名稱是在原來deployment的名字后面添加了一個10位數的隨機串
[root@k8s-m-01 ~]# kubectl get rs -n dev
NAME                       DESIRED   CURRENT   READY   AGE
pc-deployment-6696798b78   3         3         3       23s

# 4、查看pod
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-6696798b78-d2c8n   1/1     Running   0          107s
pc-deployment-6696798b78-smpvp   1/1     Running   0          107s
pc-deployment-6696798b78-wvjd8   1/1     Running   0          107s

2、擴縮容
# 1、變更副本數量為5個
[root@k8s-m-01 ~]# kubectl scale deploy pc-deployment --replicas=5  -n dev
deployment.apps/pc-deployment scaled

# 2、查看deployment
[root@k8s-m-01 ~]# kubectl get deploy pc-deployment -n dev
NAME            READY   UP-TO-DATE   AVAILABLE   AGE
pc-deployment   5/5     5            5           2m

# 3、查看pod
[root@k8s-m-01 ~]#  kubectl get pods -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-6696798b78-d2c8n   1/1     Running   0          4m19s
pc-deployment-6696798b78-jxmdq   1/1     Running   0          94s
pc-deployment-6696798b78-mktqv   1/1     Running   0          93s
pc-deployment-6696798b78-smpvp   1/1     Running   0          4m19s
pc-deployment-6696798b78-wvjd8   1/1     Running   0          4m19s

# 4、編輯deployment的副本數量,修改spec:replicas: 4即可
[root@k8s-m-01 ~]# kubectl edit deploy pc-deployment -n dev
deployment.apps/pc-deployment edited

# 5、查看pod
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-6696798b78-d2c8n   1/1     Running   0          5m23s
pc-deployment-6696798b78-jxmdq   1/1     Running   0          2m38s
pc-deployment-6696798b78-smpvp   1/1     Running   0          5m23s
pc-deployment-6696798b78-wvjd8   1/1     Running   0          5m23s

3、鏡像更新

deployment支持兩種更新策略:重建更新滾動更新,可以通過strategy指定策略型別,支持兩個屬性:

strategy:指定新的Pod替換舊的Pod的策略, 支持兩個屬性:
  type:指定策略型別,支持兩種策略
    Recreate:在創建出新的Pod之前會先殺掉所有已存在的Pod
    RollingUpdate:滾動更新,就是殺死一部分,就啟動一部分,在更新程序中,存在兩個版本Pod
  rollingUpdate:當type為RollingUpdate時生效,用于為RollingUpdate設定引數,支持兩個屬性:
    maxUnavailable:用來指定在升級程序中不可用Pod的最大數量,默認為25%,
    maxSurge: 用來指定在升級程序中可以超過期望的Pod的最大數量,默認為25%,
4、重建更新
  1. 編輯pc-deployment.yaml,在spec節點下添加更新策略
spec:
  strategy: # 策略
    type: Recreate # 重建更新
  1. 創建deploy進行驗證
# 1、變更鏡像
[root@k8s-m-01 ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.2 -n dev
deployment.apps/pc-deployment image updated

# 2、觀察升級程序
[root@k8s-m-01 ~]#  kubectl get pods -n dev -w
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-5d89bdfbf9-65qcw   1/1     Running   0          31s
pc-deployment-5d89bdfbf9-w5nzv   1/1     Running   0          31s
pc-deployment-5d89bdfbf9-xpt7w   1/1     Running   0          31s

pc-deployment-5d89bdfbf9-xpt7w   1/1     Terminating   0          41s
pc-deployment-5d89bdfbf9-65qcw   1/1     Terminating   0          41s
pc-deployment-5d89bdfbf9-w5nzv   1/1     Terminating   0          41s

pc-deployment-675d469f8b-grn8z   0/1     Pending       0          0s
pc-deployment-675d469f8b-hbl4v   0/1     Pending       0          0s
pc-deployment-675d469f8b-67nz2   0/1     Pending       0          0s

5、滾動更新
  1. 編輯pc-deployment.yaml,在spec節點下添加更新策略
spec:
  strategy: # 策略
    type: RollingUpdate # 滾動更新策略
    rollingUpdate:
      maxSurge: 25% 
      maxUnavailable: 25%
  1. 創建deploy進行驗證
# 1、變更鏡像
[root@k8s-m-01 ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.3 -n dev
deployment.apps/pc-deployment image updated

# 2、觀察升級程序
[root@k8s-m-01 ~]# kubectl get pods -n dev -w
NAME                           READY   STATUS    RESTARTS   AGE
pc-deployment-c848d767-8rbzt   1/1     Running   0          31m
pc-deployment-c848d767-h4p68   1/1     Running   0          31m
pc-deployment-c848d767-hlmz4   1/1     Running   0          31m
pc-deployment-c848d767-rrqcn   1/1     Running   0          31m

# 至此,新版本的pod創建完畢,就版本的pod銷毀完畢
# 中間程序是滾動進行的,也就是邊銷毀邊創建
6、滾動更新的程序:

在這里插入圖片描述

鏡像更新中rs的變化:

# 查看rs,發現原來的rs的依舊存在,只是pod數量變為了0,而后又新產生了一個rs,pod數量為4
# 其實這就是deployment能夠進行版本回退的奧妙所在,后面會詳細解釋
[root@k8s-m-01 ~]# kubectl get rs -n dev
NAME                       DESIRED   CURRENT   READY   AGE
pc-deployment-6696798b78   0         0         0       7m37s
pc-deployment-6696798b11   0         0         0       5m37s
pc-deployment-c848d76789   4         4         4       72s
7、版本回退

deployment支持版本升級程序中的暫停、繼續功能以及版本回退等諸多功能,下面具體來看.

kubectl rollout: 版本升級相關功能,支持下面的選項:

  • status 顯示當前升級狀態

  • history 顯示 升級歷史記錄

  • pause 暫停版本升級程序

  • resume 繼續已經暫停的版本升級程序

  • restart 重啟版本升級程序

  • undo 回滾到上一級版本(可以使用–to-revision回滾到指定版本)

# 1、查看當前升級版本的狀態
[root@k8s-m-01 ~]# kubectl rollout status deploy pc-deployment -n dev
deployment "pc-deployment" successfully rolled out

# 2、查看升級歷史記錄
[root@k8s-m-01 ~]# kubectl rollout history deploy pc-deployment -n dev
deployment.apps/pc-deployment
REVISION  CHANGE-CAUSE
1         kubectl create --filename=pc-deployment.yaml --record=true
2         kubectl create --filename=pc-deployment.yaml --record=true
3         kubectl create --filename=pc-deployment.yaml --record=true
# 可以發現有三次版本記錄,說明完成過兩次升級

# 3、版本回滾
# 這里直接使用--to-revision=1回滾到了1版本, 如果省略這個選項,就是回退到上個版本,就是2版本
[root@k8s-m-01 ~]# kubectl rollout undo deployment pc-deployment --to-revision=1 -n dev
deployment.apps/pc-deployment rolled back

# 4、查看發現,通過nginx鏡像版本可以發現到了第一版
[root@k8s-m-01 ~]# kubectl get deploy -n dev -o wide
NAME            READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         
pc-deployment   4/4     4            4           74m   nginx        nginx   

# 查看rs,發現第一個rs中有4個pod運行,后面兩個版本的rs中pod為運行
# 其實deployment之所以可是實作版本的回滾,就是通過記錄下歷史rs來實作的,
# 一旦想回滾到哪個版本,只需要將當前版本pod數量降為0,然后將回滾版本的pod提升為目標數量就可以了
[root@k8s-m-01 ~]# kubectl get rs -n dev
NAME                       DESIRED   CURRENT   READY   AGE
pc-deployment-6696798b78   4         4         4       78m
pc-deployment-966bf7f44    0         0         0       37m
pc-deployment-c848d767     0         0         0       71m
8、金絲雀發布

? Deployment控制器支持控制更新程序中的控制,如“暫停(pause)”或“繼續(resume)”更新操作,

? 比如有一批新的Pod資源創建完成后立即暫停更新程序,此時,僅存在一部分新版本的應用,主體部分還是舊的版本,然后,再篩選一小部分的用戶請求路由到新版本的Pod應用,繼續觀察能否穩定地按期望的方式運行,確定沒問題之后再繼續完成余下的Pod資源滾動更新,否則立即回滾更新操作,這就是所謂的金絲雀發布,

# 1、更新deployment的版本,并配置暫停deployment
[root@k8s-m-01 ~]#  kubectl set image deploy pc-deployment nginx=nginx:1.17.4 -n dev && kubectl rollout pause deployment pc-deployment  -n dev
deployment.apps/pc-deployment image updated
deployment.apps/pc-deployment paused

# 2、觀察更新狀態
[root@k8s-m-01 ~]# kubectl rollout status deploy pc-deployment -n dev 
Waiting for deployment "pc-deployment" rollout to finish: 2 out of 4 new replicas have been updated...

# 監控更新的程序,可以看到已經新增了一個資源,但是并未按照預期的狀態去洗掉一個舊的資源,就是因為使用了pause暫停命令

[root@k8s-m-01 ~]# kubectl get rs -n dev -o wide
NAME                       DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES         
pc-deployment-5d89bdfbf9   3         3         3       19m     nginx        nginx   
pc-deployment-675d469f8b   0         0         0       14m     nginx        nginx:1.17.2   
pc-deployment-6c9f56fcfb   2         2         2       3m16s   nginx        nginx:1.17.4   
[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-5d89bdfbf9-rj8sq   1/1     Running   0          7m33s
pc-deployment-5d89bdfbf9-ttwgg   1/1     Running   0          7m35s
pc-deployment-5d89bdfbf9-v4wvc   1/1     Running   0          7m34s
pc-deployment-6c9f56fcfb-996rt   1/1     Running   0          3m31s
pc-deployment-6c9f56fcfb-j2gtj   1/1     Running   0          3m31s

# 3、確保更新的pod沒問題了,繼續更新
[root@k8s-m-01 ~]# kubectl rollout resume deploy pc-deployment -n dev
deployment.apps/pc-deployment resumed

# 4、查看最后的更新情況
[root@k8s-m-01 ~]# kubectl get rs -n dev -o wide
NAME                       DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES         
pc-deployment-5d89bdfbf9   0         0         0       21m     nginx        nginx   
pc-deployment-675d469f8b   0         0         0       16m     nginx        nginx:1.17.2   
pc-deployment-6c9f56fcfb   4         4         4       5m11s   nginx        nginx:1.17.4   

[root@k8s-m-01 ~]# kubectl get pods -n dev
NAME                             READY   STATUS    RESTARTS   AGE
pc-deployment-6c9f56fcfb-7bfwh   1/1     Running   0          37s
pc-deployment-6c9f56fcfb-996rt   1/1     Running   0          5m27s
pc-deployment-6c9f56fcfb-j2gtj   1/1     Running   0          5m27s
pc-deployment-6c9f56fcfb-rf84v   1/1     Running   0          37s

洗掉Deployment

# 洗掉deployment,其下的rs和pod也將被洗掉
[root@k8s-m-01 ~]# kubectl delete -f pc-deployment.yaml
deployment.apps "pc-deployment" deleted

4、Horizontal Pod Autoscaler(HPA)

   在前面的課程中,我們已經可以實作通過手工執行`kubectl scale`命令實作Pod擴容或縮容,但是這顯然不符合Kubernetes的定位目標--自動化、智能化, Kubernetes期望可以實作通過監測Pod的使用情況,實作pod數量的自動調整,于是就產生了Horizontal Pod Autoscaler(HPA)這種控制器,

    HPA可以獲取每個Pod利用率,然后和HPA中定義的指標進行對比,同時計算出需要伸縮的具體值,最后實作Pod的數量的調整,其實HPA與之前的Deployment一樣,也屬于一種Kubernetes資源物件,它通過追蹤分析RC控制的所有目標Pod的負載變化情況,來確定是否需要針對性地調整目標Pod的副本數,這是HPA的實作原理,

在這里插入圖片描述

1 、安裝metrics-server

metrics-server可以用來收集集群中的資源使用情況

# 1、安裝git
[root@k8s-m-01 ~]# yum install git -y
# 2、獲取metrics-server, 注意使用的版本
[root@k8s-m-01 ~]# git clone -b v0.3.6 https://github.com/kubernetes-incubator/metrics-server
# 修改deployment, 注意修改的是鏡像和初始化引數
[root@k8s-m-01 ~]# cd /root/metrics-server/deploy/1.8+/
[root@master 1.8+]# vim metrics-server-deployment.yaml
按圖中添加下面選項
hostNetwork: true
image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server-amd64:v0.3.6
args:
- --kubelet-insecure-tls
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP

在這里插入圖片描述

# 1、安裝metrics-server
[root@master 1.8+]# kubectl apply -f ./

# 2、查看pod運行情況
[root@master 1.8+]# kubectl get pod -n kube-system
metrics-server-6b976979db-2xwbj   1/1     Running   0          90s

# 3、使用kubectl top node 查看資源使用情況
[root@master 1.8+]# kubectl top node
NAME     CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
master   98m          4%     1067Mi          62%
k8s-n-01    27m          1%     727Mi           42%
k8s-n-02    34m          1%     800Mi           46%
[root@master 1.8+]# kubectl top pod -n kube-system
NAME                              CPU(cores)   MEMORY(bytes)
coredns-6955765f44-7ptsb          3m           9Mi
coredns-6955765f44-vcwr5          3m           8Mi
etcd-master                       14m          145Mi
...
# 至此,metrics-server安裝完成
2、 準備deployment和servie

為了操作簡單,直接使用命令

# 1、創建deployment 
[root@master 1.8+]# kubectl run nginx --image=nginx:latest --requests=cpu=100m -n dev
# 2、創建service
[root@master 1.8+]# kubectl expose deployment nginx --type=NodePort --port=80 -n dev

# 3、查看
[root@master 1.8+]# kubectl get deployment,pod,svc -n dev
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           47s

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-7df9756ccc-bh8dr   1/1     Running   0          47s

NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/nginx   NodePort   10.109.57.248   <none>        80:31136/TCP   35s

3 、部署HPA

創建pc-hpa.yaml

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: pc-hpa
  namespace: dev
spec:
  minReplicas: 1  #最小pod數量
  maxReplicas: 10 #最大pod數量
  targetCPUUtilizationPercentage: 3 # CPU使用率指標
  scaleTargetRef:   # 指定要控制的nginx資訊
    apiVersion: apps/v1
    kind: Deployment  
    name: nginx  

# 1、創建hpa
[root@master 1.8+]# kubectl create -f pc-hpa.yaml
horizontalpodautoscaler.autoscaling/pc-hpa created

# 2、查看hpa
[root@master 1.8+]# kubectl get hpa -n dev
NAME     REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
pc-hpa   Deployment/nginx   0%/3%     1         10        1          62s

4 、測驗

使用壓測工具對service地址192.168.109.100:31136進行壓測,然后通過控制臺查看hpa和pod的變化

hpa變化

[root@k8s-m-01 ~]# kubectl get hpa -n dev -w
NAME     REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
pc-hpa   Deployment/nginx   0%/3%     1         10        1          4m11s
pc-hpa   Deployment/nginx   0%/3%     1         10        1          5m19s
pc-hpa   Deployment/nginx   22%/3%    1         10        1          6m50s
pc-hpa   Deployment/nginx   22%/3%    1         10        4          7m5s
pc-hpa   Deployment/nginx   22%/3%    1         10        8          7m21s
pc-hpa   Deployment/nginx   6%/3%     1         10        8          7m51s
pc-hpa   Deployment/nginx   0%/3%     1         10        8          9m6s
pc-hpa   Deployment/nginx   0%/3%     1         10        8          13m
pc-hpa   Deployment/nginx   0%/3%     1         10        1          14m

deployment變化

[root@k8s-m-01 ~]# kubectl get deployment -n dev -w
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           11m
nginx   1/4     1            1           13m
nginx   1/4     1            1           13m
nginx   1/4     1            1           13m
nginx   1/4     4            1           13m
nginx   1/8     4            1           14m
nginx   1/8     4            1           14m
nginx   1/8     4            1           14m
nginx   1/8     8            1           14m
nginx   2/8     8            2           14m
nginx   3/8     8            3           14m
nginx   4/8     8            4           14m
nginx   5/8     8            5           14m
nginx   6/8     8            6           14m
nginx   7/8     8            7           14m
nginx   8/8     8            8           15m
nginx   8/1     8            8           20m
nginx   8/1     8            8           20m
nginx   1/1     1            1           20m

pod變化

[root@k8s-m-01 ~]# kubectl get pods -n dev -w
NAME                     READY   STATUS    RESTARTS   AGE
nginx-7df9756ccc-bh8dr   1/1     Running   0          11m
nginx-7df9756ccc-cpgrv   0/1     Pending   0          0s
nginx-7df9756ccc-8zhwk   0/1     Pending   0          0s
nginx-7df9756ccc-rr9bn   0/1     Pending   0          0s
nginx-7df9756ccc-cpgrv   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-8zhwk   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-rr9bn   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-m9gsj   0/1     Pending             0          0s
nginx-7df9756ccc-g56qb   0/1     Pending             0          0s
nginx-7df9756ccc-sl9c6   0/1     Pending             0          0s
nginx-7df9756ccc-fgst7   0/1     Pending             0          0s
nginx-7df9756ccc-g56qb   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-m9gsj   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-sl9c6   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-fgst7   0/1     ContainerCreating   0          0s
nginx-7df9756ccc-8zhwk   1/1     Running             0          19s
nginx-7df9756ccc-rr9bn   1/1     Running             0          30s
nginx-7df9756ccc-m9gsj   1/1     Running             0          21s
nginx-7df9756ccc-cpgrv   1/1     Running             0          47s
nginx-7df9756ccc-sl9c6   1/1     Running             0          33s
nginx-7df9756ccc-g56qb   1/1     Running             0          48s
nginx-7df9756ccc-fgst7   1/1     Running             0          66s
nginx-7df9756ccc-fgst7   1/1     Terminating         0          6m50s
nginx-7df9756ccc-8zhwk   1/1     Terminating         0          7m5s
nginx-7df9756ccc-cpgrv   1/1     Terminating         0          7m5s
nginx-7df9756ccc-g56qb   1/1     Terminating         0          6m50s
nginx-7df9756ccc-rr9bn   1/1     Terminating         0          7m5s
nginx-7df9756ccc-m9gsj   1/1     Terminating         0          6m50s
nginx-7df9756ccc-sl9c6   1/1     Terminating         0          6m50s

5、DaemonSet(DS)

# DaemonSet:每一個節點上部署一個Pod,洗掉節點自動洗掉對應的POD(zabbix-agent)
	特點:每一臺上有且只有一臺

? DaemonSet型別的控制器可以保證在集群中的每一臺(或指定)節點上都運行一個副本,一般適用于日志收集、節點監控等場景,也就是說,如果一個Pod提供的功能是節點級別的(每個節點都需要且只需要一個),那么這類Pod就適合使用DaemonSet型別的控制器創建,

在這里插入圖片描述

DaemonSet控制器的特點:

  • 每當向集群中添加一個節點時,指定的 Pod 副本也將添加到該節點上
  • 當節點從集群中移除時,Pod 也就被垃圾回收了

下面先來看下DaemonSet的資源清單檔案

apiVersion: apps/v1 # 版本號
kind: DaemonSet # 型別       
metadata: # 元資料
  name: # rs名稱 
  namespace: # 所屬命名空間 
  labels: #標簽
    controller: daemonset
spec: # 詳情描述
  revisionHistoryLimit: 3 # 保留歷史版本
  updateStrategy: # 更新策略
    type: RollingUpdate # 滾動更新策略
    rollingUpdate: # 滾動更新
      maxUnavailable: 1 # 最大不可用狀態的 Pod 的最大值,可以為百分比,也可以為整數
  selector: # 選擇器,通過它指定該控制器管理哪些pod
    matchLabels:      # Labels匹配規則
      app: nginx-pod
    matchExpressions: # Expressions匹配規則
      - {key: app, operator: In, values: [nginx-pod]}
  template: # 模板,當副本數量不足時,會根據下面的模板創建pod副本
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

創建pc-daemonset.yaml,內容如下:

apiVersion: apps/v1
kind: DaemonSet      
metadata:
  name: pc-daemonset
  namespace: dev
spec: 
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx

# 1、創建daemonset
[root@k8s-m-01 ~]# kubectl create -f  pc-daemonset.yaml
daemonset.apps/pc-daemonset created

# 2、查看daemonset
[root@k8s-m-01 ~]#  kubectl get ds -n dev -o wide
NAME        DESIRED  CURRENT  READY  UP-TO-DATE  AVAILABLE   AGE   CONTAINERS   IMAGES         
pc-daemonset   2        2        2      2           2        24s   nginx        nginx   

# 3、查看pod,發現在每個Node上都運行一個pod
[root@k8s-m-01 ~]#  kubectl get pods -n dev -o wide
NAME                 READY   STATUS    RESTARTS   AGE   IP            NODE    
pc-daemonset-9bck8   1/1     Running   0          37s   10.244.1.43   k8s-n-01     
pc-daemonset-k224w   1/1     Running   0          37s   10.244.2.74   k8s-n-02      

# 4、洗掉daemonset
[root@k8s-m-01 ~]# kubectl delete -f pc-daemonset.yaml
daemonset.apps "pc-daemonset" deleted
# 5、更新
[root@k8s-m-01 k8s]# kubectl edit daemonsets zabbix-agent 
 - image: zabbix/zabbix-agent:5.2.4-centos
zabbix版本是5.2.4
# 6、回滾
[root@k8s-m-01 k8s]# kubectl rollout undo daemonset zabbix-agent 
daemonset.apps/zabbix-agent rolled back
# 回滾到指定版本
[root@k8s-m-01 k8s]# kubectl rollout history daemonset zabbix-agent 
daemonset.apps/zabbix-agent 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
[root@k8s-m-01 k8s]# kubectl rollout undo daemonset zabbix-agent --to-revision=1

# 7、擴展 (洗掉集群,重新添加)
[root@k8s-m-01 k8s]# kubectl delete nodes k8s-n-01  # 主節點洗掉n2從節點
[root@k8s-n-01 ~]# kubeadm reset
[root@k8s-n-01 ~]# rm -rf /etc/kubernetes/*
[root@k8s-m-01 ~]#  kubeadm token create    --print-join-command  # 主節點
從節點拿著token直接執行一下,就加入集群了

# 不支持彈性擴容,但是支持資源更新

6、Job

Job,主要用于負責**批量處理(一次要處理指定數量任務)短暫的一次性(每個任務僅運行一次就結束)**任務,Job特點如下:

  • 當Job創建的pod執行成功結束時,Job將記錄成功結束的pod數量
  • 當成功結束的pod達到指定的數量時,Job將完成執行

在這里插入圖片描述
Job的資源清單檔案:

apiVersion: batch/v1 # 版本號
kind: Job # 型別       
metadata: # 元資料
  name: # rs名稱 
  namespace: # 所屬命名空間 
  labels: #標簽
    controller: job
spec: # 詳情描述
  completions: 1 # 指定job需要成功運行Pods的次數,默認值: 1
  parallelism: 1 # 指定job在任一時刻應該并發運行Pods的數量,默認值: 1
  activeDeadlineSeconds: 30 # 指定job可運行的時間期限,超過時間還未結束,系統將會嘗試進行終止,
  backoffLimit: 6 # 指定job失敗后進行重試的次數,默認是6
  manualSelector: true # 是否可以使用selector選擇器選擇pod,默認是false
  selector: # 選擇器,通過它指定該控制器管理哪些pod
    matchLabels:      # Labels匹配規則
      app: counter-pod
    matchExpressions: # Expressions匹配規則
      - {key: app, operator: In, values: [counter-pod]}
  template: # 模板,當副本數量不足時,會根據下面的模板創建pod副本
    metadata:
      labels:
        app: counter-pod
    spec:
      restartPolicy: Never # 重啟策略只能設定為Never或者OnFailure
      containers:
      - name: counter
        image: busybox:1.30
        command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 2;done"]

關于重啟策略設定的說明:
    如果指定為OnFailure,則job會在pod出現故障時重啟容器,而不是創建pod,failed次數不變
    如果指定為Never,則job會在pod出現故障時創建新的pod,并且故障pod不會消失,也不會重啟,failed次數加1
    如果指定為Always的話,就意味著一直重啟,意味著job任務會重復去執行了,當然不對,所以不能設定為Always

創建pc-job.yaml,內容如下:

apiVersion: batch/v1
kind: Job      
metadata:
  name: pc-job
  namespace: dev
spec:
  manualSelector: true
  selector:
    matchLabels:
      app: counter-pod
  template:
    metadata:
      labels:
        app: counter-pod
    spec:
      restartPolicy: Never
      containers:
      - name: counter
        image: busybox:1.30
        command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 3;done"]

# 1、創建job
[root@k8s-m-01 ~]# kubectl create -f pc-job.yaml
job.batch/pc-job created

# 2、查看job
[root@k8s-m-01 ~]# kubectl get job -n dev -o wide  -w
NAME     COMPLETIONS   DURATION   AGE   CONTAINERS   IMAGES         SELECTOR
pc-job   0/1           21s        21s   counter      busybox:1.30   app=counter-pod
pc-job   1/1           31s        79s   counter      busybox:1.30   app=counter-pod

# 3、通過觀察pod狀態可以看到,pod在運行完畢任務后,就會變成Completed狀態
[root@k8s-m-01 ~]# kubectl get pods -n dev -w
NAME           READY   STATUS     RESTARTS      AGE
pc-job-rxg96   1/1     Running     0            29s
pc-job-rxg96   0/1     Completed   0            33s

# 接下來,調整下pod運行的總數量和并行數量 即:在spec下設定下面兩個選項
#  completions: 6 # 指定job需要成功運行Pods的次數為6
#  parallelism: 3 # 指定job并發運行Pods的數量為3
#  然后重新運行job,觀察效果,此時會發現,job會每次運行3個pod,總共執行了6個pod
[root@k8s-m-01 ~]# kubectl get pods -n dev -w
NAME           READY   STATUS    RESTARTS   AGE
pc-job-684ft   1/1     Running   0          5s
pc-job-jhj49   1/1     Running   0          5s
pc-job-pfcvh   1/1     Running   0          5s
pc-job-684ft   0/1     Completed   0          11s
pc-job-v7rhr   0/1     Pending     0          0s
pc-job-v7rhr   0/1     Pending     0          0s
pc-job-v7rhr   0/1     ContainerCreating   0          0s
pc-job-jhj49   0/1     Completed           0          11s
pc-job-5vg2j   0/1     Completed           0          12s

# 洗掉job
[root@k8s-m-01 ~]# kubectl delete -f pc-job.yaml
job.batch "pc-job" deleted

7、CronJob(CJ)

? CronJob控制器以Job控制器資源為其管控物件,并借助它管理pod資源物件,Job控制器定義的作業任務在其控制器資源創建之后便會立即執行,但CronJob可以以類似于Linux作業系統的周期性任務作業計劃的方式控制其運行時間點重復運行的方式,也就是說,CronJob可以在特定的時間點(反復的)去運行job任務

在這里插入圖片描述

1、CronJob的資源清單檔案:
apiVersion: batch/v1beta1 # 版本號
kind: CronJob # 型別       
metadata: # 元資料
  name: # rs名稱 
  namespace: # 所屬命名空間 
  labels: #標簽
    controller: cronjob
spec: # 詳情描述
  schedule: # cron格式的作業調度運行時間點,用于控制任務在什么時間執行
  concurrencyPolicy: # 并發執行策略,用于定義前一次作業運行尚未完成時是否以及如何運行后一次的作業
  failedJobHistoryLimit: # 為失敗的任務執行保留的歷史記錄數,默認為1
  successfulJobHistoryLimit: # 為成功的任務執行保留的歷史記錄數,默認為3
  startingDeadlineSeconds: # 啟動作業錯誤的超時時長
  jobTemplate: # job控制器模板,用于為cronjob控制器生成job物件;下面其實就是job的定義
    metadata:
    spec:
      completions: 1
      parallelism: 1
      activeDeadlineSeconds: 30
      backoffLimit: 6
      manualSelector: true
      selector:
        matchLabels:
          app: counter-pod
        matchExpressions: 規則
          - {key: app, operator: In, values: [counter-pod]}
      template:
        metadata:
          labels:
            app: counter-pod
        spec:
          restartPolicy: Never 
          containers:
          - name: counter
            image: busybox:1.30
            command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 20;done"]

2、需要重點解釋的幾個選項:
# schedule: cron運算式,用于指定任務的執行時間
	*/1    *      *    *     *
	<分鐘> <小時> <日> <月份> <星期>

    分鐘 值從 0 到 59.
    小時 值從 0 到 23.
    日 值從 1 到 31.
    月 值從 1 到 12.
    星期 值從 0 到 6, 0 代表星期日
    多個時間可以用逗號隔開; 范圍可以用連字符給出;*可以作為通配符; /表示每...
# concurrencyPolicy:
	Allow:   允許Jobs并發運行(默認)
	Forbid:  禁止并發運行,如果上一次運行尚未完成,則跳過下一次運行
	Replace: 替換,取消當前正在運行的作業并用新作業替換它
3、創建pc-cronjob.yaml,內容如下:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: pc-cronjob
  namespace: dev
  labels:
    controller: cronjob
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    metadata:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: counter
            image: busybox:1.30
            command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 3;done"]
4、查看
# 1、創建cronjob
[root@k8s-m-01 ~]# kubectl create -f pc-cronjob.yaml
cronjob.batch/pc-cronjob created

# 2、查看cronjob
[root@k8s-m-01 ~]# kubectl get cronjobs -n dev
NAME         SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
pc-cronjob   */1 * * * *   False     0        <none>          6s

# 3、查看job
[root@k8s-m-01 ~]# kubectl get jobs -n dev
NAME                    COMPLETIONS   DURATION   AGE
pc-cronjob-1592587800   1/1           28s        3m26s
pc-cronjob-1592587860   1/1           28s        2m26s
pc-cronjob-1592587920   1/1           28s        86s

# 4、查看pod
[root@k8s-m-01 ~]# kubectl get pods -n dev
pc-cronjob-1592587800-x4tsm   0/1     Completed   0          2m24s
pc-cronjob-1592587860-r5gv4   0/1     Completed   0          84s
pc-cronjob-1592587920-9dxxq   1/1     Running     0          24s


# 5、洗掉cronjob
[root@k8s-m-01 ~]# kubectl  delete -f pc-cronjob.yaml
cronjob.batch "pc-cronjob" deleted

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/292312.html

標籤:其他

上一篇:Zabbix監控平臺部署實驗——自定義zabbix監控專案

下一篇:C++ 多型

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more