스터디

KCD 참석후기 - 쿠버네티스에서 스케줄링 작동 방식

엔지니어-여리 2024. 9. 28. 22:47
반응형

안녕하세요. 이 글은 2024년 9월 24일 Cloud Native Korea Community Day 2024에 참석한 후기를 담고 있습니다.

 

가장 인상적이었던 주제는 쿠버네티스 스케줄러에 관한 내용이었습니다. 이번 글에서는 쿠버네티스 scheduling에 대한 내용 및 1.30버전부터 GA된 scheduling gate에 대해 다뤄보고자 합니다.

 

scheduler가 하는 일

scheduler는 3가지 일을 합니다. scheduling, preemption, eviction 입니다.

- scheduling은 신규 pod 생성을 말합니다.

- preemption은 더 우선순위가 높은 pod를 생성하기 위해 우선순위가 낮은 pod를 삭제하는 것을 말합니다.

- eviction은 리소스가 부족한 노드에서 pod를 삭제하는 것을 말합니다.

이중 오늘은 scheduling이 어떻게 동작하는지 다뤄보고자 합니다.

 

스케줄링은 kubelet이 파드를 실행할 수 있도록 파드가 노드에 적합한지 확인하는 일을 말합니다.

 

kube-scheduler 

쿠버네티스의 기본 스케줄러이고, 컨트롤 플레인의 일부입니다. 스케줄러는 이름에서 알다시피 스케줄링을 합니다.

스케줄링은 앞에서 말한 것과 같이 새로운 pod를 생성합니다. 물론 pod는 어떤 노드에 배포되어야 합니다. 결국 pod가 어떤 노드에 배포되어야 하는지 결정한다고 볼 수 있습니다. kube-scheduler는 2가지 단계로 파드가 생성될 노드를 선택합니다.

 

scheduling framework

1. filtering: 필터링은 pod를 스케줄링 할 수 있는 노드 셋을 찾는 작업입니다. 

2. scoring: 스코어링은 선택된 노드 셋중에 실제로 pod가 배포될 노드를 찾는 작업입니다.

 

먼저, 필터링을 하기 전에 클러스터내에서 얼마나 많은 노드에 대해서 필터링 & 스코어링을 해야하는지 결정할 수 있습니다. 이는 스케줄러의 성능 최적화를 말합니다. percentageOfNodesToScore 옵션의 값으로 정의합니다. 0~100 사이의 값으로 설정가능합니다. 

percentageOfNodesToScore의 값의 기본 값은 워커노드가 늘어날수록 선형적으로 감소됩니다. 50에서부터 감소되어서 최소 수치는 5입니다.

// WithPercentageOfNodesToScore sets percentageOfNodesToScore for Scheduler.
// The default value of 0 will use an adaptive percentage: 50 - (num of nodes)/125.
func WithPercentageOfNodesToScore(percentageOfNodesToScore *int32) Option {
	return func(o *schedulerOptions) {
		if percentageOfNodesToScore != nil {
			o.percentageOfNodesToScore = *percentageOfNodesToScore
		}
	}
}

https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler/scheduler.go

 

kubernetes/pkg/scheduler/scheduler.go at master · kubernetes/kubernetes

Production-Grade Container Scheduling and Management - kubernetes/kubernetes

github.com

 

필터링

필터링에서는 어떤 노드를 선택할지를 결정하는 단계라고 이해할 수 있습니다. taint, toleration, affinity, resource availability 등에 따라서 현재 파드가 배포가될 수 있는지 여부를 확인하는 단계입니다. 이를 통해서 선택된 워커노드 목록중 파드가 배포될 수 있는 파드를 (말그대로) 필터링 한다고 생각할 수 있습니다.

만약 필터링 결과로 노드가 1개만 선택된 경우 스코어링을 하지 않고 바로 해당 노드에 pod가 생성됩니다.

 

스코어링

 

위 그림을 보기 편하도록 표로 정리해보았습니다.

score는 아래 표와 같이 매겨집니다.

구분 점수
TaintToleration 3
NodeAffinity 2
PodTopologySpread 2
InterPodAffinity 2
NodeResourcesFil 1
VolumeBinding 1
NodeResourcesBalancedAllocation 1
ImageLocality 1

 

