โœ”๏ธ

Pod Scheduling

NodeSelector

nodeSelector๋Š” node ์„ ํƒ ์‚ฌํ•ญ์˜ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๋ฉด์„œ๋„ ์ถ”์ฒœํ•˜๋Š” ํ˜•ํƒœ.
pod spec์— 
nodeSelector ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ํƒ€๊ฒŸ์œผ๋กœ ์‚ผ๊ณ  ์‹ถ์€ node๊ฐ€ ๊ฐ–๊ณ  ์žˆ๋Š” lable์„ ๋ช…์‹œ.
kubernetes๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ช…์‹œํ•œ label์˜ node์—๋งŒ pod๋ฅผ ์Šค์ผ€์ค„๋งํ•œ๋‹ค.
#ํ…์„œํ”Œ๋กœ์–ด๊ฐ™์€ ๋จธ์‹ ๋Ÿฌ๋‹ ์ปจํ…Œ์ด๋„ˆ๋Š” gpu๊ฐ€ ํ•„์ˆ˜์ธ๋ฐ,
#node์ค‘์— label gpu:true์ธ ๊ณณ์—์„œ ์‹คํ–‰ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
cat tensorflow-gpu.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: tensorflow-gpu
spec:
  containers:
  - name: tensorflow
    image: tensorflow/tensorflow:nightly-jupyter
    ports:
    - containerPort: 8888
      protocol: TCP
  nodeSelector:
    gpu: "true"

Affinity & antiAffinity

Affinity(์„ ํ˜ธ) & antiAffinity(๋น„ ์„ ํ˜ธ)

node์— ์ ์šฉํ•  ์ˆ˜๋„ ์žˆ๊ณ  pod์— ์ ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
์—„๊ฒฉํ•œ์š”๊ตฌ(required~~), ์„ ํ˜ธ๋„(preferred~~)(๊ฐ€์ค‘์น˜)์š”๊ตฌ ์„ค์ •๊ฐ€๋Šฅ.
topologyKey : kubernetes๋Š” pod๋ฅผ ์Šค์ผ€์ฅด๋ง ํ• ๋•Œ ๋จผ์ € pod์˜ label์„ ๊ธฐ์ค€์œผ๋กœ ๋Œ€์ƒ๋…ธ๋“œ๋ฅผ ์ฐพ๊ณ , ์ดํ›„ topologyKey ํ•„๋“œ๋ฅผ ํ™•์ธํ•ด ์›ํ•˜๋Š” ๋…ธ๋“œ์ธ์ง€ ํ™•์ธ

#node affinity
cat tensorflow-gpu-ssd.yaml
apiVersion: v1
kind: Pod
metadata:
  name: tensorflow-gpu-ssd
spec:
  containers:
  - name: tensorflow
    image: tensorflow/tensorflow:nightly-jupyter
    ports:
    - containerPort: 8888
      protocol: TCP
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - {key: disk, operator: Exists}    #<--- disk type์ด ์žˆ๋Š” ๊ณณ์—์„œ๋งŒ ์‹คํ–‰์‹œ์ผœ์ค˜ 
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 10
        preference:
          matchExpressions:
          - {key: gpu, operator: In, values: ["true"]}  #<-- gpu๊ฐ€ true์ธ ๊ณณ์—์„œ 10์  ํ• ๋‹น 
          - {key: disk, operator: In, values: ["ssd"]}  #<-- disk๊ฐ€ ssd์ธ ๊ณณ์—์„œ 10์  ํ• ๋‹น
#pod-affinity ํ…Œ์ŠคํŠธ
kubectl run backend -l app=backend --image=busybox -- sleep 9999999
  # -->node2์— ์‹คํ–‰๋˜์—ˆ๋Š”๋ฐ 

cat > pod-affinity.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  replicas: 5
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      affinity:
        podAffinity:   #โ†“ require์ด๊ธฐ๋•Œ๋ฌธ์—, pod label์ด backend๊ฐ€ ์žˆ๋Š” node์—์„œ ์‹คํ–‰๋œ๋‹ค 
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels:
                app: backend
            topologyKey: kubernetes.io/hostname
      containers:
      - name: main
        image: busybox
        args:
        - sleep
        - "99999"

kubectl create -f pod-affinity.yaml
  # --> replicas๊ฐ€ 5๋‚˜ ๋˜์ง€๋งŒ ๋ชจ๋‘ node2์—์„œ ์‹คํ–‰๋˜์—ˆ๋‹ค.

taint & toleration

๊ฐ์—ผ, ๊ด€์šฉ
taint์™€ toleration์€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜์—ฌ pod๊ฐ€ ๋ถ€์ ์ ˆํ•œ node์— ์Šค์ผ€์ค„๋˜์ง€ ์•Š๊ฒŒ ํ•œ๋‹ค
node์— NoSchedule์ด๋ผ๋Š” taint๋ฅผ ์„ค์ •ํ•˜๊ฒŒ ๋˜๋ฉด, ํ•ด๋‹น node์—” pod๊ฐ€ ๋ฐฐ์น˜๋˜์ง€ ์•Š๋Š”๋‹ค.
#๋…ธ๋“œ1์— taint ์„ค์ •
kubectl taint nodes node1.example.com role=web:NoSchedule

