系列目錄html
部署pod時,大多數狀況下kubernetes的調度程序能將pod調度到集羣中合適的節點上。但有些狀況下用戶須要對pod調度到哪一個節點上施加更多控制,好比將特定pod部署到擁有SSD存儲節點、將同一個服務的多個後端部署在不一樣的機器上提升安全性、將通訊頻繁的服務部署在同一個可用區域下降通訊鏈路長度。用戶對pod部署的節點施加控制都與"label selector"有關。前端
nodeSelector也是標籤選擇器,是最簡單、最直接控制pod部署node的方法,在daemonset用nodeSelector過濾可部署節點,如下是其普通的應用示例。node
kubectl get nodes,返回集羣中全部node。nginx
kubectl node label
爲pod configuration添加節點選擇器:redis
apiVersion: v1 kind: Pod metadata: name: nginx labels: env: test spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent nodeSelector: disktype: ssd
當運行kubectl create -f https://k8s.io/examples/pods/pod-nginx.yaml命令建立pod時,節點選擇器選中有上述節點,若是沒有符合條件的node則調度失敗,爲pod輸出調度失敗事件並指明失敗緣由。pod一直處於pending狀態,直到找到合適的節點。後端
運行kubectl get pods -o wide查看調度程序爲pod選定的節點。api
上例中使用用戶自定義標籤,也可使用系統自動生成的內置節點標籤。不一樣kubernetes版本、不一樣的基礎設備供應商,默認添加的內置節點標籤可能不一樣,需查詢相關文檔確認,如下是kubernetes1.4的內置節點標籤:緩存
nodeSelector只能基於節點標籤控制pod部署node,而且選擇器只支持「與」邏輯操做。親和與反親和特性目前處於測試階段,相比於節點選擇器,其更靈活,功能更強大,體如今如下三點:安全
1) 不只僅是「與」,支持更多的邏輯表達式。
2) nodeSelector是硬性要求,親和與反親和支持軟硬兩種要求。
3) 除了節點標籤,親和與反親和支持根據節點上已經部署的pod進行節點選擇,這一點很重要。好比不想將兩種計算密集類型的pod部署在同一節點上,後部署pod可選擇過濾。
細分紅兩種類型的選擇器:"節點親和"與"內部pod親和、反親和"。節點親和與nodeSelector類似,具有上述一、2兩條優勢。內部pod親和依賴的是節點上已有pod的標籤而不是節點標籤,兼俱上述三個優勢。由於節點親和能完成nodeSelector所工做而且具有額外的優勢,所以nodeSelector雖然還能用,但已經再也不維護,而且未來可能刪除。
節點親和與nodeSelector工做原理相同,都是其於node標籤選擇節點。有兩點不一樣,第一是節點親和支持軟硬兩種節點選擇requiredDuringSchedulingIgnoredDuringExecution、preferredDuringSchedulingIgnoredDuringExecution。前者是硬性條件必需知足,後者是軟性條件,屬於偏好部署。第二點是在選擇節點時,節點親和比nodeSelector支持更多更靈活的表達式,示例以下:
apiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/e2e-az-name operator: In values: - e2e-az1 - e2e-az2 preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: another-node-label-key operator: In values: - another-node-label-value containers: - name: with-node-affinity image: k8s.gcr.io/pause:2.0
符合條件的節點必需知足requiredDuringSchedulingIgnoredDuringExecution的條件,在此基礎上,若是有節點知足
preferredDuringSchedulingIgnoredDuringExecution的條件,則更傾向部署在後者上。查詢表達式中可使用的操做符有:
In
, NotIn
, Exists
, DoesNotExist
, Gt
, Lt
等。
在requiredDuringSchedulingIgnoredDuringExecution中的matchExpressions能夠包含多條選擇表達式,相互之間是"邏輯與"的關係,必需同時知足。preferredDuringSchedulingIgnoredDuringExecution中的matchExpressions也能夠有多條,由於它是軟性條件,由於並不是必定要全匹配,匹配的條目越多越符合條件。另外還能夠爲偏好中的表達式賦予不一樣的權重weight,可取的值在0-100之間,最後經過計算權重和決定那個節點更符合條件。
若是同時使用了nodeSelector與nodeAffinity,那麼目標節點必需同時知足這兩個選擇器。
內部pod親和與反親和特性由kubernetes1.4版本初次引入,其基於節點上已部署pod的標籤計算親和與反親和,如實現將兩種通訊頻繁pod部署在相同節點,將兩種計算密集型pod部署在不一樣節點等。
提示:實現內部親和與反親和須要數量可觀的計算步驟,會明顯下降pod調度的速度,集羣規模越大、節點越多降速越明顯,呈指數級增加,須要在使用此特性時考慮對調度速度的影響。
在配置時,內部pod親和用podAffinity字段表示,內部pod反親和用podAntiAffinity字段表示,其它與節點親和同樣,也有軟硬兩種選擇器,每種選擇器能夠多個過濾條件。
內部pod親和示例:
apiVersion: v1 kind: Pod metadata: name: with-pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: failure-domain.beta.kubernetes.io/zone podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: security operator: In values: - S2 topologyKey: kubernetes.io/hostname containers: - name: with-pod-affinity image: k8s.gcr.io/pause:2.0
上例中的topologyKey用來縮小節點選擇範圍,其值能夠是任何合法的節點標籤,在大規模集羣中,爲此字段不指定或者指定錯誤值,可能引起巨大的性能、安全問題。所以,對其使用有以下限制:
對於親和與硬性反親和,topologyKey字段值不能爲空。
對於硬性反親和,topoloygKey只能是kubernetes.io/hostname,除非禁止LimitPodHardAntiAffinityTopology允入控制器或者修改其實現。
對於軟件反親和,容許topoloygKey爲空,表示對節點拓撲沒有限制。
以上狀況外,topologyKey能夠是任何合法標籤。
假設集羣有五個工做節點,部署一個web應用,假設其用redis做內存緩存,共須要三個副本,經過反親和將三個redis副本分別部署在三個不一樣的節點上,提升可用性,Deployment配置以下:
apiVersion: apps/v1 kind: Deployment metadata: name: redis-cache spec: selector: matchLabels: app: store replicas: 3 template: metadata: labels: app: store spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - store topologyKey: "kubernetes.io/hostname" containers: - name: redis-server image: redis:3.2-alpine
反親和會阻止同相的redis副本部署在同一節點上。
如今部署三個nginx web前端,要求三個副本不對分別部署在不一樣的節點上,經過與上列類似的反親和實現。同時須要將三個web前端部署在其上已經部署redis的節點上,下降通訊成本,經過親和實現,配置以下:
apiVersion: apps/v1 kind: Deployment metadata: name: web-server spec: selector: matchLabels: app: web-store replicas: 3 template: metadata: labels: app: web-store spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - web-store topologyKey: "kubernetes.io/hostname" podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - store topologyKey: "kubernetes.io/hostname" containers: - name: web-app image: nginx:1.12-alpine