리꾸므

[ 책 : 쿠버네티스 패턴 ] 기본 패턴 - 예측 범위 내의 요구사항 본문

발걸음/일지

[ 책 : 쿠버네티스 패턴 ] 기본 패턴 - 예측 범위 내의 요구사항

리꾸므 2024. 1. 29. 21:01

 기본 패턴은 컨테이너화된 어플리케이션이 우수한 클라우드 네이티브 일원이 되기 위해 준수해야하는 원칙을 나타냅니다.

어플리케이션 특성 및 직면하게 될 제약조건에 관계없이 이러한 지침을 따르는 것을 목표로 해야합니다.

이러한 원칙을 준수함으로써 어플리케이션은 쿠버네티스 상의 자동화에 적합하게 됩니다.

 

예측 범위 내의 요구사항

클라우드 네이티브에 친화적인 일원이 되기 위해 컨테이너화된 애플리케이션이 준수해야하는 여러 가지 기본 원칙

예측 범위 내의 요구사항(Predictable Demands)패턴이란 하드 런타임 의존성이나 자원 요구사항과는 상관없이 애플리케이션 요구사항을 선언하는 방법에 관한 것입니다.

요구사항 선언은 쿠버네티스가 클러스터 내에서 애플리케이션에 적합한 노드를 찾기위해서 반드시 필요합니다.

 

 

문제

컨테이너 최적의 기능을 수행하는 데 필요한 자원량은 예측하기가 어렵습니다.

개발자가 테스트를 수행한 후에야 비로소 서비스 구현을 위한 자원 필요량을 알 수 있습니다.

고정된 CPU값 또는 메모리가 필요한 서비스도 있고, 스파이크치는 서비스도 있습니다.

서비스 데이터 저장을 위한 영구적인 스토리지가 필요하기도 합니다.

모든 애플리케이션 특성을 정의하고 이를 관리 플랫폼으로 전달하는 것은 클라우드 네이티브 애플리케이션의 기본 전제조건이기때문에

자원 요구사항 외에도 애플리케이션 런타임은 데이터 스토리지 또는 애플리케이션 설정 같은 플랫폼 관리 기능이 필요합니다.

스케줄러가 효과적으로 역할을 수행하려면 호스트 시스템에 대한 충분한 리소스, 적절한 배치 정책, 적절하게 정의된 자원 프로파일을 포함하는 컨테이너가 필요합니다.

 


 

해결책

서비스 요구사항과 총 서비스 수에 근거해 다양한 환경에 대한 용량 계획을 세우고,

전체 클러스터에 대한 요구사항을 충족하는 비용 효율이 높은 최적의 호스트 프로파일을 만들 수 있습니다.

먼저 런타임 제약사항과 파드가 사용할 리소스를 통해서 효율적인 배치를 할 수도 있습니다.

또한 노드의 압축불가능 자원을 많이 소비하였을 때 우선 순위가 높은 파드를 남겨둘 수 있습니다.

이를 통해 애플리케이션 성능을 향상시킬 수 있으며, Down time을 줄일 수 있을 것입니다.

 

  • 런타임 의존성
  1. volumes
apiVersion: v1
kind: Pod
metadata:
 name: random-generator
spec:
 containers:
 - image: k8spatterns/random-generator:1.0
 name: random-generator
 volumeMounts:
 - mountPath: "/logs"
 name: log-volume
 volumes:
 - name: log-volume
 persistentVolumeClaim:      #1
 claimName: random-generator-log


#1: 이미 생성된 PVC에 연결하기 위한 의존성
  • 위 코드처럼 볼륨을 사용하는 컨테이너 정의 안에 명시적으로 의존성을 선언해야 합니다.
  • 스케줄러는 파드가 요청한 볼륨 종류를 판단하고 실행 위치를 결정합니다.

 

2. hostPort

  • hostPort 사용시 노드 포트에 또 다른 런타임 의존성이 생성되어 파드를 배치할 수 있는 위치가 제한됩니다.
  • 클러스터에서 각 노드에 해당 포트를 예약하고 그 포트 하나당 최대 하나의 파드만 배치되게 제한합니다.
  • 포트충돌 문제로 클러스터 노드 수만큼만 파드를 확장할 수 있습니다.

 

