본문 바로가기

Container/Kubernetes

[K8S] kube-scheduler

kube-scheduler란,

쿠버네티스 node의 pods들의 scheduling을 관리하는 컴포턴트로, 클러스터 내에서 실행될 파드(pod)를 적절한 노드(node)에 배치하는 역할을 한다. 즉, 어떤 파드를 어떤 노드에서 실행할 것인가를 결정한다.

√ pod를 node에 두는 것을 결정하는 것이 아니다 ☞ kubelet의 업무

 

주요 역할

  1. 파드 배치 결정: 스케줄링이 필요한 새 파드가 생성되면, kube-apiserver가 이를 kube-scheduler로 전달하고, 클러스터 내 노드 중 가장 적합한 노드를 선택한다.
  2. 스케줄링 조건 평가:
    • 파드 요구사항과 노드 리소스 상태를 고려하여 적합한 노드를 선택한다.
      • 예: CPU, 메모리, 태그(label), 노드 셋(label selector) 등의 조건
  3. 클러스터 리소스 최적화: 클러스터 전체의 리소스 사용률을 최적화하기 위해 스케줄링 수행
  4. 다양한 스케줄링 정책 지원: 기본 스케줄링 외에도 사용자 정의 정책과 우선순위(Preemption) 지원

구성 파일 설정

  • /etc/kubernetes/manifests/kube-scheduler.yaml

 

동작 원리

  1. 스케줄링 요청 수신:
    • 새로운 파드가 생성되면, kube-apiserver가 이를 kube-scheduler로 전달한다.
  2. 적합한 노드 선택:
    • kube-scheduler는 아래 두 단계를 통해 적합한 노드를 선택한다.
      • 필터링 단계(Predicates):
        • 노드 중에서 파드의 요구사항을 충족하지 못하는 노드를 제외시킨다.
          • 예: 노드에 리소스 부족, 태그 불일치(Label Selector), 노드 준비 상태, Taint/Toleration 등
      • 점수화 단계(Priorities):
        • 필터링을 통과한 노드들에 대해 점수를 매기고, 가장 높은 점수를 받은 노드를 선택한다.
          • 리소스 효율성, 노드 간 거리(Topology), 노드 선호도
  3. 스케줄링 결정:
    • 선택된 노드를 해당 파드의 "NodeName" 필드에 기록하여 스케줄링 완료
  4. 스케줄링 결과 전달:
    • kube-scheduler는 스케줄링 결과를 kube-apiserver에 전달하고, 파드는 지정된 노드에서 실행된다.

Manual Scheduling

 

만약 Pod의 노드를 배정하지 못했다면 Binding 개체를 생성하고, Pod의 binding API에 post request를 보내 scheduler의 역할을 대신한다.

# Pod-bind-definition.yaml
apiVersion: v1
kind: Binding
metadata:
  name: nginx
target:
  apiVersion: v1
  kind: Node
  name:
  nodeName: node02

# curl --header "Content-Type:application/json" --request POST --data http://$SERVER/api/v1/namespaces/default/pods/$PODNAME/binding/

 

실습]

controlplane ~ $ cat nginx.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  -  image: nginx
     name: nginx
     
controlplane ~ ➜  kubectl create -f nginx.yaml 
pod/nginx created

controlplane ~ ➜  kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   0/1     Pending   0          15s

# 현재 scheduler가 작동중지 않아서 Node가 배정되지 않았다.
controlplane ~ ➜  kubectl get pods -n kube-system 
NAME                                   READY   STATUS    RESTARTS   AGE
coredns-77d6fd4654-4pjh9               1/1     Running   0          5m33s
coredns-77d6fd4654-4vnf4               1/1     Running   0          5m33s
etcd-controlplane                      1/1     Running   0          5m38s
kube-apiserver-controlplane            1/1     Running   0          5m38s
kube-controller-manager-controlplane   1/1     Running   0          5m38s
kube-proxy-mf9m5                       1/1     Running   0          5m2s
kube-proxy-w76tl                       1/1     Running   0          5m34s

