쿠버네티스에서는 사용자가 파드를 어떤 노드에 배포할 것인지 아래의 기능을 통해 설정할 수 있다.
해당 기능을 자세히 알아보자.
파드의 .spec 필드에 노드셀렉터를 이용하여 어떤 노드에서 실행될지 설정한다.
우선 노드셀렉터를 적용하려면 원하는 노드의 노드레이블에 어떤 Key-Value 쌍이 있는지 확인해야 한다. 해당 명령어로 확인할 수 있다.
> kubectl get nodes --show-lables
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,kubernetes.io/hostname=worker0
사용자가 원하는 노드에 노드레이블을 추가할 수도 있다.
> kubectl label nodes docker-desktop disktype=ssd
node/docker-desktop labeled
> kubectl get nodes --show-lables
NAME STATUS ROLES AGE VERSION LABELS
worker0 Ready <none> 1d v1.13.0 ...,**disktype=ssd**,kubernetes.io/hostname=worker0
disktype=ssd
을 가지는 Key-Value쌍의 레이블 추가한다.apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd #위에서 추가한 노드레이블의 Key-Value 쌍을 입력
노드 어피니티는 노드셀렉터와 비슷하게 노드의 레이블 기반으로 파드를 스케줄링한다.
노드 어피니티와 노드 셀렉터를 함께 설정할 수도 있는데 이때는 두개의 조건을 모두 만족해야 스케줄링한다.
노드 어피니티에는 두 가지 필드가 존재한다.
requiredDuringSchedulingIgnoredDuringExecution
: 스케줄링하는 동안 꼭 필요한 조건
preferredDuringSchedulingIgnoredDuringExecution
: 스케줄링하는 동안 만족하면 좋은 조건 (굳이 조건을 만족하지 않아도 된다.)
위의 두 조건으로 파드가 이미 스케줄링되어 있는 상태에서는 해당 노드의 조건이 바뀌어도 무시된다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
required~
필드와 preferred~
필드에서 설정할 수 있는 operator
필드의 설명이다.
In
: .values[]
필드에 설정한 값 중 레이블에 있는 값과 일치하는 것이 하나라도 있는지 확인한다.
NotIn
: In과는 반대로 .values[]
필드에 있는 값 모두와 맞지 않는지 확인한다.
Exists
: .key
필드에 설정한 값이 레이블에 있는지만 확인한다.
DoesNotExist
: Exists와 반대로 .key
필드 값이 없는지만 확인
Gt (Greater than)
: .values[]
필드에 설정된 값보다 큰 숫자형 데이터인지를 확인한다. (초과)
Lt (Lower than)
: .values[]
필드에 설정된 값보다 작은 숫자형 데이터인지를 확인한다. (미만)
파드 어피니티는 서로 자주 통신하는 파드들끼리 같은 노드에 속하게 만들어서 효율을 높이는 역할을 한다.
가장 흔한예로 DB나 캐시같은 서비스와 통신하는 App 컨테이너를 같은 노드에 두어서 네트워크 통신 비용을 줄인다.
안티 어피니티는 CPU나 네트워크 같은 하드웨어 자원을 많이 사용하는 App 컨테이너가 있을 때 여러 노드로 파드를 분산하는 역할을 한다.
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
예시 템플릿 설명
① : 안티어피니티를 설정할 label의 key값으로 app을 설정하였다.
② : ①에서 설정한 key값에 대응되는 value값으로 web-store를 설정하였다.
⇒ 즉 레이블이 app: web-store
로 설정된 파드가 속한 노드를 피해서 파드를 배포한다는 설정이다.
③ : 파드어피니티를 설정할 label의 key값으로 app을 설정하였다.
④ : ③에서 설정한 key값에 대응되는 value값으로 store를 설정하였다.
⇒ 즉 레이블이 app: store
로 설정된 파드가 속한 노드를 찾아서 함께 파드를 배포한다는 설정이다.
⑤ : topologyKey는 노드의 레이블을 이용하여 파드 어피니티와 안티 어피니티를 설정할 수 있는 또 하나의 기준이다.
spec.affinity
필드에 podAffinity
, podAntiAffinity
를 사용한다는 점 외에는 ****노드 어피니티의 설정방법과 거의 같다.topologyKey
는 해당 필드에 설정된 Key:(any value)
의 레이블 쌍을 가지는 노드에 대해서만 균등한 분배를 한다.
kubernetes.io/hostname
이 Key값에 해당한다. 즉 kubernetes.io/hostname:(any value)
로 노드를 찾음.실제 쿠버네티스 클러스터를 운영하다보면 여러가지 기준으로 스케줄링을 해야할 경우가 생기는데 topologyKey
를 이용하여 스케줄링을 쉽게 설정할 수 있다.
특정 노드에 테인트를 설정할 수있는데 테인트를 설정하게된 노드에는 파드들을 스케줄링 하지 않는다.
테인트와 톨러레이션은 주로 노드를 특정 역할만 하도록 만들때 자주 사용한다.
테인트는 크게 키, 값, 효과 세가지로 구성할 수 있다.
kubectl taint nodes 노드이름 키=값:효과
# kubectl taint nodes 노드이름 키=값:효과
# 노드에 테인트 설정
> kubectl taint nodes docker-desktop key01=value01:NoSchedule
node/docker-desktop tainted
# 노드의 테인트 확인
> kubectl describe nodes docker-desktop
테인트 삭제는 아래의 명령어로 할수 있다.
kubectl taint nodes 노드이름 키=값:효과-
테인트가 설정된 노드에 파드를 실행시키려면 톨러레이션을 설정해야 한다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: kubernetes-simple-app
labels:
app: kubernetes-simple-app
spec:
replicas: 1
selector:
matchLabels:
app: kubernetes-simple-app
template:
metadata:
labels:
app: kubernetes-simple-app
spec:
containers:
- name: kubernetes-simple-app
image: arisu1000/simple-container-app:latest
ports:
- containerPort: 8080
tolerations:
- key: "key01"
value: "value01"
operator: "Equal"
effect: “NoSchedule"
tolerations
의 필드의 key와 value는 테인트에 설정했던 값을 적어준다.톨러레이션에서 설정할수 있는 설정값에 대한 설명이다.
key
: 테인트를 설정할 때 사용했던 key값을 적어준다.value
: 테인트를 설정할 때 사용했던 value값을 적어준다.operator
: 톨러레이션을 어떠한 조건에 의해 설정될 것인지 선택한다.Equal
: key, value, effect 필드 값이 테인트의 설정값과 모두 같은지 확인함.Exists
: 어떤 테인트 설정이 있든 파드를 스케줄링해서 실행한다.effect
: 파드를 스케줄링 할 조건을 설정한다.NoSchedule
: 톨러레이션 설정이 없다면 스케줄링 하지 않는다.PreferNoSchedule
: 톨러레이션 설정이 없다면 스케줄링 하지 않는다.NoExecute
: 톨러레이션 설정이 없다면 스케줄링 하지 않고 기존에 배포되어 있는 파드들도 톨러레이션 설정이 없다면 종료시킨다.커든(cordon)은 특정 노드에 추가로 파드를 스케줄링하지 않게하는 명령이다.
커든 설정은 아래의 명령어로 설정할 수 있다.
kubectl cordon 노드이름
# docker-desktop노드에 커든설정
> kubectl cordon docker-desktop
# 커든이 설정되었으므로 파드는 Pending 상태로 스케줄링되지 않는다.
> kubectl scale deploy kubernetes-simple-app --replicas2
커든 설정을 제거할면 아래의 명령어로 설정할 수 있다.
kubectl uncordon 노드이름
드레인(drain)은 지정된 노드에 있는 모든 파드들을 다른 노드로 이동시키는 명령이다.
--ignore-daemonsets=true
옵션과 함께 명령을 실행해야 한다.--force
옵션과 함께 명령을 실행해야 한다.드레인 설정은 아래의 명령어로 설정할 수 있다.
kubectl drain 노드이름