3. configuration

apiVersion: v1
kind: Pod
metadata:
 name: random-generator
spec:
 containers:
 - image: k8spatterns/random-generator:1.0
 name: random-generator
 env:
 - name: PATTERN
 valueFrom:
 configMapKeyRef:          #1
 name: random-generator-config
 key: pattern


#1: 컨피그맵의 의존성 생성
  • 애플리케이션 설정에는 환경 변수를 통한 설정과 파일 시스템을 통한 설정 2가지 방법이 있습니다.
  • 2가지 방법 모두 컨피그맵으로 명명된 컨테이너 런타임 의존성을 적용합니다.
  • 요청한 모든 컨피그맵이 생성되지 않으면 컨테이너는 노드에 스케줄링 될 수 있지만 시작되지 않습니다.

스토리지와 포트 번호 의존성은 파드가 스케줄링되는 위치를 제한하며, 컨피그맵과 시크릿 의존성은 파드가 시작하는 것을 막을 수도 있습니다.

이런 의존성을 갖는 컨테이너화된 애플리케이션을 설계할 때는 런타임 제약사항을 항상 고려해야합니다.

 


자원 프로파일

자원은 압축 가능 자원(compressible resource : cpu, 네트워크 대역폭처럼 제어 가능한 자원)

압축 불가능 자원(incompressible resource : 메모리처럼 제어 불가능한 자원)으로 분류됩니다.

압축가능자원을 너무 많이 소비하면 병목현상이 일어나고 압축 불가능 자원을 너무 많이 사용하면 컨테이너가 종료됩니다.

apiVersion: v1
kind: Pod
metadata:
 name: random-generator
spec:
 containers:
 - image: k8spatterns/random-generator:1.0
 name: random-generator
 resources:
 requests:       #1
 cpu: 100m
 memory: 200Mi
 limits:         #2
 memory: 200Mi


#1: CPU와 메모리에 대한 초기 자원 요청
#2: 애플리케이션이 최대로 증가할 수 있는 상한 값
  • 애플리케이션 특성과 세부 구현사항에 근거해 최소 자원량(requests), 최대 자원량(limits)을 지정해야합니다.
  • requests나 limits 혹 둘 모두를 기술하느냐에 따라 플랫폼은 다음과 같이 여러 종루의 서비스 품질을 제공합니다.
    • 최선적 파드(Best-Effort Pod) : 파드가 requests(요청)나 limits(제한)을 갖고 있지 않을 때
      이 파드는 가장 낮은 우선순위로 고려되고, 파드가 위치한 노드의 압축 불가능 자원이 전부 사용되면 없어지면 가장 먼저 죽습니다.
    • 확장 가능 파드(Burstable Pod) : 파드가 요청과 제한을 모두 가지고 있지만 값이 다릅니다.
      최소한의 자원보장을 받지만 가능한 경우 제한까지 더많은 자원을 소비하려고 합니다.
      노드가 압축 불가능 자원에 대한 압박을 받는 경우, 이 파드는 최선적 파드가 남아 있지 않다면 종료될 확률이 높습니다.
    • 보장 파드(Guaranteed) :파드 요청과 제한 수치가 동일할 때, 가장 우선순위가 높은 파드이며 최선적 파드와 확장 가능 파드보다 가장 나중에 종료됩니다.
  • 다음 규칙을 권장합니다
    • 메모리의 경우 항상 요청을 제한과 동일하게 설정
    • CPU의 경우 요청을 설정하지만 제한은 없습니다.

 


 

파드 우선순위

파드 우선순위를 사용하여 다른 파드와 비교해 상대적으로 파드의 중요성을 지정할 수 있으며 이를 통해 파드가 스케줄되는 순서에 영향을 줍니다.

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
 name: high-priority              #1
value: 1000                       #2
globalDefault: false              #3
description: This is a very high-priority Pod class
---
apiVersion: v1
kind: Pod
metadata:
 name: random-generator
 labels:
 env: random-generator
spec:
 containers:
 - image: k8spatterns/random-generator:1.0
 name: random-generator
 priorityClassName: high-priority #4