TaintToleration과 NodeAffinity중 TaintToleration이 더 높은 우선순위를 가지고 있음을 알 수 있네요.

만약, 스코어링을 통해서 같은 점수를 가진 노드가 있다면 kube-scheduler가 임의의 노드를 선택하게됩니다.

 

왜 이렇게 스케줄링이 복잡한 걸까요?

 

(개인적인 견해입니다.) 이렇게 생각해보겠습니다. 하나의 클러스터에 데이터플레인을 구성하고 있는 워커노드가 3대 있습니다.

여기서 새로운 디플로이먼트셋이 배포되고, 이로 인해 10개의 파드가 생성된다고 했을때 스케줄링은 아주 찰나의 시간만 필요할 것입니다. 이로 인해서 컨트롤 플레인에 큰 부하가 있진 않을 것입니다. 

하지만, 워커노드가 2,000대쯤 존재한다고 가정해볼까요? 여기서 동일한 디플로이먼트셋을 배포한다면 스케줄링 과정이 컨트롤 플레인에 얼마나 많은 부하를 가져올까요? 거기다가 파드의 수명 주기에 얼마나 많은 영향을 줄까요?  이로 인해서 파드가 늦게 뜬다면 사용자 경험에 큰 영향을 주지 않을까 합니다.

그래서 현재와 같이 복잡한 스케줄링 방식을 통해 노드가 많더라도 빠른 스케줄링을 제공하지 않는가 합니다.

 

Pod Scheduling Readiness

이 기능은 v1.26버전부터 베타 기능으로 추가되었고 쿠버네티스 v1.30에서 scheduling gate가 GA 되었습니다. 이 기능은 어떤 용도로 사용될까요 ?

먼저 기존의 scheduling은 이렇게 동작합니다. pod 생성 후 스케줄링, 파드 실행의 단계로 이어집니다.

 

 

여기서 발생하는 문제는 없을까요?

 

모든 노드에 대해서 스케줄링이 되지 않는다면 스케줄링은 완료될 때까지 api 요청을 계속하게 됩니다. 이는 컨트롤 플레인에 큰 영향을 줄 수 있습니다.

 

scheduling gate라는 기능은 다음과 같이 동작합니다. pod의 .spec.schedulingGates를 정의함으로써 scheduling gate가 부여됩니다. .spec.schedulingGates가 정의되면 파드를 생성하되, 스케줄링될 시기를 제어할 수 있습니다. pod의 .spec.schedulingGates를 삭제하면 다시 스케줄링되어 파드가 생성됩니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 10
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
      schedulingGates:
        - name: gate

실행 결과
schedulingGate 삭제 후

deployment set에서 scheduling gate 태그를 삭제하게 되면 새로운 레플리카 셋으로 파드가 실행됩니다.

 

scheduling gate의 이점

- 동적으로 pod의 수명주기를 제어할 수 있다는 점에서 scheduling gate가 사용될 수 있을 것으로 보입니다.

- 온프레미스 환경과 같이 워커 노드의 사이즈가 유연하게 변경될 수 없는 경우 불필요한 스케줄링이 발생하지 않을 수 있습니다.

 

scheduling gate 사용 사례

- gpu 머신과 같은 한정적인 자원을 포함하는 클러스터의 경우, gpu 머신에 해당하는 job을 미리 정의한 뒤 이전 job이 종료될 때 생성해둔 job의 schedulingGate를 삭제하여 동적으로 파드를 할당할 수 있습니다.

- 워크로드 정의(yaml)가 동적으로 스케줄링되어, 노드와 스케줄링이 최적화를 고려할 수 있습니다.

 

 

참고문헌

쿠버네티스 스케줄링 컨셉  https://kubernetes.io/ko/docs/concepts/scheduling-eviction/

쿠버네티스 스케줄링 준비성 https://kubernetes.io/ko/docs/concepts/scheduling-eviction/pod-scheduling-readiness/

쿠버네티스 스케줄링 준비성 개발 티켓 https://github.com/kubernetes/enhancements/tree/master/keps/sig-scheduling/3521-pod-scheduling-readiness

쿠버네티스 스케줄러 소스코드 https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler/scheduler.go

 

 

 

 

 

반응형