DevOps/Docker & K8S

쿠버네티스 파드 스케줄링 (Affinity, Taint & Toleration)

SKaSha 2020. 2. 12. 09:50

쿠버네티스는 Pod를 추가 생성할때 Pod를 적정 node에 배치하기 위해 많은 것을 고려하고 스케줄링한다.
파드가 특정 노드에 선정되기까지 크게 세가지 필터의 절차를 순차적으로 가진다.

  • 볼륨 필터
  • 리소스 필터
  • 토폴로지 필터

볼륨 필터

Pod를 생성되고자 하는 디스크 볼륨에 대해서 Node가 지원할 수 있는지를 확인하고 마운트 되는 볼륨이 충돌이 일어나지 않는지 확인한다.
기본 클라우드 제공자를 이용할 경우, 규칙과 충돌을 일으키지 않고 attach 할 수 있는지 확인한다.
Node Affinity를 이용하여 특정 노드에만 지정되도록 하는 추가적인 볼륨 토폴로지 제한이 있는지 확인한다.

리소스 필터

Pod를 배포할만한 충분한 리소스(CPU,Memory,Disk)를 특정 노드가 가지고 있는지 확인하는 단계이다.
또한 물리 리소스말고도 네트워크 포트도 체크를 하는데, Pod에서 노드의 8080 포트를 사용하고자 할때 이미 노드에서 8080 포트를 사용하고 있을 경우, 새로운 파드는 해당 노드를 Pod를 생성하기 위한 Pod 리스트에서 제외한다.

토폴로지 필터

포톨로지 필터에서는 파드가 해당 노드에서 실행될수 있는지를 확인합니다.
Pod Affinity 제약에 부합되는지 확인하고,
Node selector에 매치되는지 확인하고,
노드 taint에 파드가 tolerate 되는지 확인합니다.

Affinity

어피니티는 파드가 특정 노드에 배치되도록 지정하는 정책이며 다음 두가지 정책으로 나뉜다.

  • Node Affinity : 노드를 기준
  • Pod Affinity : 다른 파드가 배포된 노드를 기준
Node Affinity

일반적으로 쿠버네티스는 파드를 적절한 노드에 배치하기 때문에 별도로 스케줄링에 대해 고민하지 않아도 된다. 하지만 선점형(preemptible) 노드와 같은 예외 상황이 존재할수도 있다.
선점형 노드는 시스템 이벤트가 발생하면 언제든 종료될수 있으며 특정 버전에 따라 종료 스크립트가 지원되지 않을 수도 있습니다.
또한 선점형 노드는 제한된 리소스를 가지고 있기 때문에 파드를 배치하지 못할수도 있습니다.
만약 클라우드 제공자를 사용하고 있을 경우 제공자의 정책에 따라 선점형 노드는 주기적으로 재시작이 될수 있습니다. (GCP 기준 24시간 마다 재부팅)
선점형 노드는 언제든지 경고 없이 클러스터에서 사라질 수 있기 때문에 파드의 비용이 클 경우에는 가능한 선점형 노드에 파드가 스케줄링 되지 않는게 좋습니다.
이러한 경우에 노드 어피니티를 이용하여 선호도를 설정 할 수 있습니다.

  • requiredDuringSchedulingIgnoredDuringExecution (강제)
  • preferredDuringSchedulingIgnoredDuringExecution (반강제)

required는 파드가 스케줄링 되기 위해서는 반드시 규칙을 만족해야하고,
preferred는 가급적 규직을 만족하는 것이 좋지만 강제 사항은 아니다.

어피니티는 파드가 실행 중일때 규칙이 적용되는 것이 아니라 스케줄링 중에 적용된다.
그러므로 실행 중에 파드를 수정하여 어피니티를 더이상 만족하지 않더라도, 파드를 다른 노드로 이동시키지 않는다. (다만 향우에는 이러한 기능이 추가될 것으로 예상 됨)

apiVersion: v1
kind: Pod
metadata:
  name: k8s-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:    // 강제
        nodeSelectorTerms:
        - matchExpressions:
          - key: k8s/zone
            operator: In
            values:
            - us-central1-a
            - us-central1-b
      preferredDuringSchedulingIgnoredDuringExecution:    // 반강제
      - weight: 100
        preference:
          matchExpressions:
          - key: k8s/no-zone
            operator: In
            values:
            - us-central1-c

