[Kubernetes] 애플리케이션 배포를 위한 고급 설정

연수·2021년 12월 10일
0

kubernetes

목록 보기
13/15

1️⃣ 포드의 자원 사용량 제한

쿠버네티스와 같은 컨테이너 오케스트레이션 툴에서 중요한 것 중 하나는 바로 클러스터 내부에서 컴퓨팅 자원 활용륭(utilization)을 늘리는 것이다.

 

🪜 Limits와 Requests

  • Limits: 해당 포드의 컨테이너가 최대로 사용할 수 있는 자원의 상한선
  • Requests: 적어도 이 만큼의 자원은 컨테이너에게 보장돼야 한다는 것 의미
  • 오버커밋(Overcommit)
    • Requests보다 많은 자원을 사용하는 것
    • 한정된 컴퓨팅 자원을 효율적으로 사용하기 위한 방법으로, 사용할 수 있는 자원보다 더 많은 양을 가상 머신이나 컨테이너에 할당함으로써 전체 자원의 사용률을 눂이는 방법이다.
    • 오버커밋을 통해 실제 물리 자원보다 더 많은 양의 자원을 할당하는 기능을 제공한다.
  • 최소한 Requests만큼의 자원 사용이 보장되지만, 유휴 자원이 있다면 Limits만큼 사용할 수 있다.
  • 포드를 할당할 때 사용되는 자원 할당 기준은 Limits가 아닌 Requests이다.
  • 컨테이너 A가 requests보다 많은 자원을 사용하고 있는데, 컨테이너 B가 requests만큼 자원을 사용하려고 시도하면 컨테이너 A에 스로틀(throttle)이 발생한다. → 컨테이너 B가 requests만큼 자원 사용이 가능해진다.

 

🐳 메모리 자원 사용량 제한 원리

  • 쿠버네티스는 가용 메모리를 확보하기 위해 우선순위가 낮은 포드 또는 프로세스를 강제로 종료하도록 설계되어 있다.
  • (중요!) 노드에 메모리 자원이 부족해지면 어떤 포드나 프로세스가 먼저 종료되어야 하는가?!
    • Limits와 Requests 값에 따라ㅏ 내부적으로 우선순위 계산
    • 우선순위를 구분하기 위해 3가지 종류의 QoS(Quality Of Service) 클래스를 명시적으로 포드에 설정
  • 노드의 이상 상태 정보를 의미하는 Conditions에는 MemoryPressure, DiskPressure 등이 있다.
  • MemoryPressure 값이 True가 되면 가용 메모리가 부족하다는 의미로, 쿠버네티스가 해당 노드에서 실행 중이던 모든 포드에 대해 순위를 매긴 다음 가장 우선순위가 낮은 포드를 다른 노드로 퇴거(Evict)시킨다.
    • 이때 포드의 우선순위는 QoS 클래스 및 메모리 사용량에 따라 정렬되어 매겨진다.
  • MemoryPressure 상태를 감지하기 전에 급작스럽게 메모리 사용량이 많아질 경우, OOM(Out Of Memory) Killer라는 기능이 우선순위 점수가 낮은 컨테이너의 프로세스를 강제로 종료해 가능한 메모리를 확보할 수도 있다.
    • 프로세스가 메모리를 얼마나 더 많이 사용하고 있는지에 따라 프로세스의 최종 OOM 점수가 갱신된다.
    • OOM 킬러에 의해 포드 컨테이너의 프로세스가 종료되면 해당 컨테이너는 포드의 재시작 정책에 의해 다시 시작된다.

 

👑 QoS 클래스

  1. Guaranteed 클래스
    • 포드의 컨테이너에 설정된 Limits와 Requests 값이 완전히 동일할 때 부여되는 클래스
    • 자원의 오버커밋이 허용되지 않기 때문에 할당 받은 자원의 사용을 안정적으로 보장 받을 수 있다.
  2. BestEffort 클래스
    • Requests와 Limits를 아예 설정하지 않은 포드에 설정되는 클래스
    • 노드에 유휴 자원이 있다면 제한 없이 모든 자원을 사용할 수 있다.
    • 그러나 보장 받을 수 있는 자원이 존재하지 않는다.
    • 즉, 모든 자원을 사용할 수도 있지만 자원을 전혀 사용하지 못할 수도 있다.
  3. Burstable 클래스
    • Limits의 값이 Requests보다 큰 포드를 의미한다.
    • Requests에 지정된 자원만큼 사용을 보장받을 수 있지만, 상황에 따라서는 Limits까지 자원을 사용할 수도 있다.
    • 필요에 따라 자원의 한계를 확장해 사용할 수 있는 포드
    • 다른 포드와 자원 경합이 발생할 수 있는데, 이때 requests보다 더 많은 자원을 사용하고 있는 포드나 프로세스의 우선순위가 더 낮게 설정된다.

