1. 程式人生 > 其它 >k8s學習筆記-儲存-排程器和排程演算法

k8s學習筆記-儲存-排程器和排程演算法

目錄

configMap 描述資訊

ConfigMap 功能在 Kubernetes1.2 版本中引入,許多應用程式會從配置檔案、命令列引數或環境變數中讀取配置資訊。ConfigMap API 給我們提供了向容器中注入配置資訊的機制,ConfigMap 可以被用來儲存單個屬性,也可以用來儲存整個配置檔案或者 JSON 二進位制等物件

 

ConfigMap 的建立

Ⅰ、使用目錄建立

 $ ls docs/user-guide/configmap/kubectl/
    game.file
    ui.file
 
 $ cat docs/user-guide/configmap/kubectl/game.file
 version=1.17
 name=dave
 age=18
 
 $ cat docs/user-guide/configmap/kubectl/ui.properties
 level=2
 color=yellow
 
 
 $ kubectl create configmap game-config --from-file=docs/user-guide/configmap/kubectl

—from-file 指定在目錄下的所有檔案都會被用在 ConfigMap 裡面建立一個鍵值對,鍵的名字就是檔名,值就是檔案的內容

 

Ⅱ、使用檔案建立

只要指定為一個檔案就可以從單個檔案中建立 ConfigMap

 $ kubectl create configmap game-config-2 --from-file=./game.file

—from-file 這個引數可以使用多次,你可以使用兩次分別指定上個例項中的那兩個配置檔案,效果就跟指定整個目錄是一樣的

 

Ⅲ、使用字面值建立

使用文字值建立,利用 —from-literal 引數傳遞配置資訊,該引數可以使用多次,格式如下

 $ kubectl create configmap literal-config --from-literal=name=dave --from-literal=password=pass
 
 $ kubectl get configmaps literal-config -o yaml

 

Pod 中使用 ConfigMap

Ⅰ、使用 ConfigMap 來替代環境變數

 apiVersion: v1
 kind: ConfigMap
 metadata:
  name: literal-config
  namespace: default
 data:
  name: dave
  password: pass
 apiVersion: v1
 kind: ConfigMap
 metadata:
  name: env-config
  namespace: default
 data:
  log_level: INFO
 apiVersion: v1
 kind: Pod
 metadata:
  name: cm-env-test-pod
 spec:
  containers:
    - name: test-container
      image: wangyanglinux/myapp:v1
      command: [ "/bin/sh", "-c", "env" ]
      env:
        - name: USERNAME
          valueFrom:
            configMapKeyRef:
              name: literal-config
              key: name
        - name: PASSWORD
          valueFrom:
            configMapKeyRef:
              name: literal-config
              key: password
      envFrom:
        - configMapRef:
            name: env-config
  restartPolicy: Never

 

Ⅱ、用 ConfigMap 設定命令列引數
 apiVersion: v1
 kind: Pod
 metadata:
  name: cm-command-dapi-test-pod
 spec:
  containers:
    - name: test-container
      image: wangyanglinux/myapp:v1
      command: [ "/bin/sh", "-c", "echo $(USERNAME) $(PASSWORD)" ]
      env:
        - name: USERNAME
          valueFrom:
            configMapKeyRef:
              name: literal-config
              key: name
        - name: PASSWORD
          valueFrom:
            configMapKeyRef:
              name: literal-config
              key: password
  restartPolicy: Never

 

Ⅲ、通過資料卷外掛使用ConfigMap

在資料卷裡面使用這個 ConfigMap,有不同的選項。最基本的就是將檔案填入資料卷,在這個檔案中,鍵就是檔名,鍵值就是檔案內容

 apiVersion: v1
 kind: Pod
 metadata:
  name: cm-volume-test-pod
 spec:
  containers:
    - name: test-container
      image: wangyanglinux/myapp:v1
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: literal-config
  restartPolicy: Never

 

ConfigMap 的熱更新

apiVersion: v1
kind: ConfigMap
metadata:
  name: log-config
  namespace: default
data:
  log_level: INFO
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: hot-update
spec:
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: wangyanglinux/myapp:v1
        ports:
        - containerPort: 80
        volumeMounts:
        - name: config-volume
          mountPath: /etc/config
      volumes:
        - name: config-volume
          configMap:
            name: log-config
