Information in this document may be out of date
This document has an older update date than the original, so the information it contains may be out of date. If you're able to read English, see the English version for the most up-to-date information: Assigning Pods to Nodes
특정한 노드(들) 집합에서만 동작하거나 특정한 노드 집합에서 동작하는 것을 선호하도록 파드를 제한할 수 있다. 이를 수행하는 방법에는 여러 가지가 있으며 권장되는 접근 방식은 모두 레이블 셀렉터를 사용하여 선택을 용이하게 한다. 보통은 스케줄러가 자동으로 합리적인 배치(예: 자원이 부족한 노드에 파드를 배치하지 않도록 노드 간에 파드를 분배)를 수행하기에 이러한 제약 조건을 설정할 필요는 없다. 그러나, 예를 들어 SSD가 장착된 머신에 파드가 배포되도록 하거나 또는 많은 통신을 하는 두 개의 서로 다른 서비스의 파드를 동일한 가용성 영역(availability zone)에 배치하는 경우와 같이, 파드가 어느 노드에 배포될지를 제어해야 하는 경우도 있다.
쿠버네티스가 특정 파드를 어느 노드에 스케줄링할지 고르는 다음의 방법 중 하나를 골라 사용할 수 있다.
다른 쿠버네티스 오브젝트와 마찬가지로, 노드도 레이블을 가진다. 레이블을 수동으로 추가할 수 있다. 또한 쿠버네티스도 클러스터의 모든 노드에 표준화된 레이블 집합을 적용한다. 잘 알려진 레이블, 어노테이션, 테인트에서 널리 사용되는 노드 레이블의 목록을 확인한다.
kubernetes.io/hostname에 대한 값은 특정 환경에서는 노드 이름과 동일할 수 있지만
다른 환경에서는 다른 값일 수도 있다.노드에 레이블을 추가하여 파드를 특정 노드 또는 노드 그룹에 스케줄링되도록 지정할 수 있다. 이 기능을 사용하여 특정 파드가 특정 격리/보안/규제 속성을 만족하는 노드에서만 실행되도록 할 수 있다.
노드 격리를 위해 레이블을 사용할 때, kubelet이 변경할 수 없는 레이블 키를 선택한다. 그렇지 않으면 kubelet이 해당 레이블을 변경하여 노드가 사용 불가능(compromised) 상태로 빠지고 스케줄러가 이 노드에 워크로드를 스케줄링하는 일이 발생할 수 있다.
NodeRestriction 어드미션 플러그인은
kubelet이 node-restriction.kubernetes.io/ 접두사를 갖는 레이블을
설정하거나 변경하지 못하도록 한다.
노드 격리를 위해 레이블 접두사를 사용하려면,
NodeRestriction 어드미션 플러그인을 활성화 했는지 확인한다.node-restriction.kubernetes.io/ 접두사를 갖는 레이블을 추가하고, 노드 셀렉터에서 해당 레이블을 사용한다.
예: example.com.node-restriction.kubernetes.io/fips=true 또는 example.com.node-restriction.kubernetes.io/pci-dss=truenodeSelector는 노드 선택 제약사항의 가장 간단하면서도 추천하는 형태이다.
파드 스펙에 nodeSelector 필드를 추가하고,
타겟으로 삼고 싶은 노드가 갖고 있는 노드 레이블을 명시한다.
쿠버네티스는 사용자가 명시한 레이블을 갖고 있는 노드에만
파드를 스케줄링한다.
노드에 파드 할당에서 더 많은 정보를 확인한다.
nodeSelector 는 파드를 특정 레이블이 있는 노드로 제한하는 가장 간단한 방법이다.
어피니티/안티-어피니티 기능은 표현할 수 있는 제약 종류를 크게 확장한다.
주요 개선 사항은 다음과 같다.
nodeSelector로는 명시한 레이블이 있는 노드만 선택할 수 있다.
어피니티/안티-어피니티는 선택 로직에 대한 좀 더 많은 제어권을 제공한다.어피니티 기능은 다음의 두 가지 종류로 구성된다.
nodeSelector 필드와 비슷하지만
더 표현적이고 소프트(soft) 규칙을 지정할 수 있게 해 준다.노드 어피니티는 개념적으로 nodeSelector 와 비슷하며,
노드의 레이블을 기반으로 파드가 스케줄링될 수 있는 노드를 제한할 수 있다.
노드 어피니티에는 다음의 두 종류가 있다.
requiredDuringSchedulingIgnoredDuringExecution:
규칙이 만족되지 않으면 스케줄러가 파드를 스케줄링할 수 없다.
이 기능은 nodeSelector와 유사하지만, 좀 더 표현적인 문법을 제공한다.preferredDuringSchedulingIgnoredDuringExecution:
스케줄러는 조건을 만족하는 노드를 찾으려고 노력한다.
해당되는 노드가 없더라도, 스케줄러는 여전히 파드를 스케줄링한다.IgnoredDuringExecution는
쿠버네티스가 파드를 스케줄링한 뒤에 노드 레이블이 변경되어도 파드는 계속 해당 노드에서 실행됨을 의미한다.파드 스펙의 .spec.affinity.nodeAffinity 필드에
노드 어피니티를 명시할 수 있다.
예를 들어, 다음과 같은 파드 스펙이 있다고 하자.
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:2.0이 예시에서는 다음의 규칙이 적용된다.
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 연산자를 사용하여 노드 안티-어피니티 규칙을 정의할 수 있다.
또는, 특정 노드에서 파드를 쫓아내는
노드 테인트(taint)를 설정할 수 있다.
nodeSelector와 nodeAffinity를 모두 사용하는 경우,
파드가 노드에 스케줄링되려면 두 조건 모두 만족되어야 한다.
nodeAffinity의 nodeSelectorTerms에 여러 조건(term)을 명시한 경우,
노드가 명시된 조건 중 하나만 만족해도 파드가
해당 노드에 스케줄링될 수 있다. (조건들은 OR 연산자로 처리)
nodeSelectorTerms의 조건으로 단일 matchExpressions 필드에 여러 표현식(expression)을 명시한 경우,
모든 표현식을 동시에 만족하는 노드에만
파드가 스케줄링될 수 있다. (표현식들은 AND 연산자로 처리)
노드 어피니티를 사용해 노드에 파드 할당에서 더 많은 정보를 확인한다.
각 preferredDuringSchedulingIgnoredDuringExecution 어피니티 타입 인스턴스에 대해
1-100 범위의 weight를 명시할 수 있다.
스케줄러가 다른 모든 파드 스케줄링 요구 사항을 만족하는 노드를 찾으면,
스케줄러는 노드가 만족한 모든 선호하는(preferred) 규칙에 대해
합계 계산을 위한 weight 값을 각각 추가한다.
최종 합계는 해당 노드에 대한 다른 우선 순위 함수 점수에 더해진다. 스케줄러가 파드에 대한 스케줄링 판단을 할 때, 총 점수가 가장 높은 노드가 우선 순위를 갖는다.
예를 들어, 다음과 같은 파드 스펙이 있다고 하자.
apiVersion: v1
kind: Pod
metadata:
name: with-affinity-anti-affinity
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:2.0
preferredDuringSchedulingIgnoredDuringExecution 규칙을 만족하는 노드가 2개 있고,
하나에는 label-1:key-1 레이블이 있고 다른 하나에는 label-2:key-2 레이블이 있으면,
스케줄러는 각 노드의 weight를 확인한 뒤
해당 노드에 대한 다른 점수에 가중치를 더하고,
최종 점수가 가장 높은 노드에 해당 파드를 스케줄링한다.
kubernetes.io/os=linux 레이블이 있어야 한다.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로 설정하는 모든 파드에 적용되며
PodSpec에 지정된 NodeAffinity도 적용된다.
즉, 파드를 매칭시키려면, 노드가 addedAffinity와
파드의 .spec.NodeAffinity를 충족해야 한다.
addedAffinity는 엔드 유저에게 표시되지 않으므로,
예상치 못한 동작이 일어날 수 있다.
스케줄러 프로파일 이름과 명확한 상관 관계가 있는 노드 레이블을 사용한다.
nodeAffinity 규칙을 준수한다.파드간 어피니티와 안티-어피니티를 사용하여, 노드 레이블 대신, 각 노드에 이미 실행 중인 다른 파드의 레이블을 기반으로 파드가 스케줄링될 노드를 제한할 수 있다.
파드간 어피니티와 안티-어피니티 규칙은 "X가 규칙 Y를 충족하는 하나 이상의 파드를 이미 실행중인 경우 이 파드는 X에서 실행해야 한다(또는 안티-어피니티의 경우에는 "실행하면 안 된다")"의 형태이며, 여기서 X는 노드, 랙, 클라우드 제공자 영역 또는 리전 등이며 Y는 쿠버네티스가 충족할 규칙이다.
이러한 규칙(Y)은 레이블 셀렉터 형태로 작성하며, 연관된 네임스페이스 목록을 선택적으로 명시할 수도 있다. 쿠버네티스에서 파드는 네임스페이스에 속하는(namespaced) 오브젝트이므로, 파드 레이블도 암묵적으로 특정 네임스페이스에 속하게 된다. 파드 레이블에 대한 모든 레이블 셀렉터는 쿠버네티스가 해당 레이블을 어떤 네임스페이스에서 탐색할지를 명시해야 한다.
topologyKey를 사용하여 토폴로지 도메인(X)를 나타낼 수 있으며,
이는 시스템이 도메인을 표시하기 위해 사용하는 노드 레이블의 키이다.
이에 대한 예시는 잘 알려진 레이블, 어노테이션, 테인트를 참고한다.
topologyKey 와 매칭되는 적절한 레이블을 가지고 있어야 한다.
일부 또는 모든 노드에 지정된 topologyKey 레이블이 없는 경우에는
의도하지 않은 동작이 발생할 수 있다.노드 어피니티와 마찬가지로 파드 어피니티 및 안티-어피니티에는 다음의 2 종류가 있다.
requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution예를 들어, requiredDuringSchedulingIgnoredDuringExecution 어피니티를 사용하여
서로 통신을 많이 하는 두 서비스의 파드를
동일 클라우드 제공자 영역에 배치하도록 스케줄러에게 지시할 수 있다.
비슷하게, preferredDuringSchedulingIgnoredDuringExecution 안티-어피니티를 사용하여
서비스의 파드를
여러 클라우드 제공자 영역에 퍼뜨릴 수 있다.
파드간 어피니티를 사용하려면, 파드 스펙에 affinity.podAffinity 필드를 사용한다.
파드간 안티-어피니티를 사용하려면,
파드 스펙에 affinity.podAntiAffinity 필드를 사용한다.
새 파드를 스케줄링할 때, 쿠버네티스 스케줄러는 현재 클러스터 상태를 바탕으로 파드의 어피니티 및 안티-어피니티 규칙을 평가한다.
하드 제약 조건 (노드 필터링):
podAffinity.requiredDuringSchedulingIgnoredDuringExecution 및 podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution:소프트 제약 조건 (스코어링):
podAffinity.preferredDuringSchedulingIgnoredDuringExecution 및 podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution:무시되는 필드:
podAffinity.preferredDuringSchedulingIgnoredDuringExecution:podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution:만약 현재 스케줄링되고 있는 파드가 자기 자신에 대한 어피니티 규칙을 가진 일련의 파드들 중 첫 번째라면, 다른 모든 어피니티 체크를 통과한다는 전제하에 스케줄링이 허용된다. 이는 클러스터 내에 해당 파드의 네임스페이스 및 셀렉터와 일치하는 다른 파드가 없고, 파드가 자기 자신의 조건을 만족하며, 선택된 노드가 요청된 모든 토폴로지와 일치하는지 확인하여 결정된다. 이를 통해 모든 파드들에 파드 간 어피니티가 지정되어 있더라도 데드락(deadlock)이 발생하는 것을 막을 수 있다.
다음과 같은 파드 스펙을 가정한다.
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: topology.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: topology.kubernetes.io/zone
containers:
- name: with-pod-affinity
image: registry.k8s.io/pause:2.0
이 예시는 하나의 파드 어피니티 규칙과
하나의 파드 안티-어피니티 규칙을 정의한다.
파드 어피니티 규칙은 "하드" requiredDuringSchedulingIgnoredDuringExecution을,
안티-어피니티 규칙은 "소프트" preferredDuringSchedulingIgnoredDuringExecution을 사용한다.
해당 어피니티 규칙은 security=S1 레이블이 지정된 파드가 이미 실행 중인 특정
영역의
노드에만 예시 파드를 배치할 수 있도록 스케줄러에 지시한다.
예를 들어, topology.kubernetes.io/zone=V 레이블이 있는 노드들로
구성된 "Zone V"라는 영역이 있다고 가정해보면, Zone V 내에 security=S1 레이블이 있는
파드가 최소 하나 이상 존재한다면 스케줄러는 해당 영역 내의 어느 노드에나 파드를
할당할 수 있다. 반대로, security=S1 레이블이 있는 파드가 Zone V 내에 없다면,
스케줄러는 해당 영역의 어떤 노드에도 예시 파드를 할당하지 않는다.
해당 안티-어피니티 규칙은 security=S2 레이블이 지정된 파드가
있는 영역의
노드에는 가급적 파드를 스케줄링하지 않도록 스케줄러에 명시한다.
예를 들어, topology.kubernetes.io/zone=R 레이블이 있는 노드들로
구성된 영역 "Zone R"이 있다고 가정해보면, Zone R에 security=S2 레이블이 있는
하나 이상의 기존 파드가 있는 한 스케줄러는 Zone R 내의 어느 노드에도 가급적 해당 파드를
스케줄링하지 않아야 한다. 반대로, Zone R 내에 security=S2 레이블이 있는 파드가 없다면,
해당 안티-어피니티 규칙은 스케줄링에 영향을 주지 않는다.
파드 어피니티와 안티-어피니티의 예시에 대해 익숙해지고 싶다면, 디자인 제안을 참조한다.
파드 어피니티와 안티-어피니티의 operator 필드에
In, NotIn, Exists 및 DoesNotExist 값을 사용할 수 있다.
연산자에서 더 자세한 정보를 확인한다.
원칙적으로, topologyKey 에는 성능과 보안상의 이유로 다음의 예외를 제외하면
어느 레이블 키도 사용할 수 있다.
topologyKey 필드는
requiredDuringSchedulingIgnoredDuringExecution
및 preferredDuringSchedulingIgnoredDuringExecution 내에 허용되지 않는다.requiredDuringSchedulingIgnoredDuringExecution 파드 안티-어피니티 규칙에 대해,
LimitPodHardAntiAffinityTopology 어드미션 컨트롤러는
topologyKey를 kubernetes.io/hostname으로 제한한다.
커스텀 토폴로지를 허용하고 싶다면 어드미션 컨트롤러를 수정하거나 비활성화할 수 있다.labelSelector와 topologyKey에 더하여 선택적으로,
labelSelector가 비교해야 하는 네임스페이스의 목록을
labelSelector 및 topologyKey 필드와 동일한 계위의 namespaces 필드에 명시할 수 있다.
생략하거나 비워 두면,
해당 어피니티/안티-어피니티 정의가 있는 파드의 네임스페이스를 기본값으로 사용한다.
Kubernetes v1.24 [stable]네임스페이스 집합에 대한 레이블 쿼리인 namespaceSelector 를 사용하여 일치하는 네임스페이스를 선택할 수도 있다.
namespaceSelector 또는 namespaces 필드에 의해 선택된 네임스페이스 모두에 적용된다.
빈 namespaceSelector ({})는 모든 네임스페이스와 일치하는 반면,
null 또는 빈 namespaces 목록과 null namespaceSelector 는 규칙이 적용된 파드의 네임스페이스에 매치된다.
Kubernetes v1.33 [stable](enabled by default)matchLabelKeys는 베타 단계 필드이며 쿠버네티스 1.35에서
기본으로 활성화되어 있다.
이를 비활성화하려면, MatchLabelKeysInPodAffinity 기능 게이트를 통해
명시적으로 비활성화해야 한다.
쿠버네티스에는 파드 어피니티 또는 안티-어피니티를 위한 선택적 matchLabelKeys 필드가
존재한다. 이 필드는 파드 (안티)어피니티를 충족할 때, 들어오는 파드의 레이블과
일치해야 하는 레이블 키를 지정한다.
레이블 키는 파드 레이블 값들을 조회할 때 사용된다. 이러한 키-값 레이블들은
labelSelector 필드로 정의된 매치 제약과 결합된다 (AND 연산자 사용).
결합된 필터링은 파드 (안티)어피니티 계산에 포함될 기존 파드들을 선택한다.
matchLabelKeys를 파드에서 직접 업데이트될 수 있는 레이블과 함께 사용하는 것은 권장되지 않는다.
matchLabelKeys에 직접 (즉, 디플로이먼트를 통하지 않고) 명시된 파드의 레이블을 수정할 때에도
API 서버(kube-apiserver)는 병합된 labelSelector의 레이블 업데이트를 반영하지 않는다.흔한 유스케이스에는 matchLabelKeys를 pod-template-hash와 함께 사용하는
것이 있다 (디플로이먼트의 일부로 관리되는 파드에서 설정되며, 각 리비전의 값이 고유함).
matchLabelKeys에서 pod-template-hash를 사용하면 들어오는 파드와 동일한 리비전에
속하는 파드들을 타겟팅함으로써 롤링 업그레이드시 어피니티가 깨지지 않을 수 있다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: application-server
...
spec:
template:
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- database
topologyKey: topology.kubernetes.io/zone
# 주어진 롤아웃의 파드만이 파드 어피니티를 계산하는 데 고려된다.
# 디플로이먼트를 업데이트할 시, 교체되는 파드들은 자신들의 어피니티 규칙들을 따른다.
# (새로운 파드 템플릿에 정의된 규칙이 있다면)
matchLabelKeys:
- pod-template-hash
Kubernetes v1.33 [stable](enabled by default)mismatchLabelKeys는 베타 단계 필드이며 쿠버네티스 1.35에서
기본으로 활성화되어 있다.
이를 비활성화 하려면, MatchLabelKeysInPodAffinity 기능 게이트에서
명시적으로 비활성화 해야 한다.
쿠버네티스에는 파드 어피니티 또는 안티-어피니티를 위한 선택적 mismatchLabelKeys 필드가
존재한다. 이 필드는 파드 안티-어피니티를 충족할 때 들어오는 파드의 레이블과
불일치해야 하는 레이블 키들을 지정한다.
mismatchLabelKeys를 파드에서 직접 업데이트될 수 있는 레이블과 함께 사용하는 것은 권장되지 않는다.
mismatchLabelKeys에 직접, (즉, 디플로이먼트를 통하지 않고) 명시된 파드의 레이블을 수정할 때에도
API 서버(kube-apiserver)는 병합된 labelSelector의 레이블 업데이트를 반영하지 않는다.한 가지 예로 파드들이 동일한 테넌트(tenant) 또는 팀이 스케줄되어 있는 토폴로지 도메인에 (노드, 영역 등) 배치되도록 할 수 있다. 즉, 서로 다른 테넌트의 파드들이 같은 토폴로지 도메인에서 동시에 실행되는 것을 막을 수 있다.
apiVersion: v1
kind: Pod
metadata:
labels:
# 모든 관련 파드에 "tenant" 레이블이 설정되어 있다고 가정한다.
tenant: tenant-a
...
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# 이 테넌트와 연관된 파드들이 올바른 노드 풀에 배치되도록 보장한다.
- matchLabelKeys:
- tenant
labelSelector: {}
topologyKey: node-pool
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# 이 테넌트와 연관된 파드들이 다른 테넌트가 사용하는 노드에 스케줄되지 않도록 보장한다.
- mismatchLabelKeys:
- tenant # 이 파드의 "tenant" 레이블 값이 무엇이든지,
# 다른 테넌트에 속한 파드가 실행되고 있는 풀의 노드에는 스케줄링 되지
# 않도록 한다.
labelSelector:
# 테넌트 레이블이 설정된 파드들만 선택하는 labelSelector가 있어야 하며,
# 그렇지 않으면 이 파드가 데몬셋(DaemonSet) 파드와 같이
# 테넌트 레이블이 없는 파드에 대해서도 안티-어피니티를 가질 수 있기 때문이다.
matchExpressions:
- key: tenant
operator: Exists
topologyKey: node-pool
파드간 어피니티와 안티-어피니티는 레플리카셋, 스테이트풀셋, 디플로이먼트 등과 같은 상위 레벨 모음과 함께 사용할 때 더욱 유용할 수 있다. 이러한 규칙을 사용하면, 워크로드 집합이 예를 들면 서로 연관된 두 개의 파드를 동일한 노드에 배치하는 것과 같이 동일하게 정의된 토폴로지와 같은 위치에 배치되도록 쉽게 구성할 수 있다.
세 개의 노드로 구성된 클러스터를 상상해 보자. 이 클러스터에서 redis와 같은 인-메모리 캐시를 이용하는 웹 애플리케이션을 실행한다. 또한 이 예에서 웹 애플리케이션과 메모리 캐시 사이의 대기 시간은 될 수 있는 대로 짧아야 한다고 가정하자. 이 때 웹 서버를 가능한 한 캐시와 같은 위치에서 실행되도록 하기 위해 파드간 어피니티/안티-어피니티를 사용할 수 있다.
다음의 redis 캐시 디플로이먼트 예시에서, 레플리카는 app=store 레이블을 갖는다.
podAntiAffinity 규칙은 스케줄러로 하여금
app=store 레이블을 가진 복수 개의 레플리카를 단일 노드에 배치하지 않게 한다.
이렇게 하여 캐시 파드를 각 노드에 분산하여 생성한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cache
spec:
selector:
matchLabels:
app: store
replicas: 3
template:
metadata:
labels:
app: store
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- store
topologyKey: "kubernetes.io/hostname"
containers:
- name: redis-server
image: redis:3.2-alpine
웹 서버를 위한 다음의 디플로이먼트는 app=web-store 레이블을 갖는 레플리카를 생성한다.
파드 어피니티 규칙은 스케줄러로 하여금 app=store 레이블이 있는 파드를 실행 중인 노드에 각 레플리카를 배치하도록 한다.
파드 안티-어피니티 규칙은 스케줄러로 하여금 app=web-store 레이블이 있는 서버 파드를
한 노드에 여러 개 배치하지 못하도록 한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
selector:
matchLabels:
app: web-store
replicas: 3
template:
metadata:
labels:
app: web-store
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web-store
topologyKey: "kubernetes.io/hostname"
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- store
topologyKey: "kubernetes.io/hostname"
containers:
- name: web-app
image: nginx:1.16-alpine
위의 두 디플로이먼트를 생성하면 다음과 같은 클러스터 형상이 나타나는데, 세 노드에 각 웹 서버가 캐시와 함께 있는 형상이다.
| node-1 | node-2 | node-3 |
|---|---|---|
| webserver-1 | webserver-2 | webserver-3 |
| cache-1 | cache-2 | cache-3 |
전체적인 효과는 각 캐시 인스턴스를 동일한 노드에서 실행 중인 단일 클라이언트가 액세스하게 될 것 같다는 것이다. 이 접근 방식은 차이(불균형 로드)와 대기 시간을 모두 최소화하는 것을 목표로 한다.
파드간 안티-어피니티를 사용해야 하는 다른 이유가 있을 수 있다. ZooKeeper 튜토리얼에서 위 예시와 동일한 기술을 사용해 고 가용성을 위한 안티-어피니티로 구성된 스테이트풀셋의 예시를 확인한다.
nodeName은 어피니티 또는 nodeSelector보다 더 직접적인 형태의 노드 선택 방법이다.
nodeName은 파드 스펙의 필드 중 하나이다.
nodeName 필드가 비어 있지 않으면, 스케줄러는 파드를 무시하고,
명명된 노드의 kubelet이 해당 파드를 자기 노드에 배치하려고 시도한다.
nodeName은 nodeSelector 또는 어피니티/안티-어피니티 규칙보다 우선적으로 적용(overrule)된다.
nodeName 을 사용해서 노드를 선택할 때의 몇 가지 제한은 다음과 같다.
nodeName은 구성된 스케줄러를 우회해야 하는 경우 또는 커스텀 스케줄러에 사용하는 것을
의도한다. 스케줄러를 우회할 경우 할당된 노드가 과부화하여 failed 파드가 발생할 수 있다.
노드 어피니티 또는 nodeSelector 필드를
이용하여 스케줄러를 우회하지 않고 특정 노드에 파드를 배치할 수 있다.다음은 nodeName 필드를 사용하는 파드 스펙 예시이다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeName: kube-01
위 파드는 kube-01 노드에서만 실행될 것이다.
Kubernetes v1.35 [beta](enabled by default)nominatedNodeName은 외부 컴포넌트가 pending 파드를 위한 노드를 지명하는 데 사용될 수 있다.
이 지명은 최선의 노력이며, 스케줄러가 해당 파드가 지명된 노드에 배치될 수 없다고 판단하면 무시될 수 있다.
또한 이 필드는 스케줄러에 의해 (덮어)쓸 수 있다.
nominatedNodeName은 파드가 WaitOnPermit이나 PreBind 확장 포인트(extension point)를 거쳐야 할 때만 설정된다.다음은 nominatedNodeName 필드를 사용한 파드 상태의 예시이다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
...
status:
nominatedNodeName: kube-01
_토폴로지 분배 제약 조건_을 사용하여 리전(regions), 영역(zones), 노드 또는 사용자가 정의한 다른 토폴로지 도메인과 같은 장애 도메인(failure-domains) 에 파드가 클러스터 전체에 분산되는 방식을 제어할 수 있다. 성능 향상, 가용성 확보 또는 전반적인 자원 활용도 개선을 위해 이 작업을 수행할 수 있다.
파드 토폴로지 분배 제약 조건에서 작동 방식에 대해 더 자세히 알아볼 수 있다.
Kubernetes v1.35 [beta](enabled by default)파드는 할당된 노드에 토폴로지 레이블(topology.kubernetes.io/zone과 topology.kubernetes.io/region)이 존재할 경우 이를 해당 노드로부터 물려받는다. 이 레이블들은 다운워드(Downward) API를 통해 워크로드가 노드 토폴로지를 인식할 수 있도록 제공하는 데 활용될 수 있다.
다음은 영역과 리전에 다운워드 API를 사용하는 파드의 예시이다.
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']
다음은 위에서 언급된 nodeAffinity와 podAffinity의 operator 필드에서 사용할 수 있는 모든 논리 연산자이다.
| 연산자 | 동작 |
|---|---|
In | 레이블 값이 주어진 문자열 집합에 존재한다 |
NotIn | 레이블 값이 주어진 문자열 집합에 존재하지 않는다 |
Exists | 레이블 키가 오브젝트에 존재한다 |
DoesNotExist | 레이블 키가 오브젝트에 존재하지 않는다 |
다음 연산자들은 nodeAffinity에만 사용될 수 있다.
| Operator | Behavior |
|---|---|
Gt | 필드 값은 정수로 파싱되며, 이 셀렉터가 지정한 레이블 값에서 파싱된 정수가 필드 값 정수보다 크다. |
Lt | 필드 값은 정수로 파싱되며, 이 셀렉터가 지정한 레이블 값에서 파싱된 정수가 필드 값 정수보다 작다. |
Gt와 Lt 연산자들은 비정수값에는 작동하지 않는다. 만약 주어진 값이
정수로 해석되지 않는다면, 그 파드는 스케줄에 실패할 것이다. 또한, Gt와 Lt는
podAffinity에 쓰일 수 없다.