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/
접두사를 갖는 레이블을
설정하거나 변경하지 못하도록 한다.
노드 격리를 위해 레이블 접두사를 사용하려면,
- 노드 인가자(authorizer)를 사용하고 있는지, 그리고
NodeRestriction
어드미션 플러그인을 활성화 했는지 확인한다. - 노드에
node-restriction.kubernetes.io/
접두사를 갖는 레이블을 추가하고, 노드 셀렉터에서 해당 레이블을 사용한다. 예:example.com.node-restriction.kubernetes.io/fips=true
또는example.com.node-restriction.kubernetes.io/pci-dss=true
노드셀렉터(nodeSelector)
nodeSelector
는 노드 선택 제약사항의 가장 간단하면서도 추천하는 형태이다.
파드 스펙에 nodeSelector
필드를 추가하고,
타겟으로 삼고 싶은 노드가 갖고 있는 노드 레이블을 명시한다.
쿠버네티스는 사용자가 명시한 레이블을 갖고 있는 노드에만
파드를 스케줄링한다.
노드에 파드 할당에서 더 많은 정보를 확인한다.
어피니티(affinity)와 안티-어피니티(anti-affinity)
nodeSelector
는 파드를 특정 레이블이 있는 노드로 제한하는 가장 간단한 방법이다.
어피니티/안티-어피니티 기능은 표현할 수 있는 제약 종류를 크게 확장한다.
주요 개선 사항은 다음과 같다.
- 어피니티/안티-어피니티 언어가 더 표현적이다.
nodeSelector
로는 명시한 레이블이 있는 노드만 선택할 수 있다. 어피니티/안티-어피니티는 선택 로직에 대한 좀 더 많은 제어권을 제공한다. - 규칙이 "소프트(soft)" 또는 "선호사항(preference)" 임을 나타낼 수 있으며, 이 덕분에 스케줄러는 매치되는 노드를 찾지 못한 경우에도 파드를 스케줄링할 수 있다.
- 다른 노드 (또는 다른 토폴로지 도메인)에서 실행 중인 다른 파드의 레이블을 사용하여 파드를 제한할 수 있으며, 이를 통해 어떤 파드들이 노드에 함께 위치할 수 있는지에 대한 규칙을 정의할 수 있다.
어피니티 기능은 다음의 두 가지 종류로 구성된다.
- 노드 어피니티 기능은
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 연산자로 처리)
노드 어피니티를 사용해 노드에 파드 할당에서 더 많은 정보를 확인한다.
노드 어피니티 가중치(weight)
각 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/v1beta3
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 종류가 있다.
requiredDuringSchedulingIgnoredDuringExecution
preferredDuringSchedulingIgnoredDuringExecution
예를 들어, requiredDuringSchedulingIgnoredDuringExecution
어피니티를 사용하여
서로 통신을 많이 하는 두 서비스의 파드를
동일 클라우드 제공자 존에 배치하도록 스케줄러에게 지시할 수 있다.
비슷하게, preferredDuringSchedulingIgnoredDuringExecution
안티-어피니티를 사용하여
서비스의 파드를
여러 클라우드 제공자 존에 퍼뜨릴 수 있다.
파드간 어피니티를 사용하려면, 파드 스펙에 affinity.podAffinity
필드를 사용한다.
파드간 안티-어피니티를 사용하려면,
파드 스펙에 affinity.podAntiAffinity
필드를 사용한다.
파드 어피니티 예시
다음과 같은 파드 스펙을 가정한다.
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
레이블이 있는 하나 이상의 기존 파드의 존와 동일한 존에 있는 노드에만
파드를 스케줄링하도록 스케줄러에 지시한다.
더 정확히 말하면, 만약 security=S1
파드 레이블이 있는 하나 이상의 기존 파드를 실행하고 있는 노드가
zone=V
에 하나 이상 존재한다면,
스케줄러는 파드를 topology.kubernetes.io/zone=V
레이블이 있는 노드에 배치해야 한다.
위의 안티-어피니티 규칙은 security=S2
레이블이 있는 하나 이상의 기존 파드의 존와 동일한 존에 있는 노드에는
가급적 파드를 스케줄링하지 않도록 스케줄러에 지시한다.
더 정확히 말하면, 만약 security=S2
파드 레이블이 있는 파드가 실행되고 있는 zone=R
에
다른 노드도 존재한다면,
스케줄러는 topology.kubernetes.io/zone=R
레이블이 있는 노드에는 가급적 해당 파드를 스케줄링하지 않야아 한다.
파드 어피니티와 안티-어피니티의 예시에 대해 익숙해지고 싶다면, 디자인 제안을 참조한다.
파드 어피니티와 안티-어피니티의 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
는 규칙이 적용된 파드의 네임스페이스에 매치된다.
더 실제적인 유스케이스
파드간 어피니티와 안티-어피니티는 레플리카셋, 스테이트풀셋, 디플로이먼트 등과 같은 상위 레벨 모음과 함께 사용할 때 더욱 유용할 수 있다. 이러한 규칙을 사용하면, 워크로드 집합이 예를 들면 서로 연관된 두 개의 파드를 동일한 노드에 배치하는 것과 같이 동일하게 정의된 토폴로지와 같은 위치에 배치되도록 쉽게 구성할 수 있다.
세 개의 노드로 구성된 클러스터를 상상해 보자. 이 클러스터에서 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
nodeName
은 어피니티 또는 nodeSelector
보다 더 직접적인 형태의 노드 선택 방법이다.
nodeName
은 파드 스펙의 필드 중 하나이다.
nodeName
필드가 비어 있지 않으면, 스케줄러는 파드를 무시하고,
명명된 노드의 kubelet이 해당 파드를 자기 노드에 배치하려고 시도한다.
nodeName
은 nodeSelector
또는 어피니티/안티-어피니티 규칙보다 우선적으로 적용(overrule)된다.
nodeName
을 사용해서 노드를 선택할 때의 몇 가지 제한은 다음과 같다.
- 만약 명명된 노드가 없으면, 파드가 실행되지 않고 따라서 자동으로 삭제될 수 있다.
- 만약 명명된 노드에 파드를 수용할 수 있는 리소스가 없는 경우 파드가 실패하고, 그 이유는 다음과 같이 표시된다. 예: OutOfmemory 또는 OutOfcpu.
- 클라우드 환경의 노드 이름은 항상 예측 가능하거나 안정적인 것은 아니다.
다음은 nodeName
필드를 사용하는 파드 스펙 예시이다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeName: kube-01
위 파드는 kube-01
노드에서만 실행될 것이다.
파드 토폴로지 분배 제약 조건
_토폴로지 분배 제약 조건_을 사용하여 지역(regions), 영역(zones), 노드 또는 사용자가 정의한 다른 토폴로지 도메인과 같은 장애 도메인 사이에서 파드가 클러스터 전체에 분산되는 방식을 제어할 수 있다. 성능, 예상 가용성 또는 전체 활용도를 개선하기 위해 이 작업을 수행할 수 있다.
파드 토폴로지 분배 제약 조건에서 작동 방식에 대해 더 자세히 알아볼 수 있다.
다음 내용
- 테인트 및 톨러레이션에 대해 더 읽어본다.
- 노드 어피니티와 파드간 어피니티/안티-어피니티에 대한 디자인 문서를 읽어본다.
- 토폴로지 매니저가 노드 수준 리소스 할당 결정에 어떻게 관여하는지 알아본다.
- 노드셀렉터(nodeSelector)를 어떻게 사용하는지 알아본다.
- 어피니티/안티-어피니티를 어떻게 사용하는지 알아본다.