
Node마다 물리적 스펙이 다르기 때문에 Pod가 어디서 실행되어야 하는지를 통제해야 하며, 이를 위해서는 Label이 필수이다. Label에 따라 조정할 수 있도록 하는 Pod Scheduling 방식과 Node의 스케줄링을 제어하는 Taint & Toleration & Cordon & Drain에 대해서 알아보자.
Kubernetes에서 리소스들을 식별하거나 분류하기 위한 Key-Value 형식의 메타데이터 쿠버네티스: Labels
kubectl get pods -l [KEY]=[VALUE]: 해당 label을 가지는 Pod 조회kubectl get pods --show-labels: Pod의 label까지 조회kubectl delete pods --selector [KEY]=[VALUE]: 해당 label을 가지는 Pod 제거kubectl label [TYPE] [NAME] [KEY]=[VALUE]: label 추가, --overwrite 설정으로 이미 있던 label 변경, kubectl label [TYPE] [NAME] [KEY]-: label 삭제kubectl label [TYPE] -L [KEYS]: 특정 키만 출력spec.nodeSelector로 Node의 label을 선택해서 Node를 특정하고, 맞는 Node가 없으면 Pending 상태가 된다.spec:
nodeSelector:
disktype: ssd
Kubernetes 리소스에 대해 기계가 처리하는 메타데이터를 저장하는 방식, 주로 컨트롤러나 도구, 시스템이 사용하기 위해 존재하는 key-value 메타데이터
metadata.annotations로 기록, e.g. 버전 기록해서 롤링 업데이트하면 history로 남음metadata:
annotations:
revision: "v2.1.3"
contact: "dev@company.com"
label selector를 정교하게 작성할 수 있게 해주는 구문
key=value 형태인 matchLabels보다 더 복잡한 조건을 표현할 수 있다. - key: <레이블 키>
operator: <연산자>
values: [<값1>, <값2>, ...] # 일부 연산자에서는 생략 가능
| 연산자 | 의미 | 예시 |
|---|---|---|
In | key가 values 목록에 포함됨 | "zone" In ["us-west1", "us-east1"] |
NotIn | key가 values 목록에 포함되지 않음 | "disktype" NotIn ["hdd"] |
Exists | key가 존재하기만 하면 됨 (value는 필요 없음) | "gpu" Exists |
DoesNotExist | key가 존재하지 않아야 함 | "gpu" DoesNotExist |
matchExpressions는 단순 분류 외에도 Pod가 어떤 Node에 배포될지 지정하는 데 필수적인 역할한다. 이러한 메타데이터가 스케줄링에 어떻게 사용되는지 알아보자.
Pod를 배포할 때 어느 Node에 배포할지 혹은, Pod가 어느 Node를 선호하는지를 지정할 수 있다.
template.spec.nodeName에 지정한다.apiVersion: v1
kind: Pod
metadata:
name: node-name-example
spec:
nodeName: node-1 # node 이름을 직접 지정
containers:
- name: nginx
image: nginx
template.spec.nodeSelector에 label을 지정한다.kubectl label node [NAME] [key]=[value] [—overwrite]: 실행 중인 Node의 label 추가 또는 변경apiVersion: v1
kind: Pod
metadata:
name: node-selector-example
spec:
nodeSelector:
disktype: ssd # 해당 label을 가진 노드에서만 실행됨
containers:
- name: nginx
image: nginx
template.spec.affinity.nodeAffinity에서 Hard 방식과 Soft 방식 중 하나를 선택한다.requiredDuringSchedulingIgnoredDuringExecution: 스케쥴링 되는 워크로드에는 필수 조건이고 실행 중인 워크로드에는 조건을 무시한다. (Hard)nodeSelectorTerm에서 matchExpressions를 적용한다. preferredDuringSchedulingIgnoredDuringExecution: 스케쥴링 되는 워크로드에는 선호 조건이고 실행 중인 워크로드에는 조건을 무시한다. (Soft)weight에서 지정 후 preference에서 matchExpressions를 적용한다.# Hard
apiVersion: v1
kind: Pod
metadata:
name: node-affinity-hard-example
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
# Soft
apiVersion: v1
kind: Pod
metadata:
name: node-affinity-soft-example
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: zone
operator: In
values:
- zone-a
containers:
- name: nginx
image: nginx
affinity.podAffinity.topologyKey에 Node · Zone · Region 중 하나를 선택해서 그 범위 안에서 Label Selector를 수행해 노드를 선택한다.apiVersion: v1
kind: Pod
metadata:
name: pod-affinity-example
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- frontend
topologyKey: topology.kubernetes.io/zone # 같은 zone에 붙이기
containers:
- name: nginx
image: nginx
apiVersion: v1
kind: Pod
metadata:
name: pod-anti-affinity-example
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- frontend
topologyKey: "kubernetes.io/hostname" # 같은 노드에 배치하지 않음
containers:
- name: nginx
image: nginx
Pod의 Node 할당 정책을 살펴보았다. 이제 Node의 Pod 할당 정책을 살펴보자.
쿠버네티스에서는 Node에 Pod가 임의로 스케줄링되는 것을 제어하기 위한 두 가지 주요 메커니즘이 있다.
NoSchedule: Taint Node에 Pod 스케줄링 금지 (기존 Pod는 유지)NoExecute: Taint Node에 기존 Pod도 축출, 새 Pod도 스케줄링 불가PreferNoSchedule: Taint Node에 가능하면 스케줄링하지 않음 (soft) → 기존 실행 중인 Pod는 두고 앞으로 생성될 Pod에 대해서만 적용하지만 어쩔 수 없다면 허용한다.kubectl taint node [NAME] [key]=[value]:{NoSchedule, NoExecute, PreferNoSchedule} template.spec.tolerations에 key, value, effect, operator 등을 설정하여 특정 Taint를 수용할 수 있도록 Pod를 구성한다.
kubectl cordon [NODE_NAME] ↔ kubectl uncordon [NODE_NAME]kubectl drain [NODE_NAME] [--ignore-daemonsets] [--force] ↔ kubectl uncordon [NODE_NAME]