Fairy ' s

[K8s] Node Selectors & Affinity 본문

Study/K8s

[K8s] Node Selectors & Affinity

berafairy 2023. 8. 23. 17:01

 

 클러스터에 3개의 노드가 있다. 노드 중 2개는 더 낮은 하드웨어 리소스를 가진 더 작은 노드이고,나머지 노드 하나는 더 높은 리소스로 구성된 더 큰 노드이다. 다양한 종류의 워크로드가 클러스터에서 실행중이다. 더 높은 마력이 필요한 데이터 처리 워크로드를 더 큰 노드 전용으로 사용하려 한다. 하지만, 현재 기본 설정에서는 모든 파드는 모든 노드로 이동할 수 있기 때문에, 파드 C는 노드 2 또는 3으로 배치되어 죽을 수도 있다. 이를 해결하기 위해, 파드가 특정 노드에서만 실행되도록 제한할 수 있는 두 가지 방법이 있다.

1. Node Selector

 이전에 생성한 파드 definition file을 살펴보면, 데이터 처리 이미지와 함께 파드를 생성하기 위한 간단한 정의가 있을 것이다. 이 파드가 더 큰 노드에서 실행되도록 제한하려면 spec 세션에 nodeSelector라는 새 속성을 추가한 후 size는 Large를 입력하면 된다.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: data-processor
    image: data-processor
  nodeSelector:
    size: Large

 여기서 size는 무엇이고, 쿠버네티스에서는 어떤 것이 큰 노드인지 어떻게 알 수 있을까?  size: Large는 key-value 쌍으로 노드의 label이다. 스케줄러는 이 레이블을 사용해 파드를 배치할 올바른 노드를 식별한다. Node Selector에서 label을 사용하려면 파드를 만들기 전에 먼저 노드에 label을 지정해야 한다.

아래와 같은 명령으로 노드에 label을 지정할 수 있고, 명령 실행 후, 위에 작성했던 pod definition file과 같은 내용으로 nodeSelector가 설정된다. 'kubectl create'로 파드를 생성하면, 노드 1에 배치된다.

# 노드에 label 지정
$ kubectl label nodes <node-name> <label-key>=<label-value>

# Example
$ kubectl label nodes node-1 size=Large

2. Node Affinity

 Node Selector에는 한계가 있다. 이전 예시에서 단일 label과 selector를 사용했지만, 만약 요구 사항이 훨씬 복잡하다면 Node Selector로만으로는 요구 사항을 달성해내지 못할 것이다. 이를 위해 Node affinity, anti-affinity 기능이 존재한다.

 Node Affinity의 주요 기능은 파드가 특정한 노드에서 호스팅되는 것을 보장하는 것이다. 예를 들어 size가 Large인 노드 1이 있고, 1보다 작은 사이즈를 가진 노드 2와 3이 있다. 이 상황에 대용량 데이터 처리 파드를 노드 1에 배치되도록 하고 싶을 때는 Node Selector를 통해 간단하게 해결할 수 있다. 하지만 Node Selector는 "Large 노드나 Medium 노드에 파드를 배치하는 것", "Small이 아닌 노드에 파드를 배치하는 것"과 같은 advance expressions를 제공할 수 없다.

 Node Affinity는 advance expressions를 제공한다. 아래 defiition file은 NodeSelector를 사용한 definition file과 동일한 내용이다. 둘 다 큰 노드에 파드를 배치한다.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: data-processor
    image: data-processor
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: size
            operator: In
            values:
            - Large
            - Medium

 위 definition file은 size가 Large이거나 Medium인 노드에 파드를 배치(In)하라는 의미이다. 만약 Small이 아닌 노드에 파드를 배치하려면 아래와 같이 operator: NotIn을 사용하면 된다.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: data-processor
    image: data-processor
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: size
            operator: NotIn
            values:
            - Small

 만약 노드의 label을 Large와 Medium만 설정하고 Small은 label을 설정하지 않았다면, label이 존재하는 노드에만 파드를 배치하게 되기 때문에, 파드를 Large 노드나 Medium 노드에 배치할 수 있다. 이 경우 operator: Exists를 사용한다.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: data-processor
    image: data-processor
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: size
            operator: Exists

Node Affinity Type

 만약, Large 노드에 파드를 배치하려 했는데 Large라는 label이 붙은 노드가 없거나, 파드가 이미 배치되어 있는데 누군가 노드의 label을 변경하게 되면 어떻게 될까? 이 경우 Node Affinity Type라는 위 definition file들에 정의된 require~ 같은 긴 문장이 담당하게 된다. Node Affinity Type은 Node Affinity와 관련된 스케줄러의 동작을 정의한다.

  • Available

    • requiredDuringSchedulingIgnoredDuringExecution
    • preferredDuringSchedulingIgnoredDuringExecution
  • Planned
    • requiredDuringSchedulingRequiredDuringExecution
    • preferredDuringSchedulingRequiredDuringExecution


파드의 라이프사이클에는 Node Affinity에 대해 DuringSchedulingDuringExecution의 두 가지 상태가 있다.

  • DuringScheduling : 파드가 존재하지 않고 처음 생성된 상태이다. 파드가 처음 생성될 때 지정된 Node Affinity 규칙으로 파드를 올바른 노드에 배치하게 되는데, 만약 일치하는 label이 없게 되면 Node Affinity Type이 작용한다. 아래 설명은 Node Affinity Type의 두 가지 종류이다.

    • required : 스케줄러는 지정된 Node Affinity를 사용해 파드를 노드에 배치하도록 지시하고, 일치하는 노드를 찾을 수 없으면 파드가 스케줄링되지 않는다. Required는 파드의 배치가 중요한 경우에 사용된다. (파드를 일치하는 노드에 배치하도록 최선을 다하지만, 정말 찾을 수 없다면 아무데나 두어라)
  • DuringExecution : 파드가 실행 중이고, 노드 label 변경 같은 Node Affinity에도 영향을 미치는 환경 변경이 발생한 상태이다. 예를 들어 Node Affinity Type이 DuringExecution관리자가 이전에 설정한 size: Large 라는 label을 노드에서 제거했다면, 노드에서 실행 중인 파드는 계속 실행되며 Node Affinity의 변경 사항은 일단 예약되면 파드에 영향을 미치지 않는다.
    • required : Node Affinity를 충족하지 않는 노드에서 실행 중인 파드를 제거한다. 즉, Large 노드에서 실행 중인 파드는 Large label이 노드에서 제거되면, 파드가 제거되거나 종료된다.

예제

Deployment에 Node Affinity를 설정해서 파드들이 node01에만 배치되게 해보자.

요구 사항

  • Name: blue
  • Replics: 3
  • Image: nginx
  • NodeAffinity: requiredDuringSchedulingIgnoredDuringExecution
  • key: color
  • value: blue
apiVersion: apps/v1
kind: Deployment
metadata:
  name: blue
spec:
  replicas: 3
  selector:
    matchLabels:
      run: nginx
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - image: nginx
        imagePullPolicy: Always
        name: nginx
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: color
                operator: In
                values:
                - blue

 

'Study > K8s' 카테고리의 다른 글

[K8s] 리소스 요구사항  (0) 2023.08.24
[K8s] Taints and Tolerations vs Node Affinity  (0) 2023.08.24
[K8s] Taints and Tolerations  (0) 2023.08.17
[K8s] Labels & Selectors  (0) 2023.08.14
[K8s] Scheduling  (0) 2023.08.10
Comments