$ kubectl exec `kubectl get pods -l run=my-nginx  -o=name|cut -d "/" -f2` cat /etc/config/log_level
INFO

修改 ConfigMap

$ kubectl edit configmap log-config

修改 log_level 的值為 DEBUG 等待大概 10 秒鐘時間,再次檢視環境變數的值

$ kubectl exec `kubectl get pods -l run=my-nginx  -o=name|cut -d "/" -f2` cat /tmp/log_level
DEBUG

<!--!!! 特別注意 configMap 如果以 ENV 的方式掛載至容器,修改 configMap 並不會實現熱更新-->

ConfigMap 更新後滾動更新 Pod

更新 ConfigMap 目前並不會觸發相關 Pod 的滾動更新,可以通過修改 pod annotations 的方式強制觸發滾動更新

$ kubectl patch deployment my-nginx --patch '{"spec": {"template": {"metadata": {"annotations": {"version/config": "20190411" }}}}}'

這個例子裡我們在 .spec.template.metadata.annotations 中新增 version/config,每次通過修改 version/config 來觸發滾動更新

 

!!! 更新 ConfigMap 後:

  • 使用該 ConfigMap 掛載的 Env 不會同步更新

  • 使用該 ConfigMap 掛載的 Volume 中的資料需要一段時間(實測大概10秒)才能同步更新

  •  

Secret 存在意義

Secret 解決了密碼、token、金鑰等敏感資料的配置問題,而不需要把這些敏感資料暴露到映象或者 Pod Spec 中。Secret 可以以 Volume 或者環境變數的方式使用

Secret 有三種類型:

  • Service Account :用來訪問 Kubernetes API,由 Kubernetes 自動建立,並且會自動掛載到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目錄中
  • Opaque :base64 編碼格式的 Secret,用來儲存密碼、金鑰等
  • kubernetes.io/dockerconfigjson :用來儲存私有 docker 倉庫的認證資訊

Service Account

Service Account 用來訪問 Kubernetes API,由 Kubernetes 自動建立,並且會自動掛載到 Pod的 /run/secrets/kubernetes.io/serviceaccount 目錄中

$ kubectl run nginx --image nginx
deployment "nginx" created
$ kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
nginx-3137573019-md1u2   1/1       Running   0          13s
$ kubectl exec nginx-3137573019-md1u2 ls /run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token

Opaque Secret

Ⅰ、建立說明

Opaque 型別的資料是一個 map 型別,要求 value 是 base64 編碼格式:

$ echo -n "admin" | base64
YWRtaW4=
$ echo -n "1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm

secrets.yml

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  password: MWYyZDFlMmU2N2Rm
  username: YWRtaW4=
Ⅱ、使用方式

1、將 Secret 掛載到 Volume 中

apiVersion: v1
kind: Pod
metadata:
  labels:
    name: seret-test
  name: seret-test
spec:
  volumes:
  - name: volumes12
    secret:
      secretName: mysecret
  containers:
  - image: wangyanglinux/myapp:v1
    name: db
    volumeMounts:
    - name: volumes12
      mountPath: "/data"

2、將 Secret 匯出到環境變數中

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: pod-deployment
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: pod-deployment
    spec:
      containers:
      - name: pod-1
        image: wangyanglinux/myapp:v1
        ports:
        - containerPort: 80
        env:
        - name: TEST_USER
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: username
        - name: TEST_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: password

kubernetes.io/dockerconfigjson

使用 Kuberctl 建立 docker 倉庫認證的 secret

$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL
secret "myregistrykey" created.

在建立 Pod 的時候,通過 imagePullSecrets 來引用剛建立的 myregistrykey

apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
    - name: foo
      image: hub.hongfu.com/wangyang/myapp:v1
  imagePullSecrets:
    - name: myregistrykey

容器磁碟上的檔案的生命週期是短暫的,這就使得在容器中執行重要應用時會出現一些問題。首先,當容器崩潰時,kubelet 會重啟它,但是容器中的檔案將丟失——容器以乾淨的狀態(映象最初的狀態)重新啟動。其次,在 Pod 中同時執行多個容器時,這些容器之間通常需要共享檔案。Kubernetes 中的 Volume 抽象就很好的解決了這些問題

