proj.pe.kr|도커, 쿠버네티스 기본
✔️

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