Kubernetes Affinity, 제대로 이해하기

2024. 3. 25. 12:22BACKEND

반응형

본 포스팅에서는 Kubernetes의 Affinity의 개념을 이해하여 Taints & Tolerations와의 차이점을 구분할 수 있는 목표를 가집니다.

 

 

🔗  Kubernetes Series

모든 Kubernetes 시리즈를 확인하시려면 위를 참고해 주세요.

 

 


 

Assigning Pods to Nodes

노드를 특정 애플리케이션 만을 실행하게 만들거나,

다른 서비스와 구분되는 그룹으로 만들고 싶을 때가 있습니다. 

Pod을 특정 Node에 배치되도록 하는 방식에는 Label & Selector, NodeSelector, Affinity 등이 있습니다.

 

 

Node Affinity vs Taints & Tolerations

두 기능의 차이가 궁금하신 분들은 이전 포스팅의 Node Affinity vs. Taints & Tolerations 섹션을 참고 바랍니다.

 

 

스케줄러는 자동으로 자원이 부족한 노드에 파드를 배치하지 않도록 노드 간에 파드를 분배합니다.

이러한 합리적인 방식 Node를 선택하여 Pod를 배치하도록 만드는 것이 가장 좋지만,

종종, Node를 특정지어야할 때가 있습니다.

가령, SSD가 장착된 머신에 파드가 배포되도록 하거나,

통신이 빈번한 두 애플리케이션의 파드를 동일한 가용성 영역(availability zone)에 배치하는 경우가 있습니다.

 

이번 포스팅에서는 Pod의 속성으로 지정할 수 있는,

NodeSelector와 Affinity가 무엇인지 알아보도록 하겠습니다. 

 

 

 

Node Selector

Node Selector는 가장 단순하게 노드 선택을 하는 방식입니다.

Pod spec작성 시, nodeSelector 속성에 타겟이 되는 Node를 명시하면,

쿠버네티스가 해당 Label을 갖는 Node만 고려하여 스케줄링합니다.

 

가령, 세 대의 하드웨어가 있다고 가정해 봅시다.

 

                 Pod 1        Pod 2      Pod 3
Pods:          🔹              🔹             🔷

                  
Nodes:       ⬜️              ◽️             ◽️
                 Node1      Node2     Node3

 

 

가령, 위와 같이 큰 리소스를 가질 수 있는 Node 1 ( ⬜️ )과,

작은 리소스를 갖는 두 노드, Node 2 와 Node 3 (◽️)가 있습니다.

 

클러스터에는 각자 다른 종류의 작업들이 실행되고 있는데,

리소스 한계 문제로 데이터 프로세싱 처리 애플리케이션를 가지는 Pod 3 (🔷) 을 가장 큰 리소스를 가진 노드에 배치해야 합니다.

 

먼저, Node Selector를 통해 배치해 보도록 하겠습니다.

 

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

 

 

마지막 구문에, nodeSelectorsizeLarge 를 입력해, {size: Large} Label을 가진 노드를 지정한 것을 확인할 수 있습니다.

 

Pods:          🔹              🔹             🔷
                                                         ⬇️
                                                   🏷️ Large

                                                      
Nodes:       ⬜️              ◽️             ◽️

(Label)                  noting

 

 

이 때, nodeSelector을 사용하려면 Pod를 생성하기 전, 반드시 노드에 레이블을 지정해야 합니다.

 

위 조건을 만족하기 위한 방법은 Node Selector 을 살펴보았는데요.

다른 방법인 Node Affinity를 살펴보겠습니다.

 

 

$ kubectl label nodes

Pod가 특정 노드에 붙게끔 설정 했으면, 이젠 특정 노드에 Label을 붙여 찾아갈 수 있게 해야 합니다.

Label을 Node에 붙이려면 아래와 같이 입력할 수 있습니다.

 

❯ kubectl label nodes <node-name> <label-key>=<label-value>

 

위 예시를 보면 아래와 같은 모습이 되게끔 하면 됩니다.

 

Pods:          🔹              🔹             🔷
                                                          ⬇️
                                                    🏷️ Large

                                                      
Nodes:       ⬜️              ◽️             ◽️

(Label)  🏷️ Large

 

 

위의 예시를 들면 아래와 같이 나타낼 수 있습니다.

 

❯ kubectl label nodes node-1 size=Large

 

 

 

이처럼 NodeSelector은 특정 Pod가 특정 노드에 배치되는 것을 충족시켜줍니다.

하지만, 더 복잡한 요구 사항이 있을 때 대응하지 못합니다.

 

