[Kubernetes] Multiple Schedulers


서론

스케줄러는 taints, tolerations, node affinity 등 다양한 조건을 고려하여 파드를 노드에 고르게 분산시키는 알고리즘을 사용한다.

그런데 나만의 스케줄링 알고리즘을 만들어 파드를 노드에 배치하고자 하려면 어떻게해야 할까?

사용자는 자신만의 스케줄러 프로그램을 작성하여, 이를 쿠버네티스 클러스터에 추가할 수 있다.

일부 애플리케이션들은 기본 스케줄러를 계속 사용할 수 있고, 특정 애플리케이션만 사용자 정의 스케줄러를 사용할 수 있다는 뜻이다.

즉, 쿠버네티스 클러스터는 동시에 여러 개의 스케줄러를 가질 수 있다.

참고로 기본 스케줄러의 이름은 default-scheduler이다.

Binary 방식으로 스케줄러 설정하기

binary 파일을 다운받아 실행 옵션에 커스텀 스케줄러 설정파일 경로를 주어 사용자 정의 스케줄러를 사용할 수 있다.

그러나 요즘은 kubeadm으로 클러스터를 구성하여 control plane의 모든 구성요소들이 클러스터내 파드 또는 디플로이먼트 형태로 실행되어 별도의 실행파일(바이너리)을 통한 사용자 정의 스케줄링 방식은 잘 사용되지 않는다.

Kubeadm

그렇다면 자주 사용되는 파드형태로 사용자 스케줄러를 배포하는 방법에 대해 알아보자

  • 스케줄러를 쿠버네티스에 파드(Pod) 형태로 띄우기 위해 파드 정의 파일을 작성한다.
  • 사용자 정의 스케줄러를 만들기 위해 my-scheduler-config.yaml을 작성한다.
  • 스케줄러가 쿠버네티스 API 서버에 접근할 수 있도록 kubeconfig 옵션에 인증 정보가 담긴 파일 경로를 입력해줘야 한다.
  • 그 다음 사용자 kube-scheduler 설정 파일인 my-scheduler-config.yaml를 my-custom-scheduler.yaml에 config옵션에 넣어줘야한다.
  • 그리고 해당 경로에 my-scheduler-config.yaml 넣고 볼륨을 만들어 my-custom-scheduler.yaml파일에 마운트 시켜주어 설정파일을 전달해준다.
  • 이를 통해schedulerName: my-custom-scheduler로 지정된 Pod들은 사용자 정의 스케줄러가 스케줄링하게 된다.

LeaderElection 옵션

  • leaderElect 옵션은 여러 마스터 노드에서 스케줄러가 중복 실행될 때 사용된다.
  • 스케줄러가 여러 개가 동시에 같은 작업을 하면 충돌이 생기기 때문에 설정해주어 충돌을 막는다
  • 그래서 leaderElect: true를 설정하면, 여러 스케줄러가 여러 노드에서 동시에 실행 중이라면, 오직 하나만 활성 상태가 될 수 있다. 쉽게말해 락을 건다고 보면 된다.
  • --leader-elect=true 와 함께 --lock-object-name=<이름> 을 주면 “같은 lock-object-name을 가진 스케줄러 인스턴스끼리만” 리더 선출(락 경쟁)을 한다.
  • 그리고 ServiceAccount, ClusterRole, ClusterRoleBinding 설정을 해주고 배포하면 된다.
    • 커스텀 스케줄러가 Kubernetes API Server와 통신하고, 스케줄링 관련 리소스를 읽고 조작할 수 있는 권한을 가지게 해주기 위함
  • 이후 생성할 파드에서 사용자 정의 스케줄러를 사용하고싶다면 아래 그림과 같이 schedulerName필드에 이름을 넣어서 사용할 수 있다.
  • 만약 스케줄러가 올바르게 설정되지 않았다면, 해당 Pod는 계속해서 Pending 상태로 남게된다.

그렇다면 어떤 스케줄러가 이 Pod를 스케줄링했는지 어떻게 알 수 있을까?

아래 명령어를 통해 알 수 있으며 SOURCE 영역부분이 해당 스케줄러가 된다.

kubectl get events -o wide

그리고 스케줄러에 문제개 생겼을 경우 로그를 확인하는 방법이다.

kubectl logs <my-scheduler> --name-space=kube-system

쿠버네티스 스케줄링 상세 동작방식

노드는 총 4개가 존재하며, 우리가 파드A를 추가로 하나 만들었다 하자.

파드A는 10개의 CPU를 요구하기 때문에, 남은 CPU가 10개 이상인 노드에만 스케줄링될 수 있으며

파드A뿐만 아니라 다른 파드들도 스케줄링 큐에서 스케줄링되길 기다리고 있다.

