Kubernetes가 Pod를 예약 할 때 컨테이너에 실제로 실행하기에 충분한 리소스가 있어야합니다. 리소스가 제한된 노드에서 대규모 애플리케이션을 예약하면 노드의 메모리 또는 CPU 리소스가 부족하여 작업이 중지 될 수 있습니다!
응용 프로그램이 필요한 것보다 더 많은 리소스를 차지할 수도 있습니다. 이는 팀이 인위적으로 지연 시간을 줄이는 데 필요한 것보다 더 많은 복제본을 회전시키고 (코드를 효율적으로 만드는 것보다 더 많은 사본을 회전시키는 것이 더 쉽습니다!) 잘못된 구성 변경으로 인해 프로그램이 종료 될 수 있습니다. 사용 가능한 CPU를 100 % 제어하고 사용합니다. 문제가 나쁜 개발자, 나쁜 코드 또는 불운으로 인한 것인지에 관계없이 중요한 것은 당신이 통제권을 가지고 있다는 것입니다.
이 Kubernetes 모범 사례 에피소드에서는 리소스 요청 및 제한을 사용하여 이러한 문제를 해결하는 방법을 살펴 보겠습니다.
요청 및 제한
요청 및 제한은 Kubernetes가 CPU 및 메모리와 같은 리소스를 제어하는 데 사용하는 메커니즘입니다. 요청은 컨테이너가 보장받는 것입니다. 컨테이너가 리소스를 요청하면 Kubernetes는 해당 리소스를 제공 할 수있는 노드에서만이를 예약합니다. 반면 제한은 컨테이너가 특정 값을 초과하지 않도록합니다. 컨테이너는 한도까지만 올라갈 수 있으며 제한됩니다.
한도는 요청보다 낮을 수 없음을 기억하는 것이 중요합니다. 이를 시도하면 Kubernetes에서 오류가 발생하고 컨테이너를 실행할 수 없습니다.
요청 및 제한은 컨테이너별로 적용됩니다. 일반적으로 Pod에는 단일 컨테이너가 포함되지만 여러 컨테이너가있는 Pod도 표시되는 것이 일반적입니다. Pod의 각 컨테이너는 고유 한 개별 제한 및 요청을 갖지만 Pod는 항상 그룹으로 예약되므로 각 컨테이너에 대한 제한과 요청을 함께 추가하여 Pod의 집계 값을 가져와야합니다.
컨테이너가 가질 수있는 요청과 제한을 제어하기 위해 컨테이너 수준과 네임 스페이스 수준에서 할당량을 설정할 수 있습니다. 네임 스페이스에 대해 자세히 알아 보려면 블로그 시리즈의 이전 기사 를 참조하십시오 !
이것이 어떻게 작동하는지 봅시다.
컨테이너 설정
리소스에는 CPU와 메모리의 두 가지 유형이 있습니다. Kubernetes 스케줄러는이를 사용하여 포드를 실행할 위치를 파악합니다.
Google Kubernetes Engine (GKE) 에서 실행중인 경우 기본 네임 스페이스에는 이미 일부 요청과 제한이 설정되어 있습니다.
이러한 기본 설정은 "Hello World"에 적합하지만 앱에 맞게 변경하는 것이 중요합니다.
리소스에 대한 일반적인 Pod 사양은 다음과 같습니다. 이 포드에는 두 개의 컨테이너가 있습니다.
Pod의 각 컨테이너는 자체 요청 및 제한을 설정할 수 있으며 모두 가산 적입니다. 따라서 위의 예에서 포드에는 총 500mCPU 요청과 128MiB 메모리, 총 1 CPU 및 256MiB 메모리 제한이 있습니다.
CPU
CPU 리소스는 밀리 코르 단위로 정의됩니다. 컨테이너를 실행하는 데 2 개의 전체 코어가 필요한 경우 "2000m"값을 입력합니다. 컨테이너에 ¼ 코어 만 필요한 경우 "250m"값을 입력합니다.
CPU 요청에 대해 명심해야 할 한 가지는 가장 큰 노드의 코어 수보다 큰 값을 입력하면 포드가 예약되지 않는다는 것입니다. 4 개의 코어가 필요한 포드가 있지만 Kubernetes 클러스터가 듀얼 코어 VM으로 구성되어 있다고 가정 해 보겠습니다. 포드는 예약되지 않습니다.
앱이 다중 코어 (과학 컴퓨팅 및 일부 데이터베이스가 떠오르는 경우)를 활용하도록 특별히 설계되지 않은 경우 일반적으로 CPU 요청을 '1'이하로 유지하고 더 많은 복제본을 실행하여 확장하는 것이 좋습니다. 이것은 시스템에 더 많은 유연성과 신뢰성을 제공합니다.
흥미로운 것은 CPU 제한에 관한 것입니다. CPU는 "압축 가능한"리소스로 간주됩니다. 앱이 CPU 제한에 도달하기 시작하면 Kubernetes가 컨테이너 조절을 시작합니다. 즉, CPU가 인위적으로 제한되어 앱 성능이 저하 될 수 있습니다! 그러나 종료되거나 제거되지는 않습니다. 활성 상태 확인 을 사용하여 성능이 영향을받지 않았는지 확인할 수 있습니다 .
Memory
메모리 리소스는 바이트 단위로 정의됩니다. 일반적으로 메모리에 메비 바이트 값 (기본적으로 메가 바이트와 동일)을 제공하지만 바이트에서 페타 바이트까지 무엇이든 제공 할 수 있습니다 .
CPU와 마찬가지로 노드의 메모리 양보다 큰 메모리 요청을 넣으면 포드가 예약되지 않습니다.
CPU 리소스와 달리 메모리는 압축 할 수 없습니다. 메모리 사용량을 조절할 수있는 방법이 없기 때문에 컨테이너가 메모리 제한을 초과하면 종료됩니다. 팟 (Pod)이 Deployment , StatefulSet , DaemonSet 또는 다른 유형의 컨트롤러에서 관리되는 경우 컨트롤러가 교체를 시작합니다.
Nodes
노드에서 제공하는 리소스보다 큰 요청은 설정할 수 없다는 점을 기억하는 것이 중요합니다. 예를 들어 듀얼 코어 머신 클러스터가있는 경우 2.5 코어 요청이있는 포드는 예약되지 않습니다. 여기 에서 Kubernetes Engine VM의 총 리소스를 찾을 수 있습니다 .
네임 스페이스 설정
이상적인 세상에서 Kubernetes의 컨테이너 설정은 모든 것을 처리하기에 충분하지만 세상은 어둡고 끔찍한 곳입니다. 사람들은 리소스를 설정하는 것을 쉽게 잊거나 불량 팀이 요청과 제한을 매우 높게 설정하고 클러스터에서 공정한 점유율보다 더 많은 것을 차지할 수 있습니다.
이러한 시나리오를 방지하기 위해 네임 스페이스 수준에서 ResourceQuotas 및 LimitRanges를 설정할 수 있습니다.
ResourceQuotas
네임 스페이스를 만든 후 ResourceQuotas를 사용하여 잠글 수 있습니다. ResourceQuotas는 매우 강력하지만이를 사용하여 CPU 및 메모리 리소스 사용을 제한하는 방법을 살펴 보겠습니다.
리소스 할당량은 다음과 같습니다.
이 예를 보면 네 개의 섹션이 있음을 알 수 있습니다. 이러한 각 섹션 구성은 선택 사항입니다.
구성 | 내용 |
---|---|
requests.cpu | 네임 스페이스의 모든 컨테이너에 대한 최대 결합 CPU 요청 (밀리 코르)입니다. 위의 예에서는 요청이 10m 인 컨테이너 50 개, 요청이 100m 인 컨테이너 5 개 또는 요청이 500m 인 컨테이너 하나를 가질 수 있습니다. 네임 스페이스에서 요청 된 총 CPU가 500m 미만인 한! |
requests.memory | 네임 스페이스의 모든 컨테이너에 대해 결합 된 최대 메모리 요청입니다. 위의 예에서 2MiB 요청이있는 컨테이너 50 개, CPU 요청이 20MiB 인 컨테이너 5 개 또는 100MiB 요청이있는 단일 컨테이너를 가질 수 있습니다. 네임 스페이스에서 요청 된 총 메모리가 100MiB 미만인 한! |
limits.cpu | 네임 스페이스의 모든 컨테이너에 대해 결합 된 최대 CPU 제한입니다. requests.cpu와 비슷하지만 제한이 있습니다. |
limits.memory | 네임 스페이스의 모든 컨테이너에 대한 최대 결합 메모리 제한입니다. requests.memory와 비슷하지만 한계가 있습니다. 프로덕션 및 개발 네임 스페이스를 사용하는 경우 (팀 또는 서비스 당 네임 스페이스와 달리) 일반적인 패턴은 프로덕션 네임 스페이스에 할당량을 지정하지 않고 개발 네임 스페이스에 엄격한 할당량을 지정하는 것입니다. 이를 통해 트래픽이 급증하는 경우 프로덕션에서 필요한 모든 리소스를 사용할 수 있습니다. |
LimitRange | 네임 스페이스에 LimitRange를 만들 수도 있습니다. 네임 스페이스 전체를 보는 Quota와 달리 LimitRange는 개별 컨테이너에 적용됩니다. 이렇게하면 사람들이 네임 스페이스 내부에 초소형 또는 초대형 컨테이너를 만드는 것을 방지 할 수 있습니다. |
LimitRange는 다음과 같습니다.
이 예를 보면 네 개의 섹션이 있음을 알 수 있습니다. 다시 말하지만, 이러한 각 섹션을 설정하는 것은 선택 사항입니다.
Section | 내용 |
---|---|
Default | 기본 설정 한계 포드의 컨테이너를. limitRange에서 이러한 값을 설정하면 이러한 값을 명시 적으로 설정하지 않은 모든 컨테이너에 기본값이 할당됩니다. |
defaultRequest | 기본 설정 요청 포드의 컨테이너를. limitRange에서 이러한 값을 설정하면 이러한 값을 명시 적으로 설정하지 않은 모든 컨테이너에 기본값이 할당됩니다. |
max | 셋업 할 최대 한계 포드에서 컨테이너가 설정할 수 있습니다. 기본 섹션은이 값보다 클 수 없습니다. 마찬가지로 컨테이너에 설정된 제한은이 값보다 클 수 없습니다. 이 값이 설정되고 기본 섹션이 설정되지 않은 경우 이러한 값을 명시 적으로 설정하지 않은 컨테이너에는 최대 값이 제한으로 할당된다는 점에 유의해야합니다. |
min | 위로 설정 최소 요청 포드 용기가 설정할 수있다. defaultRequest 섹션은이 값보다 낮을 수 없습니다. 마찬가지로 컨테이너에 설정된 요청도이 값보다 낮을 수 없습니다. 이 값이 설정되고 defaultRequest 섹션이 설정되지 않은 경우 min 값도 defaultRequest 값이됩니다. |
Kubernetes 포드의 수명주기
하루가 끝나면 이러한 리소스 요청은 Kubernetes 스케줄러에서 워크로드를 실행하는 데 사용됩니다. 컨테이너를 올바르게 튜닝하려면 이것이 어떻게 작동하는지 이해하는 것이 중요합니다.
클러스터에서 포드를 실행하려고한다고 가정 해 보겠습니다. 포드 사양이 유효하다고 가정하면 Kubernetes 스케줄러는 라운드 로빈 부하 분산을 사용하여 워크로드를 실행할 노드를 선택합니다.
참고 : 예외는 nodeSelector 또는 유사한 메커니즘을 사용하여 Kubernetes가 특정 위치에서 Pod를 예약하도록하는 경우입니다. nodeSelector를 사용할 때 리소스 검사가 계속 발생하지만 Kubernetes는 필수 레이블이있는 노드 만 검사합니다.
그런 다음 Kubernetes는 노드에 Pod의 컨테이너에서 리소스 요청을 수행하기에 충분한 리소스가 있는지 확인합니다. 그렇지 않은 경우 다음 노드로 이동합니다.
시스템의 어떤 노드에도 요청을 채울 리소스가 남아 있지 않으면 Pod는 '보류 중'상태가됩니다. Node Autoscaler 와 같은 GKE 기능 을 사용 하면 Kubernetes Engine이이 상태를 자동으로 감지하고 더 많은 노드를 자동으로 만들 수 있습니다. 초과 용량이있는 경우 자동 확장 처리는 비용을 절약하기 위해 노드를 축소하고 제거 할 수도 있습니다!
하지만 한계는 어떻습니까? 아시다시피 한도는 요청보다 높을 수 있습니다. 모든 컨테이너 제한의 합이 실제로 머신에서 사용 가능한 리소스보다 높은 노드가있는 경우 어떻게해야합니까?
이 시점에서 Kubernetes는 " 과도하게 커밋 된 상태 "라고합니다 . 여기서 흥미로운 점이 있습니다. CPU를 압축 할 수 있기 때문에 Kubernetes는 컨테이너가 요청한 CPU를 확보하고 나머지는 제한합니다. 메모리는 압축 할 수 없으므로 Kubernetes는 노드에 메모리가 부족할 경우 종료 할 컨테이너를 결정하기 시작해야합니다.
메모리가 부족한 머신이있는 시나리오를 상상해 봅시다. Kubernetes는 무엇을할까요?
참고 : 다음은 Kubernetes 1.9 이상에 해당됩니다. 이전 버전에서는 약간 다른 프로세스를 사용합니다. 자세한 설명은이 문서를 참조하십시오.
Kubernetes는 요청한 것보다 더 많은 리소스를 사용하는 Pod를 찾습니다. Pod의 컨테이너에 요청이없는 경우 기본적으로 요청한 것보다 더 많이 사용하므로 종료 할 수있는 주요 후보입니다. 다른 주요 후보는 요청을 통과했지만 여전히 한계에 미치지 못하는 컨테이너입니다.
Kubernetes가 요청을 통과 한 여러 포드를 찾으면 포드의 우선 순위 에 따라 순위를 매기고 우선 순위 가 가장 낮은 포드를 먼저 종료합니다. 모든 포드의 우선 순위가 동일한 경우 Kubernetes는 요청보다 가장 많은 포드를 종료합니다.
매우 드문 시나리오에서 Kubernetes는 요청 내에있는 포드를 강제로 종료 할 수 있습니다. 이는 kubelet 또는 docker와 같은 중요한 시스템 구성 요소가 예약 된 것보다 더 많은 리소스를 사용하기 시작할 때 발생할 수 있습니다.
결론
리소스 요청 및 제한을 설정하지 않고도 Kubernetes 클러스터가 제대로 작동 할 수 있지만 팀과 프로젝트가 성장함에 따라 안정성 문제가 발생하기 시작합니다. Pod 및 네임 스페이스에 요청 및 제한을 추가하는 것은 약간의 추가 노력 만 필요하며, 많은 골칫거리에 빠지지 않도록 할 수 있습니다!