가령 Large 혹은 Medium 레이블에 지정 (Large OR Medium) 하거나,

Small 이라는 Label이 붙지 않은 노드 (NOT Small) 에 배치해달라고 하는 등의 표현이 불가합니다.

이 때에는 Node Affinity를 사용할 수 있습니다.

 

 

 

 

Node Affinity

Node affinity is a property of Pods that attracts them to a set of nodes (either as a preference or a hard requirement).

 

 

Node Affinity는 특정 노드에 해당 Pod를 위치시키도록 보장합니다.

참고로, 실제 단어의 개념을 살펴보면 다음과 같습니다.

 

📘 Affinity: a close similarity between two things

 

 

Node Affinity 기능은 특정 Pod 들이 특정 노드에 위치시는 것을 보장하기 위한 기능입니다.
nodeSelector는 OR이나 NOT 연산 등의 제한이 있었습니다.

 

Node Affinity 에서는 복잡한 구문을 통한 노드 매치가 가능합니다.

 

 

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

 

 

affinity 명세는 .spec.affinity 하위에 작성합니다.

 

 

 

Matching

여러 Label 들에 함께 적용하고 싶다면 아래와 같은 조건을 걸 수 있습니다.

 

 

 

✔️ Large OR Medium

Large 뿐만 아니라 Medium Label도 추가 하고 싶다면 아래와 같이 사용할 수 있습니다.

...
- matchExpressions:
    - key: size
      operator: In
      values:
        - Large
        - Medium
...

 

 

 

✔️ NOT Small

혹은 특정 Label만 제외 시키고 싶다면, 아래와 같이 구문 설정합니다.

...
- matchExpressions:
    - key: size
      operator: NotIn
      values:
        - Small
...

 

 

 

위 처럼 Node Affinity 를 사용해서 Pod를 Node 선호도에 따라 배치할 수 있는데요.

만약, 노드에 Large라는 Label을 설정할 수 없다면, 어떻게 될까요?

matchExpressions에 해당하는 노드가 존재하지 않는다면?

즉, 배치할 수 있는 Node가 존재하지 않는다면?

 

실제로, 누군가 Label을 변경한다면 배치할 수 없는 Pod이 존재할 수 있게 됩니다.

하지만 실제로 이런 일이 발생하면 안되겠죠.

쿠버네티스 스케줄러는 Node Affinity 타입을 통해, 이를 해결합니다.

 

 

 

Available:

 

1️⃣ requiredDuringSchedulingIgnoredDuringExecution

 

규칙이 만족되지 않으면 스케줄러가 Pod를 스케줄링할 수 없습니다.

이 기능은 nodeSelector와 유사하지만, 좀 더 표현적인 문법을 제공한다는 차이가 있습니다.

 

속성 명이 직관적인데요.

하나씩 확인해보면 다음과 같습니다.

 

- Required + DuringScheduling: 새로 생성되는 Pod에 대해 적용, 만족하지 않는 Node에 스케줄링 하지 않음

- Ignored + DuringExecution: 실행 중인 Pod에 대해 무시

 

 

2️⃣ preferredDuringSchedulingIgnoredDuringExecution

 

스케줄러는 조건을 만족하는 노드를 찾으려고 노력합니다.

해당되는 노드가 없더라도, 스케줄러는 여전히 파드를 스케줄링합니다.

 

- Preferred + DuringScheduling: 새로 생성되는 Pod에 대해 적용, 최대한 조건을 만족하도록 스케줄링

- Ignored + DuringExecution: 실행 중인 Pod에 대해 무시

 

 

Preferred 는 마치 "Try your best to place the pod on matching node" 라고 말하는 것과 같습니다.

"최대한 매칭될 수 있는 Node에 배치시켜줘" 라는 식입니다.

 

 

 

 

 

Planned:

3️⃣ requiredDuringSchedulingRequiredDuringExecution

 

아직 지원하지는 않지만, 곧 지원될 예정인 속성입니다.

 

- Preferred + DuringScheduling: 새로 생성되는 Pod에 대해 적용, 만족하지 않는 Node에 스케줄링 하지 않음

- Required + DuringExecution: 실행 중인 Pod에 대해 적용, 만족되지 않는 Pod는 퇴출

 

 

 

 

그럼 여기까지, Node Affinity를 알아보았습니다.

 

 

 

 

 

 

| Reference |

 

🔗  Kubernetes.io - Official Docs

🔗  Udemy: certified-kubernetes-administrator-with-practice-tests

 

반응형