→ 포드의 우선순위는 Guaranteed → Burstable → BestEffort이다.

→ 포드가 메모리를 많이 사용할수록 우선순위가 낮아진다.

 

🌙 ResourceQuota와 LimitRange

  • 쿠버네티스를 여러 사람 또는 개발팀이 함께 사용하고 있다면 각 네임스페이스에서 할당할 수 있는 자원의 최대 한도 또는 범위를 설정할 필요가 있다.
  • 이를 위해 ResourceQuota와 LimitRange라는 오브젝트를 이용해 자원 사용량을 관리할 수 있는 기능을 제공한다.
  • ResourceQuota
    • 특정 네임스페이스에서 사용할 수 있는 자원 사용량의 합을 제한하는 쿠버네티스 오브젝트
    • 네임스페이스에서 할당할 수 있는 자원의 총합 또는 네임스페이스에서 생성할 수 있는 리소스의 개수를 제한
  • LimitRange
    • 특정 네임스페이스에서 할당되는 자원의 범위 또는 기본값을 지정할 수 있는 쿠버네티스 오브젝트
    • 포드의 컨테이너에 CPU나 메모리 할당량이 설정돼 있지 않은 경우, 컨테이너에 자동으로 기본 Requests 또는 Limits 값을 설정할 수 있다.
    • 포드 또는 컨테이너의 CPU, 메모리, 퍼시스턴트 볼륨 클레임 스토리지 크기의 최솟값/최댓값을 설정할 수 있다.
  • Admission Controller
    • 사용자의 API 요청이 적절한지 검증하고, 필요에 따라 API 요청을 변형하는 단계
    • ResourceQuota와 LimitRange는 Admission Controller의 한 종류
    • ResourceQuota와 LimitRange의 원리
      1. 사용자가 API 서버에 kubectl 명령으로 요청을 전송
      2. x509, 서비스 어카운트 등을 통해 인증 단계를 거친다.
      3. 롤, 클러스터 롤 등을 통해 인가 단계를 거친다.
      4. 어드미션 컨트롤러인 ResourceQuota는 해당 포드의 자원 할당 요청이 적절한지 검증한다.
      5. 해당 API 요청에 포함된 포드 데이터에 자원 할당이 설정되지 않은 경우 LimitRange는 포드 데이터에 CPU 및 메모리 할당의 기본값을 추가함으로써 원래의 포드 생성 API의 데이터를 변형한다.

 

2️⃣ 쿠버네티스 스케줄링

  • 컨테이너나 가상 머신과 같은 인스턴스를 새롭게 생성할 때, 그 인스턴스를 어느 서버에 생성할 것일지 결정하는 일
  • 최종적으로 포드 생성이 승인되면 쿠버네티스는 해당 포드를 워커 노드 중 한 곳에 생성하는데, 이 단계에서 스케줄링이 수행된다.
  • etcd
    • 분산 코디네이터라고 불리는 도구의 일종으로, 클라우드 플랫폼 등의 환경에서 여러 컴포넌트가 정상적으로 상호작용할 수 있도록 데이터를 조정하는 역할을 담당한다.
    • 쿠버네티스는 클러스터 운용에 필요한 정보를 분산 코디네이터인 etcd에 저장한다.
    • etcd에 저장된 포드의 데이터에는 해당 포드가 어느 워커 노드에서 실행되는지 나타내는 nodeName 항목이 존재한다.
  • 스케줄러는 nodeName이 설정되지 않은 해당 포드를 스케줄링 대상으로 판단하고, 포드를 할당할 적절한 노드를 선택한 다음 API 서버에게 해당 노드와 포드를 바인딩할 것을 요청한다.
  • 그러고 나면 포드의 nodeName 값에는 선택된 노드의 이름이 설정된다.
  • nodeName이 설정되면 해당 nodeName에 해당하는 노드의 kubelet이 컨테이너 런타임을 통해 포드를 생성한다.
  • (중요!) 스케줄러가 적절한 노드를 어떻게 선택하느냐
    • 노드 필터링: 포드를 할당할 수 있는 노드와 그렇지 않은 노드를 분리해 걸러내는 단계
    • 노드 스코어링: 쿠버네티스의 소스코드에 미리 정의된 알고리즘의 가중치에 따라서 노드의 점수를 계산

 