controlplane ~ ➜  kubectl describe pod nginx | grep Node
Node:             <none>
Node-Selectors:              <none>

 

Multi-Scheduler

Reference: https://kubernetes.io/docs/tasks/extend-kubernetes/configure-multiple-schedulers/

 

Multi-Scheduler의 사용 목적

  1. 특정 요구사항 처리:
    • 기본 스케줄러로 충족할 수 없는 복잡한 스케줄링 로직 구현.
    • 예: 특정 하드웨어(GPU, 고속 네트워크 등)에 대한 스케줄링.
  2. 다양한 워크로드 지원: 서로 다른 워크로드를 다양한 스케줄링 정책으로 처리.
  3. 리소스 격리: 고유한 스케줄링 로직을 통해 워크로드가 특정 노드나 리소스를 차지하도록 보장.
쿠버네티스는 기본적으로 default-scheduler (scheduler-config.yaml) 사용한다.
그러나 default-scheduler가 needs에 맞지 않을때 custom scheduler를 만들고, 동시에 돌릴 수 있다.
각각의 scheduler는 별개의 config file을 사용해야 하고,
추가로 생성하는 custom-scheduler는 my-scheduler-config.yaml, my-scheduler-2-config.yaml와 같이 지어줄 수 있다.

 

 
# Use Custom Scheduler
custom scheduler가 deploy되고나서 해야할 것은 다음과 같다.
1. configure pod or custom scheduler를 사용하기 위한 deployment 만들기

✨사용자 정의 스케줄러는 일반적으로 Deployment로 배포 
2.  Pod Definition file을 만든다.

  • scheduler를 Pod처럼 동작시켜주려면, Pod Definition file을 만들어 줘야 한다.
    • scheduler conf file(auth 정보로 API server에 연결할 수 있다)의 Path 지정
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
  schedulerName: custom-scheduler # schedulerName 필드를 사용하여 특정 스케줄러를 지정

3. Pod 생성 (kubectl create -f pod-definition.yaml)
    - yaml파일이 잘못되면 pod는 계속 pending상태로 남아 있는다.

 

Multi-Scheduler의 동작 원리

  1. Pod 스케줄링 요청:
    • Pod이 생성되면 schedulerName 필드에 따라 스케줄러가 선택된다. (기본값은 default-scheduler)
  2. 스케줄러 선택:
    • Kubernetes는 Pod의 schedulerName에 따라 적절한 스케줄러로 요청을 전달한다.
  3. 노드 선택:
    • 선택된 스케줄러는 해당 Pod에 가장 적합한 노드를 결정.
  4. 스케줄링 완료: 선택된 노드에 Pod 실행.

# leaderElection

고가용성을 보장하기 위해  리더(Leader)를 선출하고, 클러스터 내에서 리더가 작업을 독점적으로 수행하도록 하는 메커니즘이다. 이를 통해 같은 작업을 중복 수행하지 않도록 방지하고, 리더가 실패했을 경우 새로운 리더를 선출하여 작업을 지속할 수 있다.

apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
leaderElection:
  leaderElect: true
  leaseDuration: 15s
  renewDeadline: 10s
  retryPeriod: 2s

leaderElect: 리더 선출 기능 활성화 여부.

  • true: 리더 선출을 활성화.
  • false: 모든 인스턴스가 작업을 수행.

leaseDuration:

  • 리더로 유지되는 최대 시간. 이 시간이 지나면 다른 후보가 리더로 선출될 수 있음.
  • 리더는 주기적으로 리스를 갱신하여 자신의 리더십을 유지
  • 리더가 실패하거나 리스를 갱신하지 못하면, 리스가 만료되고 새로운 리더가 선출

 

# View Events