이 큐에서는 파드들이 정의된 우선순위에 따라 스케줄링되기를 기다리며 이 예시에서는 파드가 높은 우선순위를 가지고 있다고 가정하자.

우선순위를 설정하려면 Pod-definition.yaml에서 보이는 PriorityClass를 생성해야 하며, 이름과 우선순위 값을 설정해야 한다.

위 처럼 클래스를 생성해주고 1,000,000 우선순위를 부여했다.

높은 우선순위를 가진 파드가 큐의 앞쪽에 배치되어 먼저 스케줄링되게 된다.

이 정렬 과정은 1. 스케줄링 단계에서 일어난다.

그 다음, 실행할 수 없는 노드들이 걸러지는 2. 필터링 단계로 넘어간다.

위 예시에서는 첫 두 노드가 CPU 자원 10개를 제공할 수 없기 때문에 필터링된다.

다음 단계는 3. 스코어링(점수 부여) 단계이다.

이 단계는 남은 두 노드에 대해, 스케줄러가 파드가 요구하는 CPU를 할당한 후 남은 자원을 기준으로 각 노드에 점수를 부여한다.

이 예시에는 첫 번째 노드는 2개의 CPU가 남고, 두 번째 노드는 6개가 남기 때문에 두 번째 노드가 더 높은 점수를 받아 이 노드가 선택된다.

다음 단계는 4. 바인딩 단계이다.

여기서 파드는 최종적으로 가장 높은 점수를 받은 노드에 바인딩 된다.

이러한 모든 작업들은 특정 플러그인들에 의해 수행된다.

예를들어,

  • 스케줄링 큐
    • priorty sort라는 플러그인에 의해 파드를 정렬한다.
  • 필터링 단계
    • node resource fit 플러그인이 노드가 충분한 자원을 가지고 있는지 식별하고 자원이 부족한 노드는 필터링한다.
    • node name 플러그인은 파드에 특정 노드 이름이 설정되어 있는지 확인하고 일치하지 않는 노드들은 필터링한다.
    • Node unschedulable 플러그인은 unschedulable 플래그가 true로 설정된 노드를 필터링한다.
  • 스코어링 단계
    • node resources fit 플러그인이 각 노드에 점수를 할당합니다
    • image locality 플러그인은 배포될 파드가 사용하는 컨테이너 이미지가 이미 존재하는 노드에 대해 높은 점수를 준다.
  • 바인딩 단계
    • defaultBinder 플러그인이 파드를 실제로 노드에 바인딩하는 역할을 한다.

Kubernetes에서는 위와 같은 플러그인들을 어떤 플러그인을 어디에 사용할지 또는 직접 플러그인을 작성해서 연결할 수도 있다.

각 스케줄링 단계에서 extension point 지점에 플러그인을 연결하여 동작을 커스터마이징 할 수 있다.

  • 예) 스케줄링 큐: queue sort라는 Extension point가 있고 여기에 priority sort 플러그인이 연결되어있다.

또한 위의 Extension Point외에도 실제로는 각 단계의 앞뒤로 더 많은 포인트가 존재한다.

따라서 플러그인을 만들어서 원하는 지점에 연결하여 사용할 수 있다.

일부 플러그인들은 여러 단계를 연속적으로 할당하기도하며 일부 플러그인은 특정 Extension Point에서만 동작한다.

Configuring Scheduler Profiles

  • 과거 Kubernetes에서는 여러 개의 스케줄러를 생성할 때, 각 스케줄러마다 별도의 설정 파일을 사용하고 독립적으로 관리하였다.
  • 하지만 이 방식은 스케줄러마다 별도의 프로세스가 생성되어 실행되어 동일한 노드에 대해 동시에 스케줄링을 시도할 경우 race condition이 발생할 수 있다.
    Kubernetes 내부적으로 스케줄러 하나당 하나의 프로세스가 할당
  • 쿠버네티스(1.18+ 이후)는 단일 스케줄러 인스턴스에 여러 프로필을 지원하도록 하여 여러 스케줄러를 하나의 설정 파일에서 관리가 가능하다.
  • 이 방식은 하나의 프로세스내에서 여러 스케줄러가 동작하게된다.

다중 스케줄러를 아래 처럼 구성하게 되면 하나의 실행파일안에서 여러 스케줄러를 관리할 수 있게 된다.

예를들어 my-scheduler-2 프로파일에서는 TaintToleration 플러그인은 비활성화하고 사용자 정의 플러그인을 활성화 할 수 있다.

my-scheduler-3 프로파일의 경우에는, preScore와 score 단계에 있는 모든 플러그인들을 비활성화할 수도 있다.