반강제 어피니티는 1~100의 weight를 지정하여, 더 높은 우선순위의 규칙이 결과에 영향을 준다.

Pod Affinity

파드 어피니티는 이미 실행중인 다른 파드를 참고하여 스케줄링을 하는 방법이다.
예를 들어 레디스 캐시와 같은 서드파티가 동일한 노드에서 파드와 함께 실행되는 것이 유리한 경우가 있을수도 있고, 반대로 서로 다른 노드에 파드를 배치해야 하는 경우가 있을 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: k8s-pod-affinity
spec:
  affinity:
    podAffinity:    // podAntiAffinity: 로 대체 
      requiredDuringSchedulingIgnoredDuringExecution:    // preferredDuringSchedulingIgnoredDuringExecution : 로 대체 
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - redis
        topologyKey: k8s.io/hostname

podAffinity 키워드를 사용할 경우 k8s-pod-affinity는 redis와 동일한 노드에서 실행되며, podAntiAffinity 키워드를 이용할 경우 각 파드는 서로 다른 노드에서 실행된다.

일반적으로 실제 환경에서는 파드의 레플리카를 균등하게 분산하는 것보다 충분한 개수의 레플리카를 확보하는 것이 더 중요하므로 강제 규칙보다 반강제 규칙이 더 적합하므로 preferredDuringSchedulingIgnoredDuringExecution 키워드를 사용하는 것이 더 적합하다.

Taint & Toleration

Taint는 Node에 정의할 수 있고, Toleration은 Pod에 정의할 수 있다.
특정 노드에 파드를 배치하지 않기를 원한다면 Taint를 적용하면 되고,
Taint 처리가 되어 있는 노드에는 Taint에 맞는 Toleration을 가지고 있는 파드만 배포될 수 있다.
해당 기능을 잘 활용하면 GPU와 같은 특수 하드웨어를 가진 노드를 별도로 관리할 수 있다.

Toleration
tolerations:
- key: "key"
  operator: "Equal"
  value: "value"
  effect: "NoSchedule"

위와 같이 정의할 경우 key,value,effect 3개가 Taint와 일치하는 Node에 Pod가 배포될 수 있다.

tolerations:
- key: "key"
  operator: "Exists"
  effect: "NoSchedule"

Taint에 위에서 정의한 Key가 있고, effect가 “NoSchedule”로 설정된 Node에 value 값에 상관 없이 배포될 수 있다

tolerations:
- key: "key"
  operator: "Exists"

해당 key로 Taint가 적용되어 있는 모든 Node에 대해서 Pod를 배포하는 것이 가능하다.

Taint

특정 노드에 테인트 설정 추가

kubectl taint nodes k8s-app key=value:NoSchedule

특정 노드에 테인트 설정 제거

kubectl taint nodes k8s-app key:NoSchedule-
Taint Effect
  • NoSchedule
    Pod가 배포되지 못하고 Toleration이 일치할 경우에만 배포된다.
    이미 실행중인 Pod에는 적용되지 않고, 새로운 Pod에만 적용된다.

  • NoExecute
    돌고 있던 Pod들 중에 Toleration이 해당된다면 evit 하여 다른 node로 옮기고 새로운 Pod는 들어오지 못하게 한다.
    해당 Effect가 적용되어 특정 Pod가 evit되어야 할 경우 tolerationSeconds파라미터가 선언되어 있다면 선언된 파라미터의 시간만큼 남아 있다가 evit된다.

  • PreferNoSchedule
    가급적 Pod 배포하지 않고 리소스가 부족하거나 한 상황 등에서는 우선순위를 낮추어 Pod가 배포되도록 한다.

참고

https://thenewstack.io/implementing-advanced-scheduling-techniques-with-kubernetes/
https://kubernetes.io/blog/2017/03/advanced-scheduling-in-kubernetes/
https://kubernetes.io/ko/docs/concepts/workloads/pods/pod-topology-spread-constraints/