背景

Kubernetes 中的卷有明確的壽命 —— 與封裝它的 Pod 相同。所f以,卷的生命比 Pod 中的所有容器都長,當這個容器重啟時資料仍然得以儲存。當然,當 Pod 不再存在時,卷也將不復存在。也許更重要的是,Kubernetes 支援多種型別的卷,Pod 可以同時使用任意數量的卷

卷的型別

Kubernetes 支援以下型別的卷:

  • awsElasticBlockStore azureDisk azureFile cephfs csi downwardAPI emptyDir
  • fc flocker gcePersistentDisk gitRepo glusterfs hostPath iscsi local nfs
  • persistentVolumeClaim projected portworxVolume quobyte rbd scaleIO secret
  • storageos vsphereVolume

emptyDir

當 Pod 被分配給節點時,首先建立 emptyDir 卷,並且只要該 Pod 在該節點上執行,該卷就會存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以讀取和寫入 emptyDir 卷中的相同檔案,儘管該卷可以掛載到每個容器中的相同或不同路徑上。當出於任何原因從節點中刪除 Pod 時,emptyDir 中的資料將被永久刪除

emptyDir 的用法有:
  • 暫存空間,例如用於基於磁碟的合併排序用作長時間計算崩潰恢復時的檢查點
  • Web伺服器容器提供資料時,儲存內容管理器容器提取的檔案
apiVersion: batch/v1
kind: Job
metadata:
  name: jobs-empty
spec:
  template:
    spec:
      restartPolicy: Never
      initContainers:
        - name: job-1
          image: busybox:1.34.1
          command:
            - 'sh'
            - '-c'
            - >
              for i in 1 2 3;
              do
                echo "job-1 `date`";
                sleep 1s;
              done;
              echo job-1 GG > /srv/input/code
          volumeMounts:
            - mountPath: /srv/input/
              name: input
        - name: job-2
          image: busybox:1.34.1
          command:
            - 'sh'
            - '-c'
            - >
              for i in 1 2 3;
              do
                echo "job-2 `date`";
                sleep 1s;
              done;
              cat /srv/input/code &&
              echo job-2 GG  > /srv/input/output/file
          resources:
            requests:
              cpu: 3
          volumeMounts:
            - mountPath: /srv/input/
              name: input
            - mountPath: /srv/input/output/
              name: output
      containers:
        - name: job-3
          image: busybox:1.34.1
          command:
            - 'sh'
            - '-c'
            - >
              echo "job-1 and job-2 completed";
              sleep 3s;
              cat /srv/output/file
          volumeMounts:
            - mountPath: /srv/output/
              name: output
      volumes:
        - name: input
          emptyDir: {}
        - name: output
          emptyDir: {}

hostPath

hostPath 卷將主機節點的檔案系統中的檔案或目錄掛載到叢集中

hostPath 的用途如下:

  • 執行需要訪問 Docker 內部的容器;使用 /var/lib/dockerhostPath
  • 在容器中執行 cAdvisor;使用 /dev/cgroupshostPath
  • 允許 pod 指定給定的 hostPath 是否應該在 pod 執行之前存在,是否應該建立,以及它應該以什麼形式存在

除了所需的 path 屬性之外,使用者還可以為 hostPath 卷指定 type


行為
空字串(預設)用於向後相容,這意味著在掛載 hostPath 卷之前不會執行任何檢查。
DirectoryOrCreate 如果在給定的路徑上沒有任何東西存在,那麼將根據需要在那裡建立一個空目錄,許可權設定為 0755,與 Kubelet 具有相同的組和所有權。
Directory 給定的路徑下必須存在目錄
FileOrCreate 如果在給定的路徑上沒有任何東西存在,那麼會根據需要建立一個空檔案,許可權設定為 0644,與 Kubelet 具有相同的組和所有權。
File 給定的路徑下必須存在檔案
Socket 給定的路徑下必須存在 UNIX 套接字
CharDevice 給定的路徑下必須存在字元裝置
BlockDevice 給定的路徑下必須存在塊裝置

