Pod를 노드에 배정하기
Pod를 노드에 배정하기 (Assigning Pods to Nodes)
Pod를 항상 "아무 노드나"에 배치하는 게 아니라, 특정 노드에만 제한하거나 특정 노드를 선호하도록 만들고 싶을 때가 있어요. 이 페이지에서는 그 방법들을 설명합니다. 권장 접근법은 모두 라벨 셀렉터를 사용합니다.
보통은 이런 제약을 설정할 필요가 없어요. 스케줄러가 합리적으로 배치합니다(예: 남는 리소스가 부족한 노드에 Pod를 두지 않도록 분산). 하지만 어떤 경우에는 노드를 통제하고 싶을 때가 있어요. 예를 들어 SSD가 붙은 노드에 Pod가 가도록 하거나, 통신이 잦은 두 서비스를 같은 가용 영역에 함께 배치하는 경우죠.
Pod를 어디에 스케줄링할지 정하는 데 쓸 수 있는 방법:
- 노드 라벨과 매칭하는
nodeSelector필드 - 어피니티(affinity)와 안티-어피니티(anti-affinity)
nodeName필드- Pod 토폴로지 분산 제약(topology spread constraints)
노드 라벨 (Node labels)
다른 많은 쿠버네티스 객체처럼 노드도 라벨을 가져요. 수동으로 라벨을 붙일 수 있고, 쿠버네티스는 클러스터의 모든 노드에 표준 라벨 집합을 채웁니다.
참고: 이 라벨들의 값은 클라우드 프로바이더에 따라 다르며 신뢰할 수 있다고 보장되지 않아요. 예를 들어
kubernetes.io/hostname값은 어떤 환경에서는 노드 이름과 같고, 다른 환경에서는 다를 수 있습니다.
노드 격리/제한 (Node isolation/restriction)
노드에 라벨을 추가하면 특정 노드나 노드 그룹을 대상으로 Pod를 스케줄링할 수 있어요. 이 기능으로 특정 Pod가 특정 격리·보안·규제 속성을 가진 노드에서만 실행되도록 할 수 있습니다.
노드 격리에 라벨을 쓰려면, kubelet이 수정할 수 없는 라벨 키를 선택하세요. 이렇게 하면 손상된 노드가 스케줄러가 워크로드를 그 노드에 배치하도록 자기 자신에게 그 라벨을 설정하는 것을 막을 수 있어요.
NodeRestriction 어드미션 플러그인은 kubelet이 node-restriction.kubernetes.io/ 접두사를 가진 라벨을 설정·수정하지 못하게 합니다.
노드 격리에 그 라벨 접두사를 사용하려면:
- Node authorizer를 사용하고
NodeRestriction어드미션 플러그인을 활성화했는지 확인하세요. node-restriction.kubernetes.io/접두사가 있는 라벨을 노드에 추가하고, node selector에서 그 라벨을 사용하세요. 예:example.com.node-restriction.kubernetes.io/fips=true또는example.com.node-restriction.kubernetes.io/pci-dss=true.
nodeSelector
nodeSelector는 노드 선택 제약의 가장 간단하고 권장되는 형태예요. Pod 스펙에 nodeSelector 필드를 추가하고, 대상 노드가 가져야 하는 노드 라벨을 지정할 수 있습니다. 쿠버네티스는 여러분이 지정한 각 라벨을 가진 노드에만 Pod를 스케줄링해요.
어피니티와 안티-어피니티 (Affinity and anti-affinity)
nodeSelector는 특정 라벨을 가진 노드로 Pod를 제약하는 가장 간단한 방법입니다. 어피니티와 안티-어피니티는 정의할 수 있는 제약 타입을 확장해요. 그 이점은:
- 어피니티/안티-어피니티 언어가 더 표현력이 풍부합니다.
nodeSelector는 지정한 모든 라벨을 가진 노드만 선택하지만, 어피니티/안티-어피니티는 선택 로직을 더 잘 제어할 수 있어요. - 규칙이 소프트(soft) 또는 선호(preferred) 임을 나타낼 수 있어서, 일치하는 노드를 못 찾아도 스케줄러가 여전히 Pod를 스케줄링합니다.
- 노드 라벨뿐 아니라 노드(또는 다른 토폴로지 영역)에서 실행 중인 다른 Pod의 라벨로 Pod를 제약할 수 있어, 어떤 Pod들이 한 노드에 공동 배치(co-locate)될 수 있는지 규칙을 정의할 수 있어요.
어피니티 기능은 두 종류로 구성됩니다:
- 노드 어피니티(Node affinity):
nodeSelector필드처럼 동작하지만 더 표현력이 풍부하고 소프트 규칙을 지정할 수 있어요. - Pod 간 어피니티/안티-어피니티(Inter-pod affinity/anti-affinity): 다른 Pod의 라벨로 Pod를 제약할 수 있습니다.
노드 어피니티 (Node affinity)
노드 어피니티는 개념적으로 nodeSelector와 비슷하며, 노드 라벨 기반으로 Pod가 어느 노드에 스케줄링될 수 있는지 제약합니다. 두 종류가 있어요:
requiredDuringSchedulingIgnoredDuringExecution: 규칙이 충족되지 않으면 스케줄러가 Pod를 스케줄링할 수 없어요.nodeSelector처럼 동작하지만 더 표현력이 풍부한 문법입니다.preferredDuringSchedulingIgnoredDuringExecution: 스케줄러가 규칙을 충족하는 노드를 찾으려 합니다. 일치하는 노드가 없어도 스케줄러는 여전히 Pod를 스케줄링해요.
참고: 위 타입에서
IgnoredDuringExecution은 쿠버네티스가 Pod를 스케줄링한 후 노드 라벨이 바뀌어도 Pod가 계속 실행된다는 뜻입니다.
Pod 스펙의 .spec.affinity.nodeAffinity 필드로 노드 어피니티를 지정할 수 있어요.
예시 Pod 스펙:
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- antarctica-east1
- antarctica-west1
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: registry.k8s.io/pause:3.8
이 예시의 규칙:
- 노드는 키
topology.kubernetes.io/zone의 라벨이 반드시 있어야 하고, 그 값은antarctica-east1또는antarctica-west1중 하나여야 합니다. - 노드는 키
another-node-label-key, 값another-node-label-value의 라벨이 바람직합니다(선호).
operator 필드로 규칙을 해석할 때 쿠버네티스가 사용할 논리 연산자를 지정할 수 있어요. In, NotIn, Exists, DoesNotExist, Gt, Lt를 쓸 수 있습니다.
NotIn과 DoesNotExist는 노드 안티-어피니티 동작을 정의할 수 있게 해줍니다. 또는 노드 테인트를 사용해 특정 노드에서 Pod를 밀어낼 수 있어요.
참고:
nodeSelector와nodeAffinity를 둘 다 지정하면, Pod가 노드에 스케줄링되려면 둘 다 충족되어야 합니다.
nodeAffinity타입과 연결된nodeSelectorTerms에 여러 항목을 지정하면, 지정된 항목 중 하나만 충족되어도 Pod는 그 노드에 스케줄링될 수 있어요(항목은 OR).
nodeSelectorTerms의 한 항목과 연결된matchExpressions필드에 여러 표현식을 지정하면, 모든 표현식이 충족되어야 Pod가 그 노드에 스케줄링될 수 있습니다(표현식은 AND).
노드 어피니티 가중치 (Node affinity weight)
preferredDuringSchedulingIgnoredDuringExecution 어피니티 타입의 각 인스턴스에 1~100 사이의 weight를 지정할 수 있어요. 스케줄러가 Pod의 다른 모든 스케줄링 요구사항을 충족하는 노드를 찾으면, 그 노드가 만족하는 모든 preferred 규칙을 반복하며 그 표현식의 weight 값을 합계에 더합니다.
최종 합계는 그 노드의 다른 우선순위 함수 점수에 더해져요. 스케줄러가 Pod에 대한 스케줄링 결정을 내릴 때 총점이 가장 높은 노드가 우선시됩니다.
예시 Pod 스펙:
apiVersion: v1
kind: Pod
metadata:
name: with-affinity-preferred-weight
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: label-1
operator: In
values:
- key-1
- weight: 50
preference:
matchExpressions:
- key: label-2
operator: In
values:
- key-2
containers:
- name: with-node-affinity
image: registry.k8s.io/pause:3.8
preferredDuringSchedulingIgnoredDuringExecution 규칙과 일치하는 후보 노드가 둘 있는데(하나는 label-1:key-1, 다른 하나는 label-2:key-2), 스케줄러는 각 노드의 weight를 고려해 다른 점수에 더하고, 최종 점수가 가장 높은 노드에 Pod를 스케줄링해요.
참고: 이 예시의 Pod가 성공적으로 스케줄링되려면
kubernetes.io/os=linux라벨이 있는 노드가 이미 있어야 합니다.
스케줄링 프로필별 노드 어피니티 (Node affinity per scheduling profile)
기능 상태:
Kubernetes v1.20 [beta]
여러 스케줄링 프로필을 구성할 때, 프로필을 노드 어피니티와 연결할 수 있어요. 프로필이 특정 노드 집합에만 적용되는 경우 유용합니다. 스케줄러 설정의 NodeAffinity 플러그인 args 필드에 addedAffinity를 추가하세요. 예:
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
- schedulerName: foo-scheduler
pluginConfig:
- name: NodeAffinity
args:
addedAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: scheduler-profile
operator: In
values:
- foo
addedAffinity는 .spec.schedulerName을 foo-scheduler로 설정한 모든 Pod에, PodSpec에 지정된 NodeAffinity에 더해서 적용됩니다. 즉 Pod와 일치하려면 노드는 addedAffinity와 Pod의 .spec.NodeAffinity를 모두 충족해야 해요.
addedAffinity는 최종 사용자에게 보이지 않으므로, 그 동작이 사용자에게 예상 밖일 수 있습니다. 스케줄러 프로필 이름과 명확한 상관관계가 있는 노드 라벨을 사용하세요.
nominatedNodeName
nominatedNodeName은 Pod 상태(status)의 필드로, Pod를 위해 선정된 후보 노드를 나타내요. 실제 바인딩은 아직 일어나지 않았지만, 스케줄러가 Pod를 위해 이 노드를 후보로 지목했다는 뜻입니다. 이 필드는 Pod가 다음과 같은 상황일 때 설정돼요:
- 스케줄러가 선점(preemption)을 통해 노드를 지목할 때.
- 스케줄러가 Pod를 어디에 둘지 정하고 바인딩 사이클로 옮길 때.
- 이 경우
nominatedNodeName은 Pod가WaitOnPermit이나PreBind확장 지점을 거쳐야 할 때만 설정됩니다.
- 이 경우
nominatedNodeName 필드를 사용하는 Pod 상태 예시:
apiVersion: v1
kind: Pod
metadata:
name: nginx
...
status:
nominatedNodeName: kube-01
Pod 토폴로지 분산 제약 (Pod topology spread constraints)
지역, 존, 노드 같은 실패 도메인(failure-domain)과, 여러분이 정의한 다른 토폴로지 영역에 걸쳐 Pod가 어떻게 분산되는지 제어하려면 토폴로지 분산 제약을 사용할 수 있어요. 성능, 예상 가용성, 또는 전반적인 활용도를 개선하기 위해 사용합니다.
자세한 내용은 Pod 토폴로지 분산 제약을 참고하세요.
Pod 토폴로지 라벨 (Pod topology labels)
기능 상태:
Kubernetes v1.35 [beta](기본 활성화)
Pod는 할당된 노드에 그 라벨이 있으면 토폴로지 라벨(topology.kubernetes.io/zone, topology.kubernetes.io/region)을 상속 받아요. 이 라벨들은 Downward API를 통해 워크로드에 노드 토폴로지 인식을 제공하는 데 쓸 수 있습니다.
자신의 존과 리전을 위해 downward API를 쓰는 Pod 예시:
apiVersion: v1
kind: Pod
metadata:
name: pod-with-topology-labels
spec:
containers:
- name: app
image: alpine
command: ["sh", "-c", "env"]
env:
- name: MY_ZONE
valueFrom:
fieldRef:
fieldPath: metadata.labels['topology.kubernetes.io/zone']
- name: MY_REGION
valueFrom:
fieldRef:
fieldPath: metadata.labels['topology.kubernetes.io/region']
연산자 (Operators)
위에서 언급한 nodeAffinity와 podAffinity의 operator 필드에 쓸 수 있는 논리 연산자:
| Operator | 동작 |
|---|---|
In |
라벨 값이 제공된 문자열 집합에 있음 |
NotIn |
라벨 값이 제공된 문자열 집합에 없음 |
Exists |
이 키를 가진 라벨이 객체에 존재함 |
DoesNotExist |
이 키를 가진 라벨이 객체에 없음 |
다음 연산자는 nodeAffinity에서만 쓸 수 있어요.
| Operator | 동작 |
|---|---|
Gt |
필드 값을 정수로 해석했을 때, 이 셀렉터가 지칭하는 라벨의 값 해석 결과 정수가 이 정수보다 큼 |
Lt |
필드 값을 정수로 해석했을 때, 이 셀렉터가 지칭하는 라벨의 값 해석 결과 정수가 이 정수보다 작음 |
참고:
Gt와Lt연산자는 정수가 아닌 값에서는 작동하지 않아요. 주어진 값이 정수로 해석되지 않으면 Pod는 스케줄링에 실패합니다. 또한Gt와Lt는podAffinity에는 사용할 수 없어요.