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에서 재생성 되었다