개요
K8s 환경에서 어플리케이션이 특정 노드에서만 실행 되게끔 하고싶을 수 있다. 기본적으로는 클라우드 환경에서 k8s가 스케쥴링으로 자원을 고려하여 POD들을 배치하지만 더 세밀하고 클러스터를 관리하고 싶을 수 있다. 예를 들어 어플리케이션을 특정 SSD 노드들에 배치한다던가 같은 렉의 노드들로 배치하고 싶은 일이 있을 수 있다.
아래 내용은 Kubernetes 관리 commandline tool인 kubectl에 대한 사전지식을 전제로 한다. kubectl에 대한 가이드는 kubectl 설치하기를 참고하자.
0. 요약
요약하자면 PM장비(물리장비)가 아래 이름과 같이 3대 있다고 가정하자. 이 장비들에 Label
을 붙인뒤 이 Label
로 Pod
이 배치(deployment)되게 요청하면 된다. 순서3의 deploy 요청 화살표는 편의상 개념적으로 표시한것이다.
1. 노드에 Label 정보 추가하기
1-1. 노드에 Label 추가하기
kubectl
명령어를 이응하여 아래와 같이 노드에 label을 추가해보자.
$ kubectl get nodes # k8s 클러스터의 노드 정보 보기
$ kubectl label nodes <node-name> <label-key>=<label-value> # label
실제 예를 들면 아래와 같다.
label 삭제는 아래와 같이 -
를 붙여 가능하다.
1-2. 노드 Label 검증하기
아래와 같이 검증이 가능하다.
1-3. 노드 label 실제 적용해보기
실제로 구축된 클러스터에서 아래와 같이 node를 label하고 확인해보자.
worker는 현재 3대로 구성되어있다.
– search-so-dev52
– search-so-dev54
– search-so-dev55
이 세대의 장비에 2대씩 조합하여 aurochsapp
, log2mat
, stargate
로 장비그룹을 label해본다.
테스트를 위해 아래의 그림과 같이 장비 3대에 3개의 label을 2대씩 조합하여 구성해본다.
실제 명령어는 아래와 같이 입력하면 된다.
$ kubectl label nodes search-so-dev52 aurochsapp=large
node/search-so-dev52 labeled
$ kubectl label nodes search-so-dev54 aurochsapp=large
node/search-so-dev54 labeled
$ kubectl label nodes search-so-dev54 log2mat=large
node/search-so-dev54 labeled
$ kubectl label nodes search-so-dev55 log2mat=large
node/search-so-dev55 labeled
$ kubectl label nodes search-so-dev55 stargate=large
node/search-so-dev55 labeled
$ kubectl label nodes search-so-dev52 stargate=large
node/search-so-dev52 labeled
아래와 같이 node별 label을 확인 할 수 있고 nodetype=aurochs-app
을 확인 할 수 있다.
$ kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
sample-cluster-ingress-1 Ready node 16d v1.11.5 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=sample-cluster-ingress-1,node-role/lb=true,node-role.kubernetes.io/node=true
sample-cluster-master-1 Ready master 17d v1.11.5 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=sample-cluster-master-1,node-role.kubernetes.io/master=true
sample-cluster-master-2 Ready master 17d v1.11.5 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=sample-cluster-master-2,node-role.kubernetes.io/master=true
sample-cluster-master-3 Ready master 17d v1.11.5 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=sample-cluster-master-3,node-role.kubernetes.io/master=true
search-so-dev52 Ready node 16d v1.11.5 aurochsapp=large,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=search-so-dev52,node-role/worker=true,node-role.kubernetes.io/node=true,stargate=large
search-so-dev54 Ready node 16d v1.11.5 aurochsapp=large,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=search-so-dev54,log2mat=large,node-role/worker=true,node-role.kubernetes.io/node=true
search-so-dev55 Ready node 16d v1.11.5 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=search-so-dev55,log2mat=large,node-role/worker=true,node-role.kubernetes.io/node=true,stargate=large
2. nodeSelector
nodeSelector
는 가장 심플하게 POD이 실행될 노드를 선택하는 방법이다.
2-1. POD 명세 작성
nginx를 띄우는 예제 POD이다. 주목할 점은 nodeSelector
로 POD이 실행될 노드를 지정한 것이다.
아래와 같이 지정하면 1-1
에서 정의한 label 인 disktype=ssd
가 설정된 노드에서만 POD이 실행될것이다.
pods/pod-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
2-2. POD 실행 및 검증하기
아래와 같이 POD을 실행하면 label이 설정된 노드에서 POD이 실행된다.
아래 명령어를 통해 pod이 어떤 노드
에서 실행되는지 확인 할 수 있다.
2-3. POD 실제 적용해보기
starport
docker app을 aurochsapp=large
, log2mat=large
, stargate=large
로 각각 띄워보기로 한다.
aurochsapp-deploy.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: aurochsapp
labels:
env: test
spec:
replicas: 2
template:
metadata:
labels:
env: test
spec:
containers:
- name: nginx
image: 원하는이미지
nodeSelector:
aurochsapp: "large"
$ kubectl create -f aurochsapp-deploy.yaml
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
aurochsapp-6fc75fb7b9-lsss8 1/1 Running 0 5m 10.230.5.187 search-so-dev52
aurochsapp-6fc75fb7b9-nvt5j 1/1 Running 0 5m 10.230.6.62 search-so-dev54
같은 맥락으로 log2mat
과 stargate
도 생성하고 나면 아래와 같은 결과를 볼 수 있다.
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
aurochsapp-6fc75fb7b9-lsss8 1/1 Running 0 10m 10.230.5.187 search-so-dev52
aurochsapp-6fc75fb7b9-nvt5j 1/1 Running 0 10m 10.230.6.62 search-so-dev54
log2mat-58974b9cc7-bnblv 1/1 Running 0 2m 10.230.4.196 search-so-dev55
log2mat-58974b9cc7-g8lvk 1/1 Running 0 2m 10.230.6.121 search-so-dev54
stargate-5df4488b85-fbcjn 1/1 Running 0 1m 10.230.5.48 search-so-dev52
stargate-5df4488b85-r5hc8 1/1 Running 0 1m 10.230.4.50 search-so-dev55
3. Affinity
nodeSelector
대비 더 Rich한 표현식으로 노드를 선택하고 싶으면 Affinity
나 inter pod affinity
를 이용하면 된다.
k8s는 nodeSelector보다 이 방식을 권장하고 있다.
이 방식의 장점은 아래와 같다.
- 표현식이 좀 더 다양하다.(exact match의 AND조합을 벗어남)
- hard한 명시보다
soft/preference
설정에 가깝게 바꿔준다. - 제약조건을 node 자체보다 POD간에 부여하는 방식으로 즉 서로 같이 배치될수 있는 POD과 아닌 POD을 정의할 수 있음
affinity는 크게 node affinity
와 inter-pod affinity/anti-affinity
로 나뉜다.
Node Affinity
는 nodeSelector
와 유사한 반면 inter-pod affinity/anti-affinity
는 pod label을 다룬다고 보면 된다.
nodeSelector
는 node affinity
로 훗날 대체될 예정이다.
3-1. Node Affinity
nodeSelector
와 유사하지만 POD이 어떤 노드에는 스케쥴 될 수 있는지 정의한다.
현재 두가지 타입의 node affinity
가 있는데 아래의 4가지이다.
required
와 preferred
는 조건을 반드시 충족해야 하는지 선호되는지 정도의 차이다.
IgnoredDuringExecution
와 RequiredDuringExecution
의 차이는 Runtime에 Node label이 바뀌더라도 무시할것인지 즉시 eviction할것인지에 대한 스케쥴링 정책이다.
- requiredDuringSchedulingIgnoredDuringExecution
- preferredDuringSchedulingIgnoredDuringExecution
- requiredDuringSchedulingRequiredDuringExecution
- preferredDuringSchedulingRequiredDuringExecution
예시를 하나 들자면 requiredDuringSchedulingIgnoredDuringExecution
은 반드시 intel CPU를 가진 노드에 POD을 배포해라.
가 될 수 있고 preferredDuringSchedulingIgnoredDuringExecution
은 가급적 XYZ zone의 노드에 배포되었으면 좋겠지만 안된다면 다른데 배포해라.
정도이다.
node affinity
에 대한 예시코드는 아래와 같다.
pods/pod-with-node-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/e2e-az-name
operator: In
values:
- e2e-az1
- e2e-az2
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: k8s.gcr.io/pause:2.0
위에서 설명하지 않은 명세에 관한 추가정보는 아래와 같은것들이 있다.
operator
종류는 아래의 것들이 가능하다.
- In
- NotIn
- Exists
- DoesNotExist
- Gt
- Lt
nodeSelector
및 nodAffinity
조합에 따른 POD 배포 조건은 아래와 같다.
– 만약 nodeSelector
와 nodeAffinity
가 둘다 명시 -> 두조건 모두 충족해야함
– 여러개의 nodeSelectorTerms
이 nodeAffinity
타입으로 명시 -> nodeSelectorTerms
중 하나만 충족해도 됨
– 여러개의 matchExpressions
이 nodeSelectorTerms
아래 명시 -> 모든 조건 충족해야함
– affinity selection은 스케쥴링때만 적용되고 런타임으로 적용되지 않음
weight
는 preferred...
으로 시작하는 조건에 가중치를 부여하는 것으로 1~100의 값으로 정의된다.
3-2. Node Affinity 실제 적용해보기
aurochsapp-nodeaffinity-deploy.yaml
로 예제를 만들었다.
기존 nodeSelector
와 문법만 바뀌고 동일하게 node label이 aurochsapp=large
인 node를 찾고 여기에 Pod을 배치한다.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: aurochsapp
labels:
env: test
spec:
replicas: 2
template:
metadata:
labels:
env: test
spec:
containers:
- name: nginx
image: 원하는이미지
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: aurochsapp
operator: In
values:
- large
위와 같은 Pod명세로 deployment를 만들고 pod을 확인해보면 아래와 같이 원하는 node들로 배포가 된것을 확인 할 수 있다.
$ kubectl create -f aurochsapp-nodeaffinity-deploy.yaml
deployment "aurochsapp" created
$ kubectl create -f log2mat-nodeaffinity-deploy.yaml
deployment "log2mat" created
$ kubectl create -f stargate-nodeaffinity-deploy.yaml
deployment "stargate" created
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
aurochsapp-547946678b-jpjj7 1/1 Running 0 18h 10.230.6.59 search-so-dev54
aurochsapp-547946678b-svdzd 1/1 Running 0 18h 10.230.5.160 search-so-dev52
log2mat-5b5758964-fqc4v 1/1 Running 0 18h 10.230.6.140 search-so-dev54
log2mat-5b5758964-ppnfx 1/1 Running 0 18h 10.230.7.126 search-so-dev55
stargate-6464cc9647-6w525 1/1 Running 0 18h 10.230.5.228 search-so-dev52
stargate-6464cc9647-k2n9n 1/1 Running 0 18h 10.230.7.180 search-so-dev55
4. Inter-pod affinity and anti-affinity
POD 간에 affinity, anti-affinity를 명시할 수 있는데 현재로써는 node affinity
도 충분하다고 판단하여 내용을 유심히 보지 않았다.