파드는 배치 정책에 따라 특정 용량을 가진 노드에 할당됩니다.
위 사진은 파드가 스케줄링될 때 거치는 주요 단계가 무엇인지를 보여줍니다.
노드에 할당되지 않은 파드가 생성되는 즉시, 곧바로 스케줄러는 할당 가능한 모든 노드 그리고 필터링 정택과 우선순위 정책 세트와 함께 해당 파드를 선택합니다.
대부분의 경우 파드부터 노드까지의 할당 작업은 스케줄러에 맡기는 것이 좋으며, 배치로직을 세세하게 관리하지 않는 편이 좋습니다. 그러나 일부 경우에서는 파드를 특정 노드나 노드그룹에 강제로 할당하길 원하는 수 있습니다. 이러한 할당은 노드 셀렉터를 사용해 수행할 수 있습니다.
.spec.nodeSelector
는 파드의 필드로서, 파드 실행에 적합한 노드가 되도록 노드에 레이블로 존재하는 키-값 쌍의 맵이 지정되어 있어야 합니다.
아래의 yaml파일은 SSD 스토리지를 갖는 노드에 파드를 강제로 실행시키려 합니다
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
nodeSelector:
disktype: ssd # 노드가 이 파드의 노드로 간주되기 위해 반드시 일치해야 하는 노드 레이블 세트
노드에 사용자 정의 레이블을 지정하는 것 외에도 모든 노드에 일부 기본 레이블을 이용할 수 있습니다. 모든 노드는 고유한 kubernetes.io/hostname
레이블을 갖고 있으며 파드를 호스트명으로 노드에 배치할 때 사용할 수 있습니다. OS와 아키텍처, 인스턴스 타입을 나타내는 또 다른 기본 레이블도 배치에 유용하게 사용될 수 있습니다.
노드 어피니티는 강력한 스케줄링 방법이므로 nodeSelector로는 충분하지 않을 때 선택해야합니다.
노드 어피니티(node affinity)
파드가 노드와 얼마만큼 친밀감이 있느냐는 의미로, 파드를 스케줄링할 때 노드를 선택하는 방법입니다.
노드 셀렉터 접근 방식을 일반화 하는 것으로 필수 혹은 선호라는 규칙을 지정할 수 있습니다.
아래와 같은 연산자를 활용하여 표현 가능한 제약조건의 종류를 확장시킵니다.
In
NotIn
Exists
DoesNotExist
Gt
Lt
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# 스케줄링 프로세스에서 고려해야 할 노드에 3개가 넘는 코어(노드 레이블에 표시된)가 있어야 한다는 엄격한 요구사항입니다.
# 노드의 조건이 변경되어도 스케줄링 동안에 이 규칙이 재적용 되지 않습니다.
nodeSelectorTerms:
- matchExpressions: # 레이블과 일치할 때
- key: numberCores
operator: Gt
values: ["3"]
preferredDuringSchedulingIgnoredDuringExecution:
# 유연한 요구사항, 가중치를 갖는 셀렉터의 목록입니다. 모든 노드에 대해 일치하는 셀렉터들의 모든 가중치 합계를 계산합니다.
# 엄격한 요구사항과 일치하는 한, 값이 가장 큰 노드가 선택됩니다.
- weight: 1
preference:
matchFields: # 필드와 일치합니다. 연산자로 In과 NotIn만 사용 가능하며 값 목록에는 하나의 값만 허용합니다.
- key: metadata.name
operator: NotIn
values: ["master"]
contaimers:
- image: k8spatterns/random-generator:1.0
name: random-generator
노드 어피니티는 레이블이나 필드 일치를 기반으로 파드가 실행할 수 있는 노드를 제한합니다. 또한 하나의 파드가 또 다른 파드의 상대적 위치를 지정하는 파드 간의 의존성을 표한할 수 없습니다.
고가용성을 위해 파드를 분산시키는 방법을 표현하거나, 지연 시간 개선을 위해 파드를 함께 포잘하고 배치하는 방법을 표현하기 위해서, 파드 어피니티와 파드 안티어피니티를 사용합니다.
노드 어피티니는 노드 세분성으로 작동하지만, 파드 어피니티는 노드로 제한되지 않고 다중 토폴리지 레벨에서 규칙을 표현할 수 있습니다.
아래의 yaml에서 보듯 topologyKey
필드와 일치하는 레이블을 사용하면 노드, 랙, 클라우드 제공회사 존, 리전 같은 도메인 규칙과 결합시켜서 더 세분화된 규칙을 적용 시킬 수 있습니다.
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
# 대상 노드에서 실행 중인 또 다른 파드와 관련된 파드 배치에 대해 필수 규칙입니다.
- labelSelector:
# 합께 배치할 파드를 찾기 위한 레이블 셀렉터 입니다.
matchLabels:
confidential: high
topologyKey: security-zone
# confidentail=high 레이블을 가진 파드가 실행 중인 노드는 security-zone 레이블이 있어야합니다.
# 여기에 정의된 파드는 동일한 레이블과 값을 갖는 노드에 스케줄링됩니다.
podAntiAffinity:
# 파드가 배치되어서는 안되는 노드를 찾기 위한 안티어피니티 규칙입니다.
preferredDuringSchedulingIgnoredDuringExecution:
# 이 파드가 confidential=none 레이블을 가진 파드가 실행 중인 노드에 배치되어서는 안됩니다.(절대적은 아닙니다)
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
confidential: none
topologyKey: kubernetes.io/hostname
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
파드 안티어피니티 규칙은 여러 파드가 동일한 노드에 시행되어서는 안 된다는 규칙입니다.
IgnoreDuringExecution
접미어는 향후 확장성을 위한 것입니다. 현재는 노드의 레이블이 바뀌고 어피니티 규칙이 더 이상 유효하지 않다면 파드가 계속 실행은 되지만 향후에는 런타임으로 변경되는 것도 고려 대상입니다.
노드 어피니티는 파드가 노드를 선택할 수 있는 속성인 반면 테인트
와 톨러레이션
은 그 반대입니다.
테인트와 톨러레이션은 파드가 스케줄되어야 하는지 혹은 스케줄되지 말아야 하는지를 노드가 제어하게 허용합니다.
테인트는 노드의 특성으로서 노드에 이 값이 존재할 때 파드가 테인트에 대한 톨러레이션이 없다면 해당 노드에 스케줄링될 수 없습니다. 그런 의미에서 테인트와 톨러레이션은 기본적으로 스케줄링에는 사용할 수 없는 노드에 스케줄링을 허용하는 옵트인
이라고 할 수 있습니다.
반면에 어피니티 규칙은 실행할 노드를 명시적으로 선택하여 선택되지 않은 노드를 모두 제외하는 옵트아웃
입니다.
테인트는 kubectl: kubectl taint nodes master node-role.kubernetes.io/master="true": NoSchedule
를 사용해 노드에 추가됩니다.
# taint 예시
apiVersion: v1
kind: Node
metadata:
name: master
spec:
taints:
# 파드가 이 테인트를 톨러에시녀한 경우를 제외하고는 해당 노드에 스케줄링이 불가능하다고 표시하기 위해
# 노드의 명세에 테인트를 지정합니다.
- effect: NoSchedule
key: node-role.kubernetes.io/master
# tolerations 예시
apiVersion: v1
kind: Pod
metadata:
name: random-generator
spec:
continers:
- image: k8spatterns/random-generator:1.0
name: random-generator
tolerations:
- key: node-role.kubernetes.io/master
# node-role.kubernetes.io/master 키로 테이트된 노드를 톨러레이션합니다.
# 운영 클러스터에서는 마스터로 파드가 스케줄링되는 것을 막기 위해 마스터 노드에 테인트를 설정하지만
# 톨러레이션은 이 파드가 마스터에 스케줄링 될 수 있게 허용합니다.
operator: Exists
effect: NoSchedule
테인트와 톨러레이션은 독점적인 파드 세트를 전용 노드에 배치하는 등의 복장한 사용 예를 허용하거나 문제가 있는 노드에 테인트를 지정해 이 노드에 실행 중인 파드를 강제로 축출할 수 도 있습니다.
애플리케이션의 고가용성과 성능 요구사항에 기초해 배치에 영향을 줄 수는 있지만 스케줄러에 많은 제약을 가해서 파드가 더 이상 스케줄링 되지 못하고 자원을 너무 많이 남겨지는 상황에는 이르지 않도록 조심해야합니다.
다른 컨테이너를 배치할 더 이상의 CPU가 남아 있진 않기 대문에 사용할 수 없는 4GB 메모리가 노드 A에 남겨진 상황을 볼 수 있습니다. 자원 요구사항을 줄여서 컨테이너를 생성하면 이 상황을 개선할 수 있습니다. 또 다른 방법으로는 쿠버네티스 디스케줄러를 사용해 노드 조각 모듬을 수행하고 활용도를 향상 시키는 방법이 있습니다.
일단 파드가 노드에 할당되면 스케줄러 작업은 완료된 것이며 노드의 추가 없이 파드가 삭제 되어 다시 생성되지 않는다면 파드의 배치는 변경되지 않습니다.
잠재적인 문제는 스케줄러의 결정은 새로운 파드가 스케줄링되는 그 시점의 클러스터에 기초한다는 것입니다. 만약 클러스터가 유동적이며 노드의 자원 프로파일이 변하거나 새로운 노드가 추가되더라도, 스케줄러는 이전 파드 배치를 수정하지 않습니다. 노드 용량을 변경하는 것 외에도 노드 레이블을 변경할 수 있지만 이전 배치 역시 수정되지 않습니다.
디스케줄러를 이용하여 이러한 문제점을 해결 할 수 있습니다.
클러스터 어드민이 파드를 다시 스케줄링하여 클러스터를 정리하고 조각 모음을 수행하기에 적절한 시기라고 결졍할 때마다 항상 작업으로서 실행된느 옵션 기능입니다.
디스케줄러는 활성화와 조정이 가능한 또는 비활성화할 수 있는 사전 정의된 정책으로 제공됩니다.
❕ 사용된 정책에 관계없이 디스케줄러는 다음 파드들을 축출하지 않습니다.
축출 우선도
최선적 파드 > 확장 가능 파드 > 보장 파드
파드의 서비스 품질을 준수합니다.
정리도 잘하고 너무 멋있어용 ~