본문 바로가기

Kubernetes

[Kubernetes] Pod Scheduling

반응형

Pod Scheduling

Kubernetes를 운영하다보면, 특정 워커에는 배포가 되지 않도록 하고 싶은 경우가 있다.
예를 들어, 딥러닝 어플리케이션들이 배포되는 클러스터에 일부 워커에만 GPU가 붙어있을 때 GPU가 필요 없는 어플리케이션들은 해당 워커들에 배포가 되지 않도록 막고 싶은 경우이다.

Taint 와 Toleration 이 무엇인가?

  • Taint는 일반적으로 Label을 형성하는 것이다.
    • Node에 Taint를 설정하여 임의의 Pod가 할당되는 것을 방지한다.
  • Toleration은 용인이라는 뜻으로 Pod에 설정한다.
    • 특정 Taint를 용인할 수 있는 Toleration 설정을 가진 Pod는 해당 Node에 할당 가능하다.
    -> 즉, Taint와 Toleration은 함께 이해하고 사용해야 한다.Node Taint 방법
    • Taint는 Label 및 Annotation과 비슷하게 Key=Value 형식을 가지지만 추가적으로 effect라는 파라미터를 가질 수 있다.
    • 예시 Key=Value:Effect
      • Taint가 Node에 설정될 때 어떤 효과를 가지게 될지 설정하는 것이다.
        1. NoSchedule
        - Taint Node에 Pod의 스케줄링을 허용하지 않는 것을 의미
        - 기존에 실행중인 Pod는 영향을 받지 않고 새로운 Pod를 할당받지 않는 것
        예시 ) 특정 노드에만 특정한 하드웨어 장비가 있어야 하는 경우나 특정한 네트워크 환경을 가져야하는 경우 사용될 수 있다.
        kubectl taint nodes [노드이름] app=backend:NoSchedule
        2. NoExecute
        - Taint Node에 Pod의 실행을 허용하지 않는 것을 의미
        - 해당 Node에 새로운 Pod를 할당하지 않을 뿐만 아니라, 기존에 해당 Node에 배치된 모든 Pod들을 방출시키는 것
        예시 ) 노드에 하드웨어 장애가 발생했거나 유지보수를 위해 노드를 오프라인으로 전환해야 하는 경우 사용 될 수 있다.
        kubectl taint nodes [노드이름] app=backend:NoExecute
        3. PreferNoSchedule
        - Taint Node에 Pod의 스케줄링을 선호하지 않는 것을 의미
        - 해당 Node에 새로운 Pod를 할당하는 것을 선호하지 않지만, 노드 밖에 스케줄링 될 수 있는 대안이 없을 경우에는 해당 노드에 Pod 할당 가능
        - 클러스터 내에서 자원 활용을 최대화하기 위한 방법
        kubectl taint nodes [노드이름] app=backend:PreferNoSchedule
        위의 모든 예시코드는 taint 값을 app=backend를 예시로 넣었다.
      Toleration 방법
    • Toleration (용인 규칙)을 사용하여 Pod가 특정 Taint를 용인하도록 설정할 수 있다.
  • Effect
  • 위의 그림을 보면, 앞 2개의 Node에 taint로 설정 값을 준 것을 알 수 있다.
    이렇게 되면, 일반적으로 Pod 생성시에는 해당 앞의 2개의 Node에는 배치될 수 없다.
    하지만, 만약 Pod 생성 조건으로 Node에 Taint 값 positon=low과 동일한 toleration값을 주면 앞의 2개의 Node에도 배치가 가능하게 된다.
  • Toleration은 Pod spec의 'tolerations' 필드에 명시된다.
  • 모든 종류의 Taint를 용인하는 경우
tolerations:
- operator: Exists
  • 키가 app인 모든 Taint를 용인하는 경우
tolerations:
- key: app
  operator: Exists
  • 키가 app이고 effect가 NoExercute인 모든 Taint를 용인하는 경우
tolerations:
- key: app
  operator: Exists
  effect: NoExecute
  • app=backend:NoSchedule Taint를 용인하는 경우
tolerations:
- key: app
  operator: Equal
  value: backend
  effect: NoSchedule

Pod Scheduling 실습

시나리오 별 Pod 스케쥴링을 진행해보자.

Taint와 Tolerations

Taint와 Tolerations는 Pod의 spec에 직접 정의되며, 해당 Pod를 생성 또는 업데이트 할 때 적용된다.

  • Pod를 생성 또는 업데이트 할때 Pod의 spec에 Tolerations을 추가하면, 해당 Pod는 Tolerations에 지정된 조건에 따라 스케줄링된다.
  • Node에 Taint가 존재하더라도, Pod의 Tolerations 설정을 통해 Taint를 용인하는 경우에만 해당 Node에 배포된다.
  • 따라서, Pod의 Yaml파일에서 Tolerations를 설정하면 된다.