$ kubectl get events
controlplane ~ ➜  kubectl get events
LAST SEEN   TYPE      REASON                    OBJECT              MESSAGE
27m         Warning   InvalidDiskCapacity       node/controlplane   invalid capacity 0 on image filesystem
27m         Normal    NodeHasSufficientMemory   node/controlplane   Node controlplane status is now: NodeHasSufficientMemory
27m         Normal    NodeHasNoDiskPressure     node/controlplane   Node controlplane status is now: NodeHasNoDiskPressure
27m         Normal    NodeHasSufficientPID      node/controlplane   Node controlplane status is now: NodeHasSufficientPID
27m         Normal    NodeAllocatableEnforced   node/controlplane   Updated Node Allocatable limit across pods
27m         Normal    Starting                  node/controlplane   Starting kubelet.
27m         Warning   InvalidDiskCapacity       node/controlplane   invalid capacity 0 on image filesystem
27m         Normal    NodeHasSufficientMemory   node/controlplane   Node controlplane status is now: NodeHasSufficientMemory
27m         Normal    NodeHasNoDiskPressure     node/controlplane   Node controlplane status is now: NodeHasNoDiskPressure
27m         Normal    NodeHasSufficientPID      node/controlplane   Node controlplane status is now: NodeHasSufficientPID
27m         Normal    NodeAllocatableEnforced   node/controlplane   Updated Node Allocatable limit across pods
27m         Normal    RegisteredNode            node/controlplane   Node controlplane event: Registered Node controlplane in Controller
27m         Normal    Starting                  node/controlplane   
27m         Normal    NodeReady                 node/controlplane   Node controlplane status is now: NodeReady
100s        Normal    Scheduled                 pod/nginx           Successfully assigned default/nginx to controlplane
99s         Normal    Pulling                   pod/nginx           Pulling image "nginx"
94s         Normal    Pulled                    pod/nginx           Successfully pulled image "nginx" in 4.994s (4.994s including waiting)
94s         Normal    Created                   pod/nginx           Created container nginx
94s         Normal    Started                   pod/nginx           Started container nginx

 

# View scheduler logs

$ kubectl logs <component-pod-name> -n kube-system

$ kubectl logs my-scheduler -n kube-system

 
# 실습

# custom-scheduler가 사용할 ServiceAccount 와 ClusterRoleBinding 생성해 놓은 상태.
$ kubectl get sa my-scheduler -n kube-system
NAME           SECRETS   AGE
my-scheduler   0         33s

$ kubectl get clusterrolebinding
NAME                                                     ROLE                                                                               AGE
cluster-admin                                            ClusterRole/cluster-admin                                                          8m11s
flannel                                                  ClusterRole/flannel                                                                8m7s
kubeadm:cluster-admins                                   ClusterRole/cluster-admin                                                          8m10s
kubeadm:get-nodes                                        ClusterRole/kubeadm:get-nodes                                                      8m9s
kubeadm:kubelet-bootstrap                                ClusterRole/system:node-bootstrapper  
...


# Let's create a configmap that the new scheduler will employ using the concept of ConfigMap as a volume.
# We have already given a configMap definition file called my-scheduler-configmap.yaml at /root/ path that will create a configmap with name my-scheduler-config using the content of file /root/my-scheduler-config.yaml.

$ cat my-scheduler-config.yaml 
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
  - schedulerName: my-scheduler
leaderElection:
  leaderElect: false
        
$ kubectl create configmap my-scheduler-config --from-fi
le /root/my-scheduler-config.yaml -n kube-system
configmap/my-scheduler-config created

$  kubectl get configmap my-scheduler-config -n kube-system
NAME                  DATA   AGE
my-scheduler-config   1      93s


$ kubectl get pods -A
NAMESPACE      NAME                                   READY   STATUS    RESTARTS   AGE
kube-flannel   kube-flannel-ds-j4m5q                  1/1     Running   0          14m
kube-system    coredns-69f9c977-pftw7                 1/1     Running   0          14m
kube-system    coredns-69f9c977-z2m6q                 1/1     Running   0          14m
kube-system    etcd-controlplane                      1/1     Running   0          14m
kube-system    kube-apiserver-controlplane            1/1     Running   0          14m
kube-system    kube-controller-manager-controlplane   1/1     Running   0          14m
kube-system    kube-proxy-44z4g                       1/1     Running   0          14m
kube-system    kube-scheduler-controlplane            1/1     Running   0          14m
# current scheduler.