kubectl describe nodes node{1,2}.example.com | grep -i taint
Taints:             role=web:NoSchedule
Taints:             <none>

cat  deploy-nginx.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webui
spec:
  replicas: 4
  selector:
    matchLabels:
      app: webui
  template:
    metadata:
      name: nginx-pod
      labels:
        app: webui
    spec:
      containers:
      - name: nginx-container
        image: nginx:1.14
#      tolerations:
#      - key: "role"
#        operator: "Equal"
#        value: "web"
#        effect: "NoSchedule"


kubectl apply -f deploy-nginx.yaml
  # --> taint๊ฐ€ ์—†๋Š” node2์—๋งŒ pod๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๋‹ค.
  

# ์œ„์˜ deploy-nginx.yaml์—์„œ ์ฃผ์„์„ ์‚ญ์ œํ•˜์—ฌ toleration์„ ์„ค์ •๋œ ๋””ํ”Œ๋กœ์ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด
# node1์—๋„ ๋“ค์–ด๊ฐ€๊ณ , node2์—๋„ ๋“ค์–ด๊ฐ„๋‹ค
# toleration์ด ์žˆ์œผ๋ฉด, key๊ฐ€ ๋งž๋Š” taint ๋…ธ๋“œ์—๋„ ๋“ค์–ด๊ฐ€๊ณ , taint๋…ธ๋“œ๊ฐ€ ์—†๋Š” ๊ณณ์—๋„ ๋“ค์–ด๊ฐ„๋‹ค.

#taint ์‚ญ์ œ
kubectl taint nodes node1.example.com role-

cordon & drain

cordon : ํŠน์ •๋…ธ๋“œ์— pod์Šค์ผ€์ฅด์„ ๊ธˆ์ง€(cordon)ํ•˜๊ฑฐ๋‚˜ ํ•ด์ œ(uncordon)
drain : ํŠน์ • node์˜ pod๋ฅผ ๋น„์šฐ๊ณ , cordon์ฒ˜๋ฆฌ๊นŒ์ง€ ํ•œ๋‹ค.
deployment์˜ ๊ฒฝ์šฐ, ๋‹ค๋ฅธ ๋น„์–ด์žˆ๋Š” node๋กœ pod๊ฐ€ ์ด๊ด€๋˜๋ฉฐ, ์ผ๋ฐ˜ pod๋Š” ์†Œ๋ฉธ๋œ๋‹ค.
#node2์— ์Šค์ผ€์ฅด๋ง์„ ๋ฐ›์ง€ ์•Š๊ฒ ๋‹ค
kubectl cordon node2.example.com

kubectl apply -f deploy-nginx.yaml # <--- ํŒŒ๋“œ4๊ฐœ ์‹คํ–‰์‹œํ‚ค๋Š” ๋””ํ”Œ๋กœ์ด ์‹คํ–‰ํ•ด๋ณด๋ฉด,
                                   #      node1์—์„œ๋งŒ ์‹คํ–‰๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

#node2์— ์Šค์ผ€์ฅด๋ง์„ ๋ฐ›๊ฒ ๋‹ค
kubectl uncordon node2.example.com

kubectl delete deployments.apps webui
#drain : ํŠน์ •๋…ธ๋“œ์—์„œ ๋™์ž‘์ค‘์ธ ๋ชจ๋“  pod๋ฅผ ์ œ๊ฑฐ

#node1๊ณผ node2์— ํŒŒ๋“œ ์‹คํ–‰
kubectl apply -f deploy-nginx.yaml  #<--- node1, node2์— ๊ฐ๊ฐ 2๊ฐœ ์‹คํ–‰๋˜์—ˆ๋‹ค๊ณ  ํ•œ๋‹ค

kubectl run db --image=redis  # <--- node2์— ์‹คํ–‰๋˜์—ˆ๋‹ค๊ณ  ํ•œ๋‹ค

#์ด์ƒํƒœ์—์„œ node2 ์žฅ๋น„๋ฅผ ๋น„์›Œ๋ณด์ž
kubectl drain node2.example.com  #<--- ์—๋Ÿฌ๋‚œ๋‹ค.  ์•„๋ž˜ ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์•ผํ•จ. ๊ทธ๋ฆฌ๊ณ  node2๋Š” ์ž๋™ cordon์ฒ˜๋ฆฌ๋จ
#  --ignore-daemonsets : DaemonSet-managed pod๋“ค์€ ignore
#  --force=true : RC,RS,Job,DaemonSet ๋˜๋Š” StatefulSet์—์„œ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” Pod๊นŒ์ง€ ์ œ๊ฑฐ

#์˜ต์…˜์„ ํ†ตํ•ด node2 ์žฅ๋น„๋ฅผ ๋น„์›Œ๋ณด์ž
kubectl drain node2.example.com --ignore-daemonsets --force
  # --> redis pod๋Š” ์‚ญ์ œ๋˜์—ˆ์œผ๋ฉฐ, deploy๋œ pod๋“ค์€ node1์—์„œ ์žฌ์ƒ์„ฑ ๋˜์—ˆ๋‹ค