🚀 kube-scheduler
kube-scheduler
는 파드나 컨트롤러를 만들었을 때 또는 스케줄링을 할 때 파드를 어디에 배치시킬 것인지 결정한다.
kube-scheduler
는 각 노드를 필터링하고 스코어링한다.
필터링은 어떤 노드의 어떤 리소스를 볼 것인가 하는 기준을 정하는 것이고
스코어링은 해당 기준에 따라서 가중치를 두며 이에 기반해 점수를 매긴다.
즉, 노드가 여러개 있는 경우 각 노드마다 점수를 매겨서 파드를 만들었을 때
파드를 어디에 배치할 것인지 결정하는 것이 kube-scheduler
가 하는 역할이다.
필터링, 스코어링을 어떻게 할 것인지 구성할 수 있다.
🚀 nodeName
노드에 파드 할당하기 | KubernetesnodeName
은 가능하면 사용하지 않는 것을 권장한다.nodeName
은 실질적으로 스케줄링을 사용하지 않는다.
kube-scheduler
의 영향을 받지 않고 특정 노드에 강제로 배치할 수 있다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeName: kube-01
파드 선언시 spec.nodeName
이라는 필드가 있다.
이 필드를 지정하면 해당 파드는 지정한 노드에만 배치된다.
즉, 스케줄링의 필터링, 스코어링을 무시하고 강제로 배치시킬 수 있다.
vagrant@k8s-node1 ~ kubectl explain pod.spec.nodeName
KIND: Pod
VERSION: v1
FIELD: nodeName <string>
vagrant@k8s-node1 ~ kubectl explain rs.spec.template.spec.nodeName
KIND: ReplicaSet
VERSION: apps/v1
FIELD: nodeName <string>
vagrant@k8s-node1 ~ kubectl explain deploy.spec.template.spec.nodeName
KIND: Deployment
VERSION: apps/v1
FIELD: nodeName <string>
Pod
, RS
, Deploy
, STS
에 모두 nodeName
필드가 존재한다.
🚀 실습
myweb-rs-nn.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myweb-rs-nn
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
nodeName: node2
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
vagrant@k8s-node1 ~/schedule/nodename kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myweb-rs-nn-82lxr 1/1 Running 0 33s 10.233.96.137 node2 <none> <none>
myweb-rs-nn-mcgxp 1/1 Running 0 33s 10.233.96.135 node2 <none> <none>
myweb-rs-nn-szphk 1/1 Running 0 33s 10.233.96.136 node2 <none> <none>
nfs-client-provisioner-758f8cd4d6-wpjbt 1/1 Running 0 2d19h 10.233.92.110 node3 <none> <none>
고가용성을 위해 복제본을 구성했지만 nodeName
설정 때문에 노드 3개 모두가 node2
에 배치되었다.
노드 장애가 발생하면 해당 App은 더이상 실행할 수 없다.
replicas
가 1개라면 어떤 노드에 배치시킬 것인지를 결정할 때 사용할 수는 있지만
기본적으로 여러개의 복제본을 구성하는 경우 장점이 없다.
🚀 nodeSelector
필요한 특정 구성이 있는 경우 특정 노드 그룹을 만들어서 배치시킬 수 있다.
노드에 레이블을 적절하게 붙여서 특정 파드를 원하는 위치에만 배치시킬 수 있다.
vagrant@k8s-node1 ~/cont/ds kubectl get ds
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
myweb-ds 3 3 2 3 2 <none> 4s
NODE SELECTOR
항목을 볼 수 있다.
데몬셋의 경우 NODE SELECTOR
를 많이 사용하는 워크로드 중 하나이다.
그렇지만 데몬셋만이 NODE SELECTOR
를 사용할 수 있는 것은 아니다.
vagrant@k8s-node1 ~/schedule/nodename kubectl explain pod.spec.nodeSelector
KIND: Pod
VERSION: v1
FIELD: nodeSelector <map[string]string>
vagrant@k8s-node1 ~/schedule/nodename kubectl explain deploy.spec.template.spec.nodeSelector
KIND: Deployment
VERSION: apps/v1
FIELD: nodeSelector <map[string]string>
vagrant@k8s-node1 ~/schedule/nodename kubectl explain sts.spec.template.spec.nodeSelector
KIND: StatefulSet
VERSION: apps/v1
FIELD: nodeSelector <map[string]string>
vagrant@k8s-node1 ~/schedule/nodename kubectl explain rc.spec.template.spec.nodeSelector
KIND: ReplicationController
VERSION: v1
FIELD: nodeSelector <map[string]string>
모든 컨트롤러는 nodeSelector
라는 구성이 존재한다. 노드에 부여된 노드의 레이블과 매칭시킨다.
📌 노드 레이블 확인하기
kubectl get nodes --show-labels
node1
beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=node1
kubernetes.io/os=linux
node-role.kubernetes.io/control-plane=
node-role.kubernetes.io/master=
node.kubernetes.io/exclude-from-external-load-balancers=
node-role.kubernetes.io/control-plane=
node-role.kubernetes.io/master=
node.kubernetes.io/exclude-from-external-load-balancers=
해당 내용은 컨트롤 플레인에서만 확인할 수 있다.
클라우드 환경에서는 각 클라우드에서 필요한 노드 레이블이 기본적으로 붙어있다.
node2
beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=node2
kubernetes.io/os=linux
node3
beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=node3
kubernetes.io/os=linux
📌 노드에 레이블 부여하기
vagrant@k8s-node1 ~/schedule/nodename kubectl label node node1 gpu=highend
node/node1 labeled
vagrant@k8s-node1 ~/schedule/nodename kubectl label node node2 gpu=midrange
node/node2 labeled
vagrant@k8s-node1 ~/schedule/nodename kubectl label node node3 gpu=lowend
node/node3 labeled
vagrant@k8s-node1 ~/schedule/nodename kubectl get nodes -L gpu
NAME STATUS ROLES AGE VERSION GPU
node1 Ready control-plane,master 10d v1.22.8 highend
node2 Ready <none> 10d v1.22.8 midrange
node3 Ready <none> 7d20h v1.22.8 lowend
명령형 커맨드를 이용해 노드에 레이블을 부여할 수 있다.-L
: key를 지정해서 필드로 볼 수 있다.
myweb-rs-ns.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myweb-rs-ns
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
nodeSelector:
gpu: lowend
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
vagrant@k8s-node1 ~/schedule/nodeselector kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myweb-rs-ns-gzbwx 1/1 Running 0 4s 10.233.92.157 node3 <none> <none>
myweb-rs-ns-hcc5c 1/1 Running 0 4s 10.233.92.156 node3 <none> <none>
myweb-rs-ns-v28cd 1/1 Running 0 4s 10.233.92.158 node3 <none> <none>
nfs-client-provisioner-758f8cd4d6-wpjbt 1/1 Running 0 2d19h 10.233.92.110 node3 <none> <none>
모두 node3에 배치된 것을 볼 수 있다. 노드에 셀렉팅되는 것이 1개밖에 없기 때문이다.
vagrant@k8s-node1 ~/schedule/nodeselector kubectl label node node2 gpu=lowend --overwrite
node/node2 labeled
vagrant@k8s-node1 ~/schedule/nodeselector kubectl get nodes -L gpu
NAME STATUS ROLES AGE VERSION GPU
node1 Ready control-plane,master 10d v1.22.8 highend
node2 Ready <none> 10d v1.22.8 lowend
node3 Ready <none> 7d20h v1.22.8 lowend
vagrant@k8s-node1 ~/schedule/nodeselector kubectl delete po -l app=web
pod "myweb-rs-ns-gzbwx" deleted
pod "myweb-rs-ns-hcc5c" deleted
pod "myweb-rs-ns-v28cd" deleted
vagrant@k8s-node1 ~/schedule/nodeselector kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myweb-rs-ns-m2cjh 1/1 Running 0 8s 10.233.96.140 node2 <none> <none>
myweb-rs-ns-pf6dj 1/1 Running 0 8s 10.233.96.139 node2 <none> <none>
myweb-rs-ns-vq44h 1/1 Running 0 8s 10.233.92.159 node3 <none> <none>
nfs-client-provisioner-758f8cd4d6-wpjbt 1/1 Running 0 2d19h 10.233.92.110 node3 <none> <none>
node2의 gpu를 lowend로 바꾸고 app이 web인 파드를 전부 삭제하면 파드가 재생성되고 다시 스케줄링이 된다.
node2번과 node3번에 걸쳐 파드가 배치되는 것을 볼 수 있다.
스케줄러는 우리가 지정한 노드의 레이블을 확인하고 어떻게 분산할 것인지 결정한다.
따라서 gpu가 lowend가 아닌 node1은 배치의 대상이 아니다.
📌 사용 사례
상용환경에서 4개의 노드 중 2개에만 gpu 인스턴스가 있다고 하자
인공지능 모델링 같은 고성능 컴퓨팅을 요구하는 작업을 할 때
nodeSelector
를 지정하지 않고 그래픽카드가 없는 다른 노드에 배치시키면 작업이 매우 느리게 진행된다.
gpu 인스턴스는 매우 비싸기 때문에 gpu:on
같은 레이블을 달아놓고
리소스를 만들 때 nodeSelector
를 이용하여 해당 레이블이 있는 노드에만 배치시킬 수 있다.
ARM CPU를 가진 노드 2개와 X86 CPU를 가진 노드 2개가 있을 때
사용할 이미지가 특정 CPU에서만 돌아가는 이미지라면 ARM CPU에 배치시켰을 때 실행 자체가 안된다.
kubernetes.io/arch=amd64
라고 하는 셀렉터를 부여해서 적절하게 배치될 수 있도록 구성할 수 있다.
AWS의 경우 nodeSelector
를 사용해 원하는 가용영역에 배치시킬 수 있다.
'DevOps > Kubernetes' 카테고리의 다른 글
[Kubernetes] Cordon & Drain (0) | 2022.06.06 |
---|---|
[Kubernetes] Affinity (affinity, anti-affinity) (0) | 2022.06.05 |
[Kubernetes] HPA : Horisontal Pod AutoScaler (파드의 오토 스케일링) (0) | 2022.06.04 |
[Kubernetes] Resource Request & Limit (리소스 요청과 제한) (0) | 2022.06.04 |
[Kubernetes] StatefulSet (스테이트풀)과 Headless Service (헤드리스 서비스) (0) | 2022.06.04 |
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!