[kubernetes] 쿠버네티스 패턴 - 자동 배치 -1

자동 배치 패턴은 쿠버네티스 스케줄러의 핵심 기능으로서 컨테이너 자원 요청을 만족하고 스케줄링 정책을 준수하는 노드에 신규 파드를 할당해주는 기능입니다.

문제

컨테이너와 파드는 패키지와 배포를 위한 좋은 추상화를 제공하지만 적절한 노드에 격리된 프로세스들을 배치하는 문제는 해결하지 못했습니다. MSA가 점점 늘어나기 때문에 개별적으로 노드에 할당하고 배치하는 것은 관리하기 어려운 작업입니다.

컨테이너는 컨테이너 서로 간의 의존성, 컨테이너와 노드 간의 의존성, 자원 요구사항, 시간에 따른 변경사항을 가지고 있습니다. 클러스터에서 사용 가능한 자원은 시간이 지남에 따라 클러스터를 확장 축소함에 따라 이미 배치된 컨테이너가 자원을 소비함에 따라 다양하게 변하고 있습니다.

컨테이너를 배치 하는 방법은 가용성, 성능 뿐만 아니라 분산 시스템의 용량에도 영향을 줍니다. 이로인해 노드에 컨테이너를 스케줄링하는 일은 마치 이동 목표물에 과녁을 조준하는 것과도 같습니다.

해결책

k8s에서 파드는 스케줄러에 의해 노드에 할당됩니다. 전체 쿠버네티스 플랫폼에서 스케줄러는 기본적인 역할을 수행하지만 다른 쿠버네티스 컴포넌트와 비슷하게 하나의 독립 프로세스로 실행될 수 있거나 전혀 사용되지 않을 수 있습니다.

상위 레벨에서 보면 쿠버네티스 스케줄러가 수행하는 주요 작업은 API 서버로부터 새로 생성된 파드 정의를 조회하고, 파드를 노드에 할당하는 것입니다. 스케줄러는 초기 애플리케이션 배치를 위한 것이든 스케일 업을 위한 것이든 애플리케이션이 비정상 노드에서 정상 노드로 이동될 때이든간에 모든 파드에 대해 적절한 노드를 찾습니다.

이는 런타임 의존성, 자원 요구사항, 고가용성 가이드 정책 등에 대한 고려를 통해, 그리고 파드의 수평적 확장, 또는 상호 호출 시 성능 및 낮은 지역 시간을 위한 파드들의 가까운 배치 등을 통해 수행됩니다. 그러나 스케줄러가 스케줄링 작업을 정확하게 수행하고 선언적 배치를 가능하게 하려면 가용한 용량을 확보한 노드와 선언된 자원 프로파일 및 가이드 정책을 갖춘 컨테이너가 필요합니다.

가용한 노드 자원

쿠버네티스 클러스터에는 새로운 파드를 실행하기 위해 충분한 자원 용량을 확보한 노드가 있어야합니다. 모든 노드에는 파드를 실해할 수 있는 용량이 있고 스케줄러는 파드가 요청한 자원의 총합이 할당 가능한 노드의 용량보다 작다는 것을 확인해야 합니다.

쿠버네티스 전용 노드만을 고려하면, 노드 용량은 아래와 같이 계산할 수 있습니다.

Allocatable [ 애플리케이션 파드에 대한 용량 ] = 
Node Capacity [ 하나의 노드에 가용한 용량 ] - Kube-reserved [큐블릿,컨테이너 런타임 같은 쿠버네티스 데몬] 
- System-reserved [sshd, udev 같은 OS 시스템 데몬]

OS와 쿠버네티스를 관리하는 시스템 데몬 용도의 자원을 에약해 놓지 않으면 파드는 노드의 전체 용량을 사용할 때까지 스케줄링 될 수 있고, 이로 인해 파드와 시스템 데몬이 서로 자원을 사용하겠다고 경쟁하여 노드에 자원 부족 문제를 발생 시킬 수 있습니다. 또한 쿠버네티스에 의해 관리되지 않는 컨테이너가 노드에서 실행 중이라도, 쿠버네티스에 의한 노드 용량 게산이 반영됩니다.

이런 제한에 대한 임시적 해결방법은 아무 일도 하지 않는 플레이스홀더 파드를 실행하는 것으로 이 플레이스 홀더에는 관리되지 않는 컨테이너 자원 사용량과 일치하는 CPU와 메모리에 대한 자원 요청만이 있을 뿐입니다.

이런 파드는 추적되지 않는 컨테이너의 자원 소비를 나타내거나 예약하기 위해서만 생성되고 스케줄러가 노드에 대한 더 좋은 자원 모델을 구축하는데 도움을 줍니다.

컨테이너 자원 요구

효율적인 파드 배치를 위한 중요한 요구사항은 컨테이너가 런타임 의존성과 자원 요구 정의를 갖는 것입니다. 컨테이너에 요청과 제한을 갖는 자원 프로파일과 스토리지 또는 포트 같은 환경 의존성을 선언해야합니다. 그래야만 파드가 현명하게 노드에 할당되고 피크 타임 동안 서로 영향 없이 실행될 수 있습니다.

배치 정책

올바른 필터를 가지거나 특정 애플리케이션 요구에 대해 우선순위 정책에 관한 내용입니다.

대부분의 사용 예에서는 기본 술어 세트와 기본 우선순위 정책이 설정된 세트를 갖는 스케줄러만으로도 충분합니다. 아래와 같은 내용으로 스케줄러를 실행할 때 기본 스케줄러 정책을 다른 정책으로 덮어 쓸 수도 있습니다.

{
	"kind" : "Policy",
  	"apiVersion" : "v1",
  	"predicates" : [ # 술어는 자격 없는 노드를 필터링하여 제외하는 규칙입니다.
            	{"name" : "PodFitsHostPorts"}, # 이 포트 사용이 가능한 노드에만 특정 고정된 호스트 포트를 요청하도록 스케줄링합니다.
            	{"name" : "PodFitsResources"},
            	{"name" : "NodiskConflict"},
            	{"name" : "NoVolumeZoneconflict"},
	    	{"name" : "MatchNodeSelector"},
		{"name" : "HostName"}
	],
        "priorities" : [ # 우선순위는 설정에 따라 사용 가능한 노드를 정렬하는 규칙입니다.
                {"name" : "LeastRequestPriority","weight":2}, # 요청된 자원이 적은 노드에 더 높은 우선순위를 부여합니다.
                {"name" : "BalanceResourceAllocation","weight":1},
                {"name" : "ServiceSpreadingPriority","weight":2},
                {"name" : "EqualPriority","weight":1},
    	]
}

기본 스케줄러 정책을 설정하는 것 외에도 다중 스케줄러를 띄워서 파드를 특정 스케줄러에 지정해 배치할 수 있습니다. 스케줄러에 고유한 이름을 주어서 다르게 설정된 또 다른 스케줄러를 띄울 수 있습니다. 그런 다음 파드를 정의할 때 파드 명세에 .spec.schedulerName 필드 값으로 사용자정의 스케줄러 이름을 추가하면, 파드는 사용자정의 스케줄러에 의해서 스케줄링됩니다.

좋은 웹페이지 즐겨찾기