📅 NodeSelector와 Node Affinity, Pod Affinity

  1. NodeSelector
    • 포드의 YAML 파일에 노드의 이름을 직접 명시
  2. Node Affinity
    • 반드시 충족해야 하는 조건과 선호하는 조건을 별도로 정의할 수 있다.
    • **required**DuringSchedulingIgnoredDuringExecution
    • **preferred**DuringSchedulingIgnoredDuringExecution
  3. Pod Affinity
    • 특정 조건을 만족하는 포드와 함께 실행되도록 스케줄링한다.
  4. Pod Anti-affinity
    • 특정 포드와 같은 토폴로지의 노드를 선택하지 않는 방법

 

🎨 Taints와 Toleration

  • Taints
    • 특정 노드에 얼룩을 지정함으로써 해당 노드에 포득 ㅏ할당되는 것을 막는 기능
    • NoSchedule, PreferNoSchedule, NoExecute의 효과가 있다.
  • Toleration
    • Taints가 설정된 노드에도 포드를 할당할 수 있다.
    • tolerationSeconds 옵션을 추가할 수 있다. 특정 시간 동안 해당 Taint를 용인하겠다는 뜻이다.

 

💧 Cordon, Drain, PodDistributionBudget

  • cordon
    • 해당 명령어로 지정된 노드는 새로운 포드가 할당되지 않는다.
  • drain
    • 해당 노드에 스케줄링을 금지하며, 노드에서 기존에 실행 중이던 포드를 다른 노드로 옮겨가도록 퇴거를 수행한다.
  • PodDistributionBudget
    • drain 명령어 등으로 인해 포드에 퇴거가 발생할 때, 특정 개수 또는 비율만큼의 포드는 반드시 정상적인 상태를 유지하기 위해서 사용된다.

 

3️⃣ 쿠버네티스 애플리케이션 상태와 배포

🥐 디플로이먼트를 통해 롤링 업데이트

  • 레플리카셋의 변경 사항을 저장하는 리비전을 디플로이먼트에서 관리함으로써 애플리케이션의 배포를 쉽게 할 수 있다.
  • 쿠버네티스는 포드를 조금씩 삭제하고 생성하는 롤링 업데이트 기능을 제공한다.
  • 롤링 업데이트를 사용하면 디플로이먼트를 업데이트하는 도중에도 사용자의 요청을 처리할 수 있는 포드가 계속 존재하기 때문에 애플리케이션의 중단이 발생하지 않는다.
  • 블루 그린 배포: 기존 버전의 포드를 그대로 놔둔 상테에서 새로운 버전의 포드를 미리 생성해 둔 뒤 서비스의 라우팅만 변경하는 배포 방식. 롤링 업데이트와 달리 특정 순간에 두 버전의 애플리케이션이 공존하지 않는다.

 

🍼 포드의 생애 주기

  1. Pending: 포드를 생성하는 요청이 API 서버에 의해 승인됐지만, 어떠한 이유로 인해 아직 실제로 생성되지 않은 상태
  2. Running: 포드에 포함된 컨테이너들이 모두 생성돼 포드가 정상적으로 실행된 상태
  3. Completed: 포드가 정상적으로 실행돼 종료됨
  4. Error: 포드가 정상적으로 실행되지 않은 상태로 종료됨
  5. Terminating: 포드가 삭제 또는 퇴거되기 위해 삭제 상태에 머물러 있는 경우
  • restartPolicy: Always, Never, OnFailure로 설정 가능

 

🏃‍♀️ Running 상태가 되기 위한 조건

  • Init Container
    • 포드의 컨테이너 내부에서 애플리케이션이 실행되기 전에 초기화를 수행하는 컨테이너
  • postStart
    • 포드의 컨테이너가 실행될 때 특정 작업을 수행하도록 라이프사이클 훅을 정의할 수 있다.
    • 두 가지 방식으로 사용 가능
      • HTTP → 특정 주소로 HTTP 요청을 전송
      • Exec → 컨테이너 내부에서 특정 명령어 실행
  • 애플리케이션 상태 검사
    • livenessProbe: 컨테이너 내부의 애플리케이션이 살아있는지 검사. 검사에 실패할 경우 해당 컨테이너는 restartPolicy에 따라서 재시작된다.
    • readinessProbe: 컨테이너내부의 애플리케이션이 사용자 요청을 처리할 준비가 됐는지 검사. 검사에 실패할 경우 컨테이너는 서비스의 라우팅 대상에서 제외된다.

 

➕ HPA를 활용한 오토스케일링

  • 리소스 사용량에 따라 디플로이먼트의 포드 개수를 자동으로 조절하는 HPA(Horizontal Pod Autoscaler)라는 기능을 제공한다.

 


[출처] 시작하세요! 도커/쿠버네티스 (용찬호 지음)

profile
DCDI

0개의 댓글