Kubernetes scheduler 동작

Winston Lee·2023년 5월 8일
0

k8s

목록 보기
5/9

Kubernetes 스케줄러가 새 파드를 발견하고 노드에 할당하는 방법에 대해

How Kubernetes scheduler works

쿠버네티스 파드는 공유 스토리지 및 네트워크 리소스가 있는 하나 이상의 컨테이너로 구성. Kubernetes 스케줄러의 임무는 각 파드가 실행할 노드에 할당되도록 하는 것입니다.

개략적인 수준에서 Kubernetes 스케줄러의 작동 원리는 다음과 같습니다:
1. 예약해야 하는 모든 파드가 큐에 추가됩니다.
2. 새 파드가 생성되면, 해당 파드도 큐에 추가된다.
3. 스케줄러는 해당 큐에서 지속적으로 파드를 가져와 스케줄링한다.

스케줄러의 코드 scheduler.go는 약 9,000줄에 달하는 방대한 분량이며 상당히 복잡하지만, 중요한 부분은 다음과 같다:

1. Code that waits/watches for pod creation

// Run begins watching and scheduling. It waits for cache to be synced, then starts a goroutine and returns immediately.

func (sched *Scheduler) Run() {
	if !sched.config.WaitForCacheSync() {
		return
	}
go wait.Until(sched.scheduleOne, 0, sched.config.StopEverything) 	

이 코드는 Kubernetes에서 사용되는 스케줄러(Scheduler)의 Run 메서드입니다.

이 메서드는 스케줄링을 시작하는 함수이며, 캐시 동기화를 대기하고 goroutine을 시작합니다.

먼저 WaitForCacheSync 메서드를 사용하여 스케줄러의 캐시 동기화가 완료될 때까지 기다립니다. 캐시가 동기화되면, 스케줄러의 scheduleOne 메서드를 실행하는 goroutine을 시작합니다.

wait.Until 함수는 주어진 함수(scheduleOne)를 반복적으로 실행합니다. 이 함수는 스케줄러가 파드를 하나씩 가져와서 해당 파드를 실행할 수 있는 적절한 노드를 찾아 할당하는 역할을 수행합니다.

마지막으로, sched.config.StopEverything 채널이 닫히면 스케줄러가 중지됩니다.

즉, 이 코드는 스케줄러가 파드를 스케줄링하기 위해 goroutine을 시작하고, 캐시 동기화를 기다린 후 scheduleOne 메서드를 주기적으로 실행하여 파드를 노드에 할당하는 역할을 합니다.

2. Code that is responsible for queuing the pod

파드 큐잉을 담당하는 함수는 다음과 같다:

// queue for pods that need scheduling
	podQueue *cache.FIFO

이벤트 핸들러가 트리거되어 새 파드를 사용할 수 있음을 나타내면 이 코드가 자동으로 새 파드를 큐에 넣습니다:

func (f *ConfigFactory) getNextPod() *v1.Pod {
	for {
		pod := cache.Pop(f.podQueue).(*v1.Pod)
		if f.ResponsibleForPod(pod) {
			glog.V(4).Infof("About to try and schedule pod %v", pod.Name)
			return pod
		}
	}
}

이 코드는 Kubernetes의 스케줄러에서 사용되는 ConfigFactory 타입의 메서드인 getNextPod입니다.

이 메서드는 스케줄러에서 처리할 다음 파드를 가져오는 함수입니다.

코드에서는 cache.Pop 함수를 사용하여 파드 큐에서 다음 파드를 가져옵니다. 가져온 파드는 *v1.Pod 형태로 반환되며, 이를 pod 변수에 할당합니다.

ResponsibleForPod 함수를 사용하여 해당 파드가 현재 스케줄러에 의해 스케줄링될 수 있는지 확인합니다. 만약 해당 파드가 스케줄러에 의해 스케줄링될 수 있다면, pod 변수를 반환하고, 그렇지 않으면 다음 파드를 가져오기 위해 반복문을 계속 실행합니다.

코드에서는 로그를 남기기 위해 glog.V(4) 함수를 사용하여 로그 레벨을 설정하고, "About to try and schedule pod [파드 이름]"이라는 메시지를 로그로 출력합니다.

따라서 이 코드는 파드 큐에서 다음 스케줄링할 파드를 가져오고, 이를 스케줄러에 의해 스케줄링할 수 있는지 확인한 후 해당 파드를 반환하는 역할을 합니다.

3. Code that handles errors

파드 스케줄링에서 스케줄링 오류가 필연적으로 발생할 수 있다. 다음 코드는 스케줄러가 에러를 처리하는 방법이다. 이 스케줄러는 podInformer를 수신한 다음, 파드가 스케줄링되지 않았다는 오류를 출력하고 종료한다:

// scheduled pod cache
	podInformer.Informer().AddEventHandler(
		cache.FilteringResourceEventHandler{
			FilterFunc: func(obj interface{}) bool {
				switch t := obj.(type) {
				case *v1.Pod:
					return assignedNonTerminatedPod(t)
				default:
					runtime.HandleError(fmt.Errorf("unable to handle object in %T: %T", c, obj))
					return false
				}
			},
            

이 코드는 Kubernetes 스케줄러에서 사용되는 이벤트 핸들러 함수입니다. 이벤트 핸들러 함수는 캐시에 저장된 오브젝트의 변경 사항을 감지하고, 변경 사항이 발생할 때마다 실행됩니다.

podInformer는 파드에 대한 informer입니다. informer는 Kubernetes에서 객체의 변경 사항을 감지하고, 변경 사항을 핸들러 함수로 전달합니다.

AddEventHandler 함수는 파드 informer에 대한 이벤트 핸들러를 등록하는 함수입니다. 이벤트 핸들러로는 cache.FilteringResourceEventHandler를 사용하며, 이벤트 발생 시 필터링 및 처리할 리소스 유형과 관련된 함수를 제공합니다.

이 코드에서는 FilterFunc 함수를 사용하여 파드를 필터링하고, assignedNonTerminatedPod 함수를 사용하여 조건을 검사합니다.

assignedNonTerminatedPod 함수는 스케줄러가 할당된 파드를 검사하고, 아직 종료되지 않은 파드만을 대상으로 합니다.

만약 필터링 결과가 true이면 이벤트 핸들러 함수를 실행하고, false이면 실행하지 않습니다.

이 코드는 파드 informer에 대한 이벤트 핸들러를 등록하고, 필터링 조건에 따라 파드 객체의 변경 사항을 처리합니다.

즉, 쿠버네티스 스케줄러가 담당하는 업무들은 :

  • 파드의 리소스 요구를 충족시키기에 충분한 공간을 가진 노드에서 새로 생성된 파드를 스케줄링한다.
  • 새로 생성된 파드의 존재를 위해 kube-apiserver와 컨트롤러를 수신한 다음 클러스터의 사용 가능한 노드로 스케줄링한다.
  • 스케줄되지 않은 파드를 감시하고 /binding pod 하위 리소스 API를 사용하여 노드에 바인딩한다.

예를 들어, 1GB의 메모리와 2개의 CPU 코어가 필요한 애플리케이션이 배포되고 있다고 가정해 보자. 따라서 이 애플리케이션의 파드는 사용 가능한 리소스가 충분한 노드에 생성됩니다. 그런 다음 스케줄러가 계속 실행되면서 스케줄링해야 하는 파드가 있는지 확인합니다.

profile
인프라 엔지니어

0개의 댓글