#1: 우선순위 클래스 객체명
#2: 객체의 우선순위 값
#3: true일 경우 priorityClass를 지정하지 않는 포드에 사용, 하나의 PriorityClass만 globalDefault를 true로 설정할 수 있습니다.
#4: PriorityClass 자원에서 정의된 값으로, 파드에 적용될 우선순위 클래스
  • 위 예제에선 네임스페이스가 없는 객체로 정수 값으로 우선순위를 정의하는 PriorityClass를 생성했습니다.
  • #2 값이 더 높을 수록 더 중요한 파드임을 나타냅니다.
  • 파드를 배치하기에 충분한 용량을 가진 노드가 하나도 없다면 스케줄러는 자원을 확보하고 우선순위 높은 파드를 배치하기 위해 kubelet을 통해 노드에서 실행되고 있는 우선순위가 낮은 파드를 제거합니다.
  • 중요한 워크로드 파드를 효과적으로 제어하고 낮은 우선순위 파드를 축출해 워커 노드에 공간을 확보함으로써 우선순위 높은 파드를 먼저배치합니다.
  • 파드 서비스품질(Pod QoS)와 파드 우선순위(Pod priority)기능은 직교하는 기능입니다.
    • 큐블릿은 파드를 축출하기전 서비스 품질 고려 후 파드의 우선순위를 고려합니다.
    • 스케줄러 축출 로직은 파드의 서비스 품질을 완전 무시하고 우선순위 파드의 요구를 충족하는 가장 낮은 우선순위 파드를 축출합니다.

 


 

프로젝트 자원

일부 사용자가 플랫폼의 모든 자원을 소비하지 못하게 하는 제어 장치가 있습니다.

1.리소스쿼터(ResourceQuota)

  • 네임스페이스 안에서 집계된 자원 소비를 제한하기 위한 제약조건을 제공합니다.
  • 사용시 클러스터 관리자가 컴퓨팅 자원 전체 사용량과 스토리지 전체 사용량을 제한할 수 있습니다.
  • 네임스페이스 안에서 생성된 컨피그맵, 시크릿, 파드, 서비스 같은 객체의 총 개수를 제한할 수 있습니다.

 

2.리미트레인지(LimitRange)

  • 각 자원 종류마다 최대 자원량을 설정할 수 있습니다.
  • 자원 종류에 대한 최소 및 최대 허용량과 이 자원에 대한 기본 값도 지정할 수 있습니다.
  • 오버커밋 레벨로 알려진 requests와 limits 사이의 비율을 제어할 수 있습니다.
  • 클러스터 사용자가 노드에 또 다른 컨테이너가 할당 될 수 없을 정도의 매우 큰 자원을 사용하는 컨테이너를 생성하는것을 방지할 수 있습니다.
종류 자원 최소 최대 기본 제한 기본 요청 제한/요청 비율
컨테이너 CPU 500m 2 500m 250m 4
컨테이너 메모리 250Mi 2Gi 500Mi 250Mi 4

 

 


 

용량 계획

다목적 환경에 대해 용량을 계획하는 것은 그리 쉬운일이 아닙니다. 이런 경우 환경에 맞춰 설계해야할 필요가 있습니다.

 

1. 운영클러스터가 아닌 환경

최선적(Best-Effort)와 확장가능(Burstable) 파드를 주로 사용할 수 있습니다.

 

2. 운영 환경

보장(Guaranteed)파드를 사용하고 약간의 확장가능(Burstable) 파드를 사용하면 되겠습니다.

파드 CPU요청 CPU제한 메모리요청 메모리제한 인스턴스
A 500m 500m 500Mi 500Mi 4
B 250m 500m 250Mi 1000Mi 2
C 500m 1000m 1000Mi 2000Mi 2
D 500m 500m 500Mi 500Mi 1
총합 4000m 5500m 5000Mi 8500Mi 9

 

 


 

정리

자원 프로파일이 식별되면 컨테이너는 성공적인 용량 계획을 위한 구성 요소가 됩니다.

초기 테스트를 수행해 각 컨테이너에 필요한 자원을 찾고 이를 향후 용량 계획 및 용량 예측의 기본정보로 사용하길 바랍니다.

또한 자원 프로파일을 스케줄링하고 관리하는 것을 돕기 위해 애플리케이션에서는 필수로 자원 선언을 염두에 두고 제공해야합니다.