Node Affinity

Node Affinity는 Pod가 특정 Node에 예약되도록 지정하는 규칙을 정의한다.

  • Pod는 자신이 선호하는 Node에 대한 조건을 지정하여 해당 Node에 스케줄링 되도록 할 수 있다.
  • Node Affinit는 Pod의 spec에 추가되며, 특정 노드에 대한 선호 조건을 지정한다.

기존 Pod 수정하고 싶지 않고, Node에 Taint 만 추가해서 특정 Node 에 특정 Pod의 배포를 거부하고 싶은 경우

Taint와 Tolerations를 이용하여 실습

  • 배포를 거부하고자 하는 Node에 Taint를 추가한다.
kubectl taint nodes ptty-nodepool-w-2rpr app=backend:NoSchedule
  • 해당 Taint를 용인하는 Tolerations을 Pod의 spec에 추가해야 한다.
    Pod의 YAML파일에서 'spec'섹션 내에 'tolerations'필드를 추가하고, Tolerations를 지정한다.
tolerations:                
- key: app
  operator: Equal
  value: backend
  effect: NoSchedule
  • 이제 해당 Pod를 배고파거나 업데이트하면, 이제 그 Pod는 'ptty-nodepool-w-2rpr' Node에 배포되지 않고 다른 Node에 배포된다.
  • 실제 배포해서 확인해보자.
kubectl apply -f php-apache.yaml

현재 php-apache pod가 ptty-nodepool-w-2q4v node에 배포된 것을 확인 할 수 있다.

Node affinity를 이용해 Pod를 특정 node에 예약하기

각 Node에 Node가 속한 AZ를 지정하는 label을 주고, Node affinity rules를 통해 우선순위를 지정하고 싶은 경우

해결 방안 : Node Affinity에 'preferredDuringSchedulingIgnoredDuringExecution' 필드를 지정

그럼 이제 실습 해보자.

  • 노드에 라벨을 지정한다.
    kubectl label node <node_name> <label_key>=<label_value> 명령을 사용하여 원하는 기준에 따라 노드에 라벨을 지정합니다. 예를 들어, 가용성 영역으로 노드를 라벨링할 수 있다.
kubectl label node ptty-nodepool-w-2rpr availability-zone=zone1
kubectl label node ptty-nodepool-w-2rpr availability-zone2=zone2
kubectl label node ptty-nodepool-w-2rpr availability-zone3=zone3

 


'ptty-nodepool-w-2rpr' node에 availiability-zone=zone1으로 라벨을 지정했다.

파드를 생성할 Deployment YAML파일을 만들어 업데이트 한다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache2
spec:
  selector:
    matchLabels:
      app: php-apache
  replicas: 3
  template:
    metadata:
      labels:
        app: php-apache
    spec:
      containers:
      - name: php-apache
        image: php:7.4-apache
        ports:
        - containerPort: 80
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 50
              preference:
                matchExpressions:
                  - key: availability-zone
                    operator: In
                    values:
                    - zone1
            - weight: 30
              preference:
                matchExpressions:
                  - key: availability-zone2
                    operator: In
                    values:
                    - zone2
            - weight: 20
              preference:
                matchExpressions:
                  - key: availability-zone3
                    operator: In
                    values:
                    - zone3

가중치에 자세히 알고 싶다면 weight 에 들어가서 읽어보자.

Node affinity가 작동하는 방식

Node Affinity는 Pod의 스케줄링을 특정 노드 혹은 노드 그룹에 지정하는데 사용된다.
Node Affinity는 일치 조건을 기반으로 작동한다.

  • 필수(Mandatory) : 필수 일치 그룹에 속한 노드는 노드 그룹에만 Pod를 스케줄링한다. 일치하지 않는경우 Pod는 스케줄링되지 않는다.
  • 선호(Preferred) : 선호 일치 그룹에 속한 노드 노드 그룹에 우선적으로 Pod를 스케줄링한다. 그러나 일치하지 않는 다른 그룹에서도 스케줄링이 가능하다.
  • 필수가 아닌(RequiredDuringSchedulingIgnoredDuringExecution) : 일치 그룹에 속하지 않는 노드 또는 노드 그룹에만 Pod를 스케줄링 한다. 그러나 이미 해당 노드에 실행 중인 Pod는 영향을 받지 않는다.

예시) 클러스터에 많은 노드가 있는 경우, Pod 스케줄링 시 노드는 2^3개의 그룹으로 분할된다. 이 그룹은 노드의 라벨을 기반으로 구성된다. (만약 라벨이 n개라면 2^n개의 그룹으로 분할된다)