# 사용자 정의 scheduler를 deploy해준다.
# /root/my-scheduler.yaml에 제공된 manifest file을 사용하고,
# default kubernetes scheduler에 의해 사용된 같은 image를 사용한다.
controlplane ~ ➜  cat my-scheduler.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: my-scheduler
  name: my-scheduler
  namespace: kube-system
spec:
  serviceAccountName: my-scheduler
  containers:
  - command:
    - /usr/local/bin/kube-scheduler
    - --config=/etc/kubernetes/my-scheduler/my-scheduler-config.yaml
    image: registry.k8s.io/kube-scheduler:v1.31.0
    livenessProbe:
      httpGet:
        path: /healthz
        port: 10259
        scheme: HTTPS
      initialDelaySeconds: 15
    name: kube-second-scheduler
    readinessProbe:
      httpGet:
        path: /healthz
        port: 10259
        scheme: HTTPS
    resources:
      requests:
        cpu: '0.1'
    securityContext:
      privileged: false
    volumeMounts:
      - name: config-volume
        mountPath: /etc/kubernetes/my-scheduler
  hostNetwork: false
  hostPID: false
  volumes:
    - name: config-volume
      configMap:
        name: my-scheduler-config

$ kubectl describe pod kube-scheduler-controlplane -n kube-system | grep Image
    Image:         registry.k8s.io/kube-scheduler:v1.29.0
    Image ID:      registry.k8s.io/kube-scheduler@sha256:5df310234e4f9463b15d166778d697830a51c0037ff28a1759daaad2d3cde991

$ kubectl create -f my-scheduler.yaml 
pod/my-scheduler created

$ kubectl get pods -n kube-system
NAME                                   READY   STATUS    RESTARTS   AGE
coredns-69f9c977-pftw7                 1/1     Running   0          22m
coredns-69f9c977-z2m6q                 1/1     Running   0          22m
etcd-controlplane                      1/1     Running   0          22m
kube-apiserver-controlplane            1/1     Running   0          22m
kube-controller-manager-controlplane   1/1     Running   0          22m
kube-proxy-44z4g                       1/1     Running   0          22m
kube-scheduler-controlplane            1/1     Running   0          22m
my-scheduler                           1/1     Running   0          5s

controlplane ~ ➜  cat nginx-pod.yaml 
apiVersion: v1 
kind: Pod 
metadata:
  name: nginx 
spec:
  schedulerName: my-scheduler  # 이렇게 사용할 scheduler 지정해주기
  containers:
  - image: nginx
    name: nginx
    
controlplane ~ ➜  kubectl create -f nginx-pod.yaml 
pod/nginx created

controlplane ~ ➜  kubectl get pods
NAME    READY   STATUS              RESTARTS   AGE
nginx   0/1     ContainerCreating   0          3s

# my-scheduler로 작동 최종 확인
controlplane ~ ➜  kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          56s

 

# 참고문서

1. https://github.com/kubernetes/community/blob/master/contributors/devel/sig-scheduling/scheduling_code_hierarchy_overview.md

2. https://kubernetes.io/blog/2017/03/advanced-scheduling-in-kubernetes/

3. https://jvns.ca/blog/2017/07/27/how-does-the-kubernetes-scheduler-work/

4. https://stackoverflow.com/questions/28857993/how-does-kubernetes-scheduler-work

반응형

'Container > Kubernetes' 카테고리의 다른 글

[K8S] SW Version & Cluster Upgrade  (0) 2024.04.26
[K8S] Logging & Monitoring  (1) 2024.04.26
[K8S] ETCD Backup 및 Restore  (0) 2024.04.21
CKA 시험준비  (0) 2024.04.16
[K8S] cordon & drain  (0) 2024.04.13