JUST WRITE

특정 Node에 Pod 스케줄링 본문

MLOps/Kubernetes

특정 Node에 Pod 스케줄링

천재보단범재 2023. 2. 26. 13:20

특정 Node에 Pod 스케줄링

Kubernetes에 Python으로 짠 Process를 여러 개 구동할 업무가 주어졌습니다.

해당 Process는 법인별로 1~3개씩 구동해야되서 다수의 Process를 구동해야 했습니다.

Kubernetes Cluster에서 자체적으로 Node의 상태에 맞게 Pod을 Node에 배치하게 됩니다.

이번 Python Process가 법인 상황에 따라 많은 Resource를 차지할 수 있는 상황이었습니다.

그래서 해당 Process의 Pod이 Node들에 적절하게 분배될 수 있도록 구성해 보았습니다.

affinity를 이용한 스케줄링

첫 번째 시도한 방식은 affinity를 이용한 방식이었습니다.

affinity는 사전적 의미로 선호도라고 합니다.

Label를 통해서 선호도를 설정하여 Node에 Pod를 배치하는 방식입니다.

affinity의 종류는 아래 4가지입니다.

  • NodeAffinity
  • NodeAntiAffinity
  • PodAffinity
  • PodAntiAffinity

NodeAffinity, NodeAntiAffinityNode Label에 대해서 Pod을 어떻게 배치할지 결정합니다.

PodAffinity, PodAntiAffinityNode에 배치된 Pod들의 Label을 체크하여 Pod이 어디에 배치할지 결정합니다.

아래 예시를 보며 살펴보려 합니다.

...
spec:
  affinity:
    podAntiAffinity:                                          
      requiredDuringSchedulingIgnoredDuringExecution:          
      - labelSelector:                                         
          matchExpressions:
          - key: app                                           
            operator: In
            values:
            - consumer-sedam-master
        topologyKey: kubernetes.io/hostname                    # Node의 hostname 정보 기준으로 Pod 배치
...

 

위 예시에서는 podAntiAffinity를 사용하고 있습니다.

아래 labelSelector에서 지정한 label이 있는 Pod 없는(anti이기 때문에) Node 쪽으로 배치하려고 합니다.

위 예시를 통해서 하나하나 살펴보려 합니다.

Affinity 정책 강제 옵션

위에 보시면 requiredDuringSchedulingIgnoredDuringExecution이 있습니다.

해당 설정은 아래에서 지정한 affinity를 필수로 지킬지 말지를 설정해 주는 부분입니다.

  • requiredDuringSchedulingIgnoredDuringExecution
  • preferredDuringSchedulingIgnoredDuringExecution

requeird로 반드시 아래 지정할 Affinity를 지켜서 Pod을 배치하게 됩니다.

만약 required로 세팅하고 Affinity Rule 못 지킬 상황에 Pod이 생성된다면 pending상태로 됩니다.

preferred는 반드시는 아니며 Affinity Rule을 못 지킬 상황이어도 Pod을 정상적으로 배치됩니다.

Operator

그리고 주목할 부분이 Operator입니다.

Operator에 따라 어떤 Rule로 Pod이 배치될지 정해지게 됩니다.

  • In -> Label 중 하나라도 일치하면 적용
  • NotIn -> Label 중 하나라도 일치하면 적용 X
  • Exists -> 모든 key가 존재하면 적용, Label의 key만 설정
  • DoesNotExists -> 모든 key가 존재하면 적용 X, Label의 key만 설정
  • Gt -> greater than, Label의 value가 정수값이어야 함. value보다 큰 값일 때 적용
  • Lt -> less than, Label의 value가 정수값이어야 함. value보다 작은 값일때 적용

위 6가지 Rule로 적용할 수 있으며, 상황에 맞게 적절하게 배치하면 됩니다.

아래는 Exists의 예시입니다.

신경 써야 할 부분은 values가 들어가면 안 됩니다.

...
spec:
  affinity:
    podAntiAffinity:                                           
      requiredDuringSchedulingIgnoredDuringExecution: 
      - labelSelector:                                         
          matchExpressions:
          - key: key1
            key: key2
            key: key3
            operator: Exists
            #values: -> Exists, NotExists에서는 values 사용 안함.
        topologyKey: kubernetes.io/hostname             
...

아래는 Gt의 예시입니다.

신경 써야 할 부분은 values가 정수이어야 합니다.

...
spec:
  affinity:
    podAntiAffinity:                                           
      requiredDuringSchedulingIgnoredDuringExecution: 
      - labelSelector:                                         
          matchExpressions:
          - key: key1
            values: ["100"] # value가 정수어야 한다.
            operator Gt
        topologyKey: kubernetes.io/hostname             
...

Topology Spread

affinity를 사용하는 방법도 있지만 Topology Spread를 활용한 방법이 있었습니다.

affinity만큼 디테일하게 Rule을 못 정하지만 현 상황에서 간편하게 쓸 수 있어 해당 방식으로 변경하였습니다.

Kubernetes Cluster 전체적으로 고르게 분포하게 쓸 때 유용한 방식입니다.

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
  mathc-type: type1
spec:
  topologySpreadConstraints:
    - maxSkew: 1
      topologyKey: kubernetes.io/hostname
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          mathc-type: type1

maxSkew

Pod가 균등하게 분배되지 않게 허용하는 정도를 나타냅니다.

maxSkew가 2라면 Node에 배치될 수 있는 해당 Pod의 개수가 2개까지 가능한다는 의미입니다.

whenUnsatisfiable

조건을 만족하지 않았을 때 Pod을 어떻게 처리할지 설정하는 부분입니다.

  • DoNotSchdule -> 만족하지 않으면 Pod이 Pending 상태로 둠.
  • ScheduleAnyway -> 만족하지 않아도 Pod을 정상적으로 구동

Affinity에서 requiredDuringSchedulingIgnoredDuringExecution, prferredDuringSchedulingIgnoredDuringExecution 설정과 비슷하다.

 

[참고사이트]

728x90
반응형
Comments