使用這種卷型別是請注意,因為:

  • 由於每個節點上的檔案都不同,具有相同配置(例如從 podTemplate 建立的)的 pod 在不同節點上的行為可能會有所不同
  • 當 Kubernetes 按照計劃新增資源感知排程時,將無法考慮 hostPath 使用的資源
  • 在底層主機上建立的檔案或目錄只能由 root 寫入。您需要在特權容器中以 root 身份執行程序,或修改主機上的檔案許可權以便寫入 hostPath
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: wangyanglinux/myapp:v1
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # directory location on host
      path: /data
      # this field is optional
      type: Directory

概念

PersistentVolume(PV)

是由管理員設定的儲存,它是群集的一部分。就像節點是叢集中的資源一樣,PV 也是叢集中的資源。 PV 是 Volume 之類的卷外掛,但具有獨立於使用 PV 的 Pod 的生命週期。此 API 物件包含儲存實現的細節,即 NFS、iSCSI 或特定於雲供應商的儲存系統

PersistentVolumeClaim(PVC)

是使用者儲存的請求。它與 Pod 相似。Pod 消耗節點資源,PVC 消耗 PV 資源。Pod 可以請求特定級別的資源(CPU 和記憶體)。宣告可以請求特定的大小和訪問模式(例如,可以以讀/寫一次或 只讀多次模式掛載)

靜態 pv

叢集管理員建立一些 PV。它們帶有可供群集使用者使用的實際儲存的細節。它們存在於 Kubernetes API 中,可用於消費

動態

當管理員建立的靜態 PV 都不匹配使用者的 PersistentVolumeClaim 時,叢集可能會嘗試動態地為 PVC 建立卷。此配置基於 StorageClasses:PVC 必須請求 [儲存類],並且管理員必須建立並配置該類才能進行動態建立。宣告該類為 "" 可以有效地禁用其動態配置

要啟用基於儲存級別的動態儲存配置,叢集管理員需要啟用 API server 上的 DefaultStorageClass [准入控制器] 。例如,通過確保 DefaultStorageClass 位於 API server 元件的 --admission-control 標誌,使用逗號分隔的有序值列表中,可以完成此操作

繫結

master 中的控制環路監視新的 PVC,尋找匹配的 PV(如果可能),並將它們繫結在一起。如果為新的 PVC 動態調配 PV,則該環路將始終將該 PV 繫結到 PVC。否則,使用者總會得到他們所請求的儲存,但是容量可能超出要求的數量。一旦 PV 和 PVC 繫結後,PersistentVolumeClaim 繫結是排他性的,不管它們是如何繫結的。 PVC 跟 PV 繫結是一對一的對映

持久化卷宣告的保護

PVC 保護的目的是確保由 pod 正在使用的 PVC 不會從系統中移除,因為如果被移除的話可能會導致資料丟失

當啟用PVC 保護 alpha 功能時,如果使用者刪除了一個 pod 正在使用的 PVC,則該 PVC 不會被立即刪除。PVC 的刪除將被推遲,直到 PVC 不再被任何 pod 使用

持久化卷型別

PersistentVolume 型別以外掛形式實現。Kubernetes 目前支援以下外掛型別:

  • GCEPersistentDisk AWSElasticBlockStore AzureFile AzureDisk FC (Fibre Channel)
  • FlexVolume Flocker NFS iSCSI RBD (Ceph Block Device) CephFS
  • Cinder (OpenStack block storage) Glusterfs VsphereVolume Quobyte Volumes
  • **HostPath ** VMware Photon Portworx Volumes ScaleIO Volumes StorageOS

持久卷演示程式碼

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0003
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  mountOptions:
    - hard
    - nfsvers=4.1
  nfs:
    path: /tmp
    server: 172.17.0.2

PV 訪問模式

PersistentVolume 可以以資源提供者支援的任何方式掛載到主機上。如下表所示,供應商具有不同的功能,每個 PV 的訪問模式都將被設定為該卷支援的特定模式。例如,NFS 可以支援多個讀/寫客戶端,但特定的 NFS PV 可能以只讀方式匯出到伺服器上。每個 PV 都有一套自己的用來描述特定功能的訪問模式

  • ReadWriteOnce——該卷可以被單個節點以讀/寫模式掛載
  • ReadOnlyMany——該卷可以被多個節點以只讀模式掛載
  • ReadWriteMany——該卷可以被多個節點以讀/寫模式掛載

