k8s學習筆記-儲存-排程器和排程演算法
- Secret 存在意義
- Taint 和 Toleration
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
apiVersion
apiVersion
Ⅱ、用 ConfigMap 設定命令列引數
apiVersion
Ⅲ、通過資料卷外掛使用ConfigMap
在資料卷裡面使用這個 ConfigMap,有不同的選項。最基本的就是將檔案填入資料卷,在這個檔案中,鍵就是檔名,鍵值就是檔案內容
apiVersion
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/docker
的hostPath
- 在容器中執行 cAdvisor;使用
/dev/cgroups
的hostPath
- 允許 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