在命令列中,訪問模式縮寫為:

  • RWO - ReadWriteOnce
  • ROX - ReadOnlyMany
  • RWX - ReadWriteMany
Volume 外掛 ReadWriteOnce ReadOnlyMany ReadWriteMany
AWSElasticBlockStoreAWSElasticBlockStore - -
AzureFile
AzureDisk - -
CephFS
Cinder - -
FC -
FlexVolume -
Flocker - -
GCEPersistentDisk -
Glusterfs
HostPath - -
iSCSI -
PhotonPersistentDisk - -
Quobyte
NFS
RBD -
VsphereVolume - - (當 pod 並列時有效)
PortworxVolume -
ScaleIO -
StorageOS - -

回收策略

  • Retain(保留)——手動回收
  • Recycle(回收)——基本擦除(rm -rf /thevolume/*
  • Delete(刪除)——關聯的儲存資產(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷)將被刪除

當前,只有 NFS 和 HostPath 支援回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支援刪除策略

狀態

卷可以處於以下的某種狀態:

  • Available(可用)——一塊空閒資源還沒有被任何宣告繫結
  • Bound(已繫結)——卷已經被宣告繫結
  • Released(已釋放)——宣告被刪除,但是資源還未被叢集重新宣告
  • Failed(失敗)——該卷的自動回收失敗

命令列會顯示繫結到 PV 的 PVC 的名稱

持久化演示說明 - NFS

Ⅰ、安裝 NFS 伺服器
yum install -y nfs-common nfs-utils  rpcbind
mkdir /nfsdata
chmod 666 /nfsdata
chown nfsnobody /nfsdata
cat /etc/exports
	/nfsdata *(rw,no_root_squash,no_all_squash,sync)
  systemctl start rpcbind
systemctl start nfs
Ⅱ、部署 PV
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfspv1
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: nfs
  nfs:
    path: /data/nfs
    server: 10.66.66.10
Ⅲ、建立服務並使用 PVC
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: wangyanglinux/myapp:v1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "nfs"
      resources:
        requests:
          storage: 1Gi  

關於 StatefulSet

  • 匹配 Pod name ( 網路標識 ) 的模式為:$(statefulset名稱)-$(序號),比如上面的示例:web-0,web-1,web-2
  • StatefulSet 為每個 Pod 副本建立了一個 DNS 域名,這個域名的格式為: $(podname).(headless server name),也就意味著服務間是通過Pod域名來通訊而非 Pod IP,因為當Pod所在Node發生故障時, Pod 會被飄移到其它 Node 上,Pod IP 會發生變化,但是 Pod 域名不會有變化
  • StatefulSet 使用 Headless 服務來控制 Pod 的域名,這個域名的 FQDN 為:$(service name).$(namespace).svc.cluster.local,其中,“cluster.local” 指的是叢集的域名
  • 根據 volumeClaimTemplates,為每個 Pod 建立一個 pvc,pvc 的命名規則匹配模式:(volumeClaimTemplates.name)-(pod_name),比如上面的 volumeMounts.name=www, Pod name=web-[0-2],因此創建出來的 PVC 是 www-web-0、www-web-1、www-web-2
  • 刪除 Pod 不會刪除其 pvc,手動刪除 pvc 將自動釋放 pv

Statefulset的啟停順序:

  • 有序部署:部署StatefulSet時,如果有多個Pod副本,它們會被順序地建立(從0到N-1)並且,在下一個Pod執行之前所有之前的Pod必須都是Running和Ready狀態。

  • 有序刪除:當Pod被刪除時,它們被終止的順序是從N-1到0。

  • 有序擴充套件:當對Pod執行擴充套件操作時,與部署一樣,它前面的Pod必須都處於Running和Ready狀態。 

StatefulSet使用場景:

  • 穩定的持久化儲存,即Pod重新排程後還是能訪問到相同的持久化資料,基於 PVC 來實現。
  • 穩定的網路識別符號,即 Pod 重新排程後其 PodName 和 HostName 不變。
  • 有序部署,有序擴充套件,基於 init containers 來實現。
  • 有序收縮。

簡介

Scheduler 是 kubernetes 的排程器,主要的任務是把定義的 pod 分配到叢集的節點上。聽起來非常簡單,但有很多要考慮的問題:

  • 公平:如何保證每個節點都能被分配資源
  • 資源高效利用:叢集所有資源最大化被使用
  • 效率:排程的效能要好,能夠儘快地對大批量的 pod 完成排程工作
  • 靈活:允許使用者根據自己的需求控制排程的邏輯

Sheduler 是作為單獨的程式執行的,啟動之後會一直堅挺 API Server,獲取 PodSpec.NodeName 為空的 pod,對每個 pod 都會建立一個 binding,表明該 pod 應該放到哪個節點上

排程過程

排程分為幾個部分:首先是過濾掉不滿足條件的節點,這個過程稱為 預選;然後對通過的節點按照優先順序排序,這個是 優選;最後從中選擇優先順序最高的節點。如果中間任何一步驟有錯誤,就直接返回錯誤

預選 有一系列的演算法可以使用:

  • PodFitsResources:節點上剩餘的資源是否大於 pod 請求的資源
  • PodFitsHost:如果 pod 指定了 NodeName,檢查節點名稱是否和 NodeName 匹配
  • PodFitsHostPorts:節點上已經使用的 port 是否和 pod 申請的 port 衝突
  • PodSelectorMatches:過濾掉和 pod 指定的 label 不匹配的節點
  • NoDiskConflict:已經 mount 的 volume 和 pod 指定的 volume 不衝突,除非它們都是隻讀

如果在 預選 過程中沒有合適的節點,pod 會一直在 pending 狀態,不斷重試排程,直到有節點滿足條件。經過這個步驟,如果有多個節點滿足條件,就繼續 優選 過程: 按照優先順序大小對節點排序

優先順序由一系列鍵值對組成,鍵是該優先順序項的名稱,值是它的權重(該項的重要性)。這些優先順序選項包括:

  • LeastRequestedPriority:通過計算 CPU 和 Memory 的使用率來決定權重,使用率越低權重越高。換句話說,這個優先順序指標傾向於資源使用比例更低的節點
  • BalancedResourceAllocation:節點上 CPU 和 Memory 使用率越接近,權重越高。這個應該和上面的一起使用,不應該單獨使用
  • ImageLocalityPriority:傾向於已經有要使用映象的節點,映象總大小值越大,權重越高

通過演算法對所有的優先順序專案和權重進行計算,得出最終的結果

自定義排程器

除了 kubernetes 自帶的排程器,你也可以編寫自己的排程器。通過 spec:schedulername 引數指定排程器的名字,可以為 pod 選擇某個排程器進行排程。比如下面的 pod 選擇 my-scheduler 進行排程,而不是預設的 default-scheduler

apiVersion: v1
kind: Pod
metadata:
  name: test-scheduler
  labels:
    name: test-scheduler
spec:
  schedulername: test-scheduler
  containers:
  - name: pod-with-second-annotation-container
    image: wangyanglinux/myapp:v2

節點親和性

pod.spec.nodeAffinity
  • preferredDuringSchedulingIgnoredDuringExecution:軟策略
  • requiredDuringSchedulingIgnoredDuringExecution:硬策略
requiredDuringSchedulingIgnoredDuringExecution
apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: wangyanglinux/myapp:v1
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: NotIn
            values:
            - k8s-node02

preferredDuringSchedulingIgnoredDuringExecution

apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: wangyanglinux/myapp:v1
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: source
            operator: In
            values:
            - qikqiak

合體

apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: wangyanglinux/myapp:v1
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: NotIn
            values:
            - k8s-node02
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: source
            operator: In
            values:
            - qikqiak
鍵值運算關係
  • In:label 的值在某個列表中
  • NotIn:label 的值不在某個列表中
  • Gt:label 的值大於某個值
  • Lt:label 的值小於某個值
  • Exists:某個 label 存在
  • DoesNotExist:某個 label 不存在

Pod 親和性

pod.spec.affinity.podAffinity/podAntiAffinity

  • preferredDuringSchedulingIgnoredDuringExecution:軟策略
  • requiredDuringSchedulingIgnoredDuringExecution:硬策略
apiVersion: v1
kind: Pod
metadata:
  name: pod-3
  labels:
    app: pod-3
spec:
  containers:
  - name: pod-3
    image: wangyanglinux/myapp:v1
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - pod-1
        topologyKey: kubernetes.io/hostname
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - pod-2
          topologyKey: kubernetes.io/hostname

親和性/反親和性排程策略比較如下:

排程策略 匹配標籤 操作符 拓撲域支援 排程目標
nodeAffinity 主機 In, NotIn, Exists, DoesNotExist, Gt, Lt 指定主機
podAffinity POD In, NotIn, Exists, DoesNotExist POD與指定POD同一拓撲域
podAnitAffinity POD In, NotIn, Exists, DoesNotExist POD與指定POD不在同一拓撲域

Taint 和 Toleration

節點親和性,是 pod 的一種屬性(偏好或硬性要求),它使 pod 被吸引到一類特定的節點。Taint 則相反,它使 節點 能夠 排斥 一類特定的 pod

Taint 和 toleration 相互配合,可以用來避免 pod 被分配到不合適的節點上。每個節點上都可以應用一個或多個 taint ,這表示對於那些不能容忍這些 taint 的 pod,是不會被該節點接受的。如果將 toleration 應用於 pod 上,則表示這些 pod 可以(但不要求)被排程到具有匹配 taint 的節點上

汙點(Taint)

Ⅰ、 汙點 ( Taint ) 的組成

使用 kubectl taint 命令可以給某個 Node 節點設定汙點,Node 被設定上汙點之後就和 Pod 之間存在了一種相斥的關係,可以讓 Node 拒絕 Pod 的排程執行,甚至將 Node 已經存在的 Pod 驅逐出去

每個汙點的組成如下:

key=value:effect

每個汙點有一個 key 和 value 作為汙點的標籤,其中 value 可以為空,effect 描述汙點的作用。當前 taint effect 支援如下三個選項:

  • NoSchedule:表示 k8s 將不會將 Pod 排程到具有該汙點的 Node 上
  • PreferNoSchedule:表示 k8s 將盡量避免將 Pod 排程到具有該汙點的 Node 上
  • NoExecute:表示 k8s 將不會將 Pod 排程到具有該汙點的 Node 上,同時會將 Node 上已經存在的 Pod 驅逐出去
Ⅱ、汙點的設定、檢視和去除
# 設定汙點
kubectl taint nodes node1 key1=value1:NoSchedule

# 節點說明中,查詢 Taints 欄位
kubectl describe pod  pod-name  

# 去除汙點
kubectl taint nodes node1 key1:NoSchedule-

容忍(Tolerations)

設定了汙點的 Node 將根據 taint 的 effect:NoSchedule、PreferNoSchedule、NoExecute 和 Pod 之間產生互斥的關係,Pod 將在一定程度上不會被排程到 Node 上。 但我們可以在 Pod 上設定容忍 ( Toleration ) ,意思是設定了容忍的 Pod 將可以容忍汙點的存在,可以被排程到存在汙點的 Node 上

pod.spec.tolerations
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
  tolerationSeconds: 3600
- key: "key2"
  operator: "Exists"
  effect: "NoSchedule"

Ⅰ、當不指定 key 值時,表示容忍所有的汙點 key:

tolerations:
- operator: "Exists"

Ⅱ、當不指定 effect 值時,表示容忍所有的汙點作用

tolerations:
- key: "key"
  operator: "Exists"
Ⅲ、有多個 Master 存在時,防止資源浪費,可以如下設定
  kubectl taint nodes Node-Name node-role.kubernetes.io/master=:PreferNoSchedule

指定排程節點

Ⅰ、Pod.spec.nodeName 將 Pod 直接排程到指定的 Node 節點上,會跳過 Scheduler 的排程策略,該匹配規則是強制匹配
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myweb
spec:
  replicas: 7
  template:
    metadata:
      labels:
        app: myweb
    spec:
      nodeName: k8s-node01
      containers:
      - name: myweb
        image: wangyanglinux/myapp:v1
        ports:
        - containerPort: 80

Ⅱ、Pod.spec.nodeSelector:通過 kubernetes 的 label-selector 機制選擇節點,由排程器排程策略匹配 label,而後排程 Pod 到目標節點,該匹配規則屬於強制約束

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myweb
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: myweb
    spec:
      nodeSelector:
        type: backEndNode1
      containers:
      - name: myweb
        image: harbor/tomcat:8.5-jre8
        ports:
        - containerPort: 80