본문 바로가기

Infrastructure/Kubernetes

[K8S] 모범 사례

쿠버네티스 공식문서를 확인하며 모범 사례와 관련하여 기억해야 하는 부분을 기록한다.


대형 클로스터에 대한 고려 사항

클러스터는 컨트롤 플레인에서 관리하는 쿠버네티스 에이전트를 실행하는 노드(물리 또는 가상 머신)의 집합이며 v1.25에서는 아래의 기준을 만족하는 설정을 수용하도록 설정되어 있다.

  • 노드 당 파드 110 개 이하.
  • 노드 5,000개 이하.
  • 전체 파드 150,000개 이하.
  • 전체 컨테이너 300,000개 이하.

노드를 추가하거나 제거하여 클러스터를 확장할 수 있지만 수행하는 방법은 클러스터 배포 방법에 따라 다르다.

클라우드 프로바이더 리소스 쿼터

리소스 쿼터는 여러 팀이 노드로 클러스터를 공유할 때 한 팀이 분배된 리소스보다 많은 리소스를 사용하는 것을 의미한다. 여러 노드를 가지는 클러스터를 만들 때, 클라우드 프로바이더 쿼터 이슈를 피하기 위해 고려할 점은 아래와 같다.

아래와 같은 클라우드 리소스에 대한 쿼터 증가를 요청한다.

  • 컴퓨터 인스턴스
  • CPU
  • 스토리지 볼륨
  • 사용 중인 IP 주소
  • 패킷 필터링 규칙 세트
  • 로드밸런서 개수
  • 로그 스트림

일부 클라우드 프로바이더는 새로운 인스턴스 생성 속도에 상한이 있기 때문에 클러스터 확장 작업 간 새로운 노드를 일괄적으로 배치하며 배치 작업을 위해 일시 중단한다.

컨트롤 플레인 컴포넌트

대규모 클러스터의 경우, 충분한 컴퓨트 및 기타 리소스가 있는 컨트롤 플레인이 필요하다.

일반적으로 장애 영역 당 하나 또는 두 개의 컨트롤 플레인 인스턴스를 실행하고, 해당 인스턴스를 먼저 수직(vertically) 확장한 다음 (수직) 규모로 하락하는 지점에 도달한 후 수평(horizontally)적으로 확장한다.

내결함성을 제공하려면 장애 영역 당 하나 이상의 인스턴스를 실행해야 한다. 쿠버네티스 노드는 동일한 장애 영역에 있는 컨트롤 플레인 엔드포인트로 트래픽을 자동 조정하지 않지만, 클라우드 프로바이더는 이를 수행하기 위한 자체 메커니즘을 가지고 있을 수 있다.

예를 들어, 관리형 로드 밸런서를 사용하여 장애 영역 A의 kubelet 및 파드에서 시작되는 트래픽을 전송하도록 로드 밸런서를 구성하고, 해당 트래픽을 A 영역에 있는 컨트롤 플레인 호스트로만 전달한다. 단일 컨트롤 플레인 호스트 또는 엔드포인트 장애 영역 A가 오프라인이 되면 영역 A의 노드에 대한 모든 컨트롤 플레인 트래픽이 영역간 전송되고 있음을 의미한다. 각 영역에서 여러 컨트롤 플레인 호스트를 실행하면 가용성이 낮아진다.

규모가 큰 클러스터의 성능을 향상시키기 위해, 사용자는 이벤트 오브젝트를 각각의 전용 etcd 인스턴스에 저장한다. 클러스터 생성시의 부가 스크립트이며, 클러스터 생성 시에 사용자 도구를 사용하여 아래와 같은 작업을 수행할 수 있다.

  • 추가 etcd 인스턴스 시작 및 설정
  • 이벤트를 저장하기 위한 API server 설정

애드온 리소스

애드온 리소스는 쿠버네티스의 기능을 확장한다.

쿠버네티스의 리소스 제한은 파드와 컨테이너가 다른 컴포넌트에 영향을 줄 수 있는 메모리 누수 및 기타 방식의 영향을 최소화하는 데 도움이 된다. 아래와 같은 방식의 리소스 제한은 애플리케이션 워크로드에 적용될 수 있는 것처럼 애드온 리소스에도 적용될 수 있다.

containers:
  - name: fluentd-cloud-logging
    image: fluent/fluentd-kubernetes-daemonset:v1
    resources:
      limits:
        cpu: 100m
        memory: 200Mi

애드온의 기본 제한은 일반적으로 중소형 쿠버네티스 클러스터에서 각 애드온을 실행한 경험에서 수집된 데이터를 기반으로 한다. 대규모 클러스터에서 실행할 때, 애드온은 종종 기본 제한보다 많은 리소스를 소비한다. 값을 조정하지 않고 대규모 클러스터를 배포하면, 애드온이 메모리 제한에 지속적으로 도달하면서 종료되거나 애드온이 실행될 수 있지만 CPU 시간 슬라이스 제한으로 인해 성능이 저하된다.

클러스터 애드온 리소스 문제가 발생하지 않도록, 노드가 많은 클러스터를 만들 때, 아래와 같은 사항을 고려해야 한다.

  • 일부 애드온은 수직으로 확장된다. 클러스터 또는 전체 장애 영역을 제공하는 애드온 레플리카가 하나 있는 경우 클러스터를 확장할 때 요청과 제한을 늘린다.
  • 대부분의 애드온은 수평으로 확장된다. 더 많은 파드를 실행하여 용량을 추가하지만, 매우 큰 클러스터에서는 CPU 또는 메모리 제한을 약간 높여야 할 수도 있다. VerticalPodAutoscaler는 recommender 모드에서 실행되어 요청 및 제한에 대한 제안 수치를 제공할 수 있다.
  • 일부 애드온은 데몬셋(DaemonSet)에 의해 제어되는 노드 당 하나의 복사본으로 실행된다. 예를 들어, 노드 수준의 로그 수집기가 있다. 수평 확장 애드온의 경우와 유사하게, CPU 또는 메모리 제한을 약간 높여야 할 수도 있다.

[정리]

  • 클러스터는 컨트롤 플레인을 관리하는 쿠버네티스 에이전트를 실행하는 노드의 집합이며 노드와 파드, 컨테이너는 수용 가능한 최대 값이 정해져 있다.
  • 클라우드 프로바이더는 클러스터를 확작할 때 새로운 노드를 일괄적으로 배치하며 배치 작업 중 일시 중단된다.
  • 가용 영역 당 하나 또는 두 개의 컨트롤 플레인 인스턴스를 생성한다. 해당 인스턴스를 먼저 수직 확장한 다음 수평적으로 확장한다.
  • 내결함성을 위해 가용 영역 당 하나 이상의 인스턴스를 실행해야 하며 쿠버네티스는 동일한 가용 영역내에 있는 컨트롤 플레인으로의 트래픽을 조정하지 않으며 클라우드 프로바이더에 의존해야 한다.
  • 규모가 큰 클러스터의 성능을 향상시키기 위해서 이벤트 오브젝트를 각각의 전용 etcd 인스턴스에 저장해야 한다.
  • 리소스 제한을 통해 메모리 누수와 다른 컴포넌트에 영향을 주는 것을 최소화 할 수 있다.
  • 애드온의 기본 제한 값은 주소형 쿠버네티스 클러스터에서 수집된 데이터를 기반으로 한다.
  • 대부분의 애드온은 수평으로 확장되지만 일부 애드온은 수직으로 확장된다. 수직으로 확장하는 애드온의 경우 CPU 또는 메모리 제한을 높여야 할 수 있다.

여러 영역(Zone)에서 실행

쿠버네티스는 단일 쿠버네티스 클러스터가 여러 장애 영역에서 실행될 수 있도록 설계되었다. 일반적으로 이러한 영역은 지역(region)이라는 논리적 그룹 내에 적합하다. 주요 클라우드 제공자는 지역을 일관된 기능 집합을 제공하는 장애 영역 집합(가용 영역, Available Zone, 이하 가용 영역)으로 정의한다. 지역 내에서 각 영역은 동일한 API 및 서비스를 제공한다.

일반적인 클라우드 아키텍처는 한 영역의 장애가 다른 영역의 서비스도 손상시킬 가능성을 최소화하는 것을 목표로 한다.

컨트롤 플레인 동작

컨트롤 플레인 컴포넌트는 클러스터에 관한 전반적인 스케줄링과 같은 결정을 수행한다. 또한 디플로이먼트의 replica필드에 대한 요구 조건이 충족되지 않을 경우 새로운 파드를 구동시키는 것과 같은 클러스터 이벤트를 를 감지하고 반응한다.

모든 컨트롤 플레인 컴포넌트는 컴포넌트별로 복제되는 교환 가능한 리소스 풀로 실행을 지원한다.

클러스터 컨트롤 플레인을 배포할 때, 여러 장애 영역에 컨트롤 플레인 컴포넌트의 복제본을 배치한다. 가용성이 중요한 경우, 3개 이상의 가용 영역을 선택하고 각 영역별로 컨트롤 플레인 컴포넌트(API 서버, 스케줄러, etcd, 클러스터 컨트롤러 관리자)를 3개 이상의 가용 영역에 복제한다. 클라우드 컨트롤 관리자를 실행 중인 경우 선택한 모든 장애 영역에 걸쳐 이를 복제해야 한다.

쿠버네티스는 API 서버 엔드포인트에 대한 교차 영역 복원성을 제공하지 않는다. DNS 라운드-로빈, SRV 레코드 또는 상태 확인 기능이 있는 써드파티 로드 밸런싱 솔루션을 포함하여 다양한 기술을 사용하여 클러스터 API 서버의 가용성을 향상 시킬 수 있다.

노드 동작

쿠버네티스는 클러스터의 여러 노드에 걸쳐 디플로이먼트(Deployment) 또는 스테이트풀셋(StatefulSet)과 같은 워크로드 리소스에 대한 파드를 자동으로 분배한다. 이러한 분배는 실패에 대한 영향을 줄이는 데 도움이 된다.

노드가 시작되면, 각 노드의 kubelet이 쿠버네티스의 API에서 특정 kubelet을 나타내는 노드 오브젝트에 레이블을 자동으로 추가하고 레이블에는 영역 정보가 포함될 수 있다.

클러스터가 여러 영역(Zone) 또는 지역(Region)에 걸쳐있는 경우, 파드 토폴로지 분배 제약 조건과 함께 노드 레이블을 사용하여 파드가 장애 도메인(지역, 영역, 특정 노드)간 클러스터에 분산되는 방식을 제어할 수 있다. 이러한 힌트를 통해 스케줄러는 더 나은 예상 가용성을 위해 파드를 배치할 수 있으므로, 상관 관계가 있는 오류가 전체 워크로드에 영향을 미칠 위험을 줄일 수 있다.

예를 들어, 가능할 때마다 스테이트풀셋의 3개 복제본이 모두 서로 다른 영역에서 실행되도록 제약 조건을 설정할 수 있으며 각 워크로드에 사용 중인 가용 영역을 명시적으로 정의하지 않고 선언적으로 정의할 수 있다.

쿠버네티스 코어는 사용자를 위해 노드를 생성하지 않는다. 사용자가 직접 수행하거나, 클러스터 API와 같은 도구를 사용하여 사용자 대신 노드를 관리해야 한다. 클러스터 API와 같은 도구를 사용하면 여러 장애 도메인에서 클러스터의 워커 노드로 실행할 머신 집합과 전체 영역 서비스 중단 시 자동으로 복구하는 규칙을 정의할 수 있다.

파드에 대한 수동 영역 할당

생성한 파드와 디플로이먼트, 스테이트풀셋, 잡과 같은 워크로드 리소스의 파드 템플릿에 노드 셀렉터 제약 조건을 적용할 수 있다.

영역에 대한 스토리지 접근

퍼시스턴트 볼륨이 생성되면, PersistentVolumeLabel 어드미션 컨트롤러는 특정 영역에 연결된 모든 퍼시스턴트 볼륨(PersistentVolume)에 영역 레이블을 자동으로 추가한다. 그런 다음 스케줄러는 NoVolumeZoneConflict 프레디케이트를 통해 주어진 퍼시스턴트 볼륨을 요구하는 파드가 해당 볼륨과 동일한 영역에만 배치되도록 한다.

해당 클래스의 스토리지가 사용할 수 있는 장애 도메인을 지정하는 퍼시스턴트볼륨클레임(PersistentVolumeClaims)에 대한 스토리지클래스(StorageClass)를 지정할 수 있다.

[정리]

  • 컨트롤 플레인은 파드를 관리하는 핵심 두뇌.
  • 고가용성을 유지하기 위해서는 모든 가용 영역에 컨트롤 플레인 컴포넌트를 설치하여 운영.
  • 쿠버네티스의 기본 기능으로는 교차 영역 복원성을 제공하지 않으므로 써드파티 로드 밸런싱 솔루션을 사용.
  • 쿠버네티스는 파드를 자동으로 분배하여 실패를 줄이는 데 도움을 준다.
  • 특정 kubelet을 나타내는 노드 오브젝트의 레이블에 영역 정보가 포함될 수 있다.
  • 클러스터가 여러 지역에 분산되어 있더라도 쿠버네티스는 고가용성을 위해 파드를 배치하면서 전체 워크로드에 영향을 미칠 위험을 줄여준다.
  • 쿠버네티스 코어는 사용자를 위해 노드를 생성하지 않으며 클러스터 API와 같은 도구를 사용해서 사용자를 대신해 노드를 관리하도록 해야 한다.
  • 어드미션 컨트롤러는 특정 영역에 연결된 퍼시스턴트 볼륨에는 영역 정보를 포함하는 레이블이 자동으로 추가되고 해당 퍼시스턴트 볼륨을 요구하는 파드가 해당 볼륨과 동일한 영역에 배치되도록 한다.

노드 적합성 테스트

노드 적합성 테스트는 노드의 시스템 검증과 기능 테스트를 제공하기 위해 컨테이너화된 테스트 프레임워크다. 테스트는 노드가 쿠버네티스를 위한 최소 요구조건을 만족하는지 검증하고 테스트를 통과한 노드만 클러스터에 참여할 자격이 주어진다.

노드 필수 구성 요소

노드 적합성 테스트를 실행하기 위해, 해당 노드는 표준 쿠버네티스 노드로서 동일한 전제 조건을 만족해야 하며 최소한 아래의 데몬들이 설치되어야 한다.

  • 컨테이너 런타임(Docker)
  • Kubelet

노드 적합성 테스트는 노드 e2e 테스트를 컨테이너화한 버전이며 기본적으로, 모든 적합성 테스트를 실행한다.

이론적으로, 컨테이너와 필요한 볼륨을 적절히 설정했다면 어떤 노드 e2e 테스트도 수행할 수 있다. 하지만, 적합성 테스트가 아닌 테스트들은 훨씬 복잡한 설정이 필요하기 때문에 공식문서에서는 적합성 테스트만 실행하는 것을 강하게 추천한다.

[정리]

  • 노드 적합성 테스트는 기본 제공기능이 아니며 추가로 관리해야 하는 프레임워크다.
  • 노드는 컨테이너 런타임(Docker)Kubelet이 필수로 설치되어야 한다.
  • 노드 적합성 테스트는 노드 e2e 테스트의 모든 기능을 제공하지만 공식문서에서는 적합성 테스트만 실행할 것을 강력하게 추천한다.

PKI 인증서 및 요구 사항

쿠버네티스는 TLS를 통한 인증을 위해서 PKI 인증서가 필요하다. 만약 kubeadm으로 쿠버네티스를 설치한다면, 클러스터에 필요한 인증서는 자동으로 생성된다. 개인 키를 API 서버에 저장하지 않기 때문에 인증서를 더 안전하게 보관할 수 있다.

클러스터에서 인증서가 이용되는 방식

쿠버네티스는 아래와 같은 작업에서 PKI를 필요로 한다.

  • kubelet에서 API 서버 인증서를 인증시 사용하는 클라이언트 인증서
  • API 서버가 kubelet과 통신하기 위한 kubelet 서버 인증서
  • API 서버 엔드포인트를 위한 서버 인증서
  • API 서버에 클러스터 관리자 인증을 위한 클라이언트 인증서
  • API 서버에서 kubelet과 통신을 위한 클라이언트 인증서
  • API 서버에서 etcd 간의 통신을 위한 클라이언트 인증서
  • 컨트롤러 매니저와 API 서버 간의 통신을 위한 클라이언트 인증서/kubeconfig
  • 스케줄러와 API 서버간 통신을 위한 클라이언트 인증서/kubeconfig
  • front-proxy를 위한 클라이언트와 서버 인증서

인증서 저장 위치

kubeadm으로 쿠버네티스를 설치하는 경우, 대부분 인증서는 /etc/kubernetes/pki에 저장되고 사용자 어카운트 인증서의 경우만 /etc/kubernetes에 저장된다.

인증서 수동 설정

필요한 인증서를 kubeadm으로 생성하기 싫다면, 단일 루트 CA를 이용하거나 모든 인증서를 제공하여 생성할 수 있다.

단일 루트 CA

관리자에 의해 제어되는 단일 루트 CA를 만들 수 있다. 이 루트 CA는 여러 중간 CA를 생성할 수 있고, 모든 추가 생성에 관해서도 쿠버네티스 자체에 위임할 수 있다.

[정리]

  • 쿠버네티스는 TLS를 통한 인증을 위해 PKI 인증서가 필요하다.
  • 쿠버네티스는 개인 키를 API 서버에 저장하지 않기 때문에 인증서를 안전하게 보관할 수 있다.
  • 쿠버네티스에 의해 생성된 인증서를 사용하지 않고 직접 인증서를 설정할 수 있다.

파드 시큐리티 스탠다드 강제하기

내장된 파드 시큐리티 어드미션 컨트롤러 사용

파드 시큐리티 어드미션 컨트롤러(Pod Security Admission Controller)는 더 이상 사용되지 않는 파드시큐리티폴리시(PodSecurityPolicy)를 대체한다.

모든 클러스터 네임스페이스 구성

구성이 전혀 없는 네임스페이스는 클러스터 시큐리티 모델에서 심각한 틈으로 간주해야 한다. 시간을 들여 각 네임스페이스에서 발생하는 워크로드 유형을 분석하고, 파드 시큐리티 폴리시를 참조하여 각각에 적합한 수준을 결정하는 것이 권장되며 레이블이 없는 네임스페이스는 평가되지 않았음을 표기해야 한다.

최소 권한 원칙 수용

이상적인 경우 모든 네임스페이스의 모든 파드가 제한된 정책의 요구 사항을 충족할 것이다. 그러나 일부 워크로드는 정당한 이유로 승격된 권한(elevated privilege)이 필요하므로 이는 불가능하거나 실용적이지 않다.

  • 권한 있는(privileged) 워크로드를 허용하는 네임스페이스는 적절한 액세스 제어를 설정하고 시행해야 한다.
  • 허용되는 네임스페이스에서 실행되는 경우, 고유한 보안 요구 사항에 대한 문서를 유지 관리한다. 가능하다면 이러한 요구 사항을 어떻게 더 제한할 수 있는지 고려해야 한다.

다중 모드(multi-mode) 전략 채택

파드 시큐리티 스탠다드 어드미션 컨트롤러의 감사(audit)경고(warn) 모드를 사용하면 기존 워크로드를 중단하지 않고 파드에 대한 중요한 보안 현황을 쉽게 이해할 수 있다.

이러한 모드들을 모든 네임스페이스에 강제(enforce) 하려는 원하는 수준 및 버전으로 설정하는 것이 좋다. 이 단계에서 생성된 경고 및 감사 어노테이션은 해당 상태로 안내할 수 있다. 워크로드 작성자가 원하는 수준에 맞게 변경을 수행할 것으로 예상되는 경우 경고 모드를 활성화한다. 감사 로그를 사용하여 원하는 수준에 맞게 변경 사항을 모니터링/구동하려는 경우 감사 모드를 활성화한다.

강제 모드를 원하는 값으로 설정한 경우 이러한 모드는 몇가지 다른 방식으로도 유용할 수 있다.

  • 경고강제와 같은 수준으로 설정하면 클라이언트가 유효성 검사를 통과하지 못한 파드(또는 파드 템플릿이 있는 리소스)를 만들려고 할 때 경고를 받게 된다. 이렇게 하면 규정을 준수하도록 해당 리소스를 업데이트 하는 데 도움이 된다.
  • 강제를 최신이 아닌 특정 버전에 고정하는 네임스페이스에서는 감사경고 모드가 강제와 동일한 수준으로 설정되지만, 최신 버전으로 고정하면 설정 정보를 볼 수 있다. 이는 이전 버전에서는 허용되지만 현재 모범 사례에서는 허용되지 않는다.

Third-Party

내장 솔루션인 파드 시큐리티 어드미션 컨트롤러의 대안으로 Third-Party 프로젝트가 개발되고 있으며 사용자의 상황에 맞게 선택하여 사용해야 한다. 솔루션을 평가할 때는 공급 업체가 실뢰할 수 있는 업체인지 검토해야 한다.

  • Kubewarden
  • Kyverno
  • OPA Gatekeeper

[정리]

  • 파드시큐리티폴리시(PodSecuirtyPolicy)는 더 이상 사용되지 않는다.
  • 구성이 없는 네임스페이스는 클러스터 시큐리티 모델에서 구멍으로 볼 수 있기 때문에 레이블에 평가되지 않은 네임스페이스임을 명시해야 한다.
  • 모든 네임스페이스의 모든 파드가 제한된 정책의 요구 사항을 충족하는 것이 이상적이다.
  • 허용된 네임스페이스에서 실행되는 경우 보안 요구 사항 문서를 관리해야 하며 최대한 접근을 제한할 수 있는 방법에 대해서 고려해야 한다.
  • 파드 시큐리티 스탠다드 어드미션 컨트롤러를 통해 워크로드 중단없이 파드에 대한 중요한 보안 현황을 이해할 수 있다.
  • 감사 및 경고 모드를 모든 네임스페이스에 강제하려는 수준으로 설정하는 것이 좋다.

참고 자료

'Infrastructure > Kubernetes' 카테고리의 다른 글

[클러스터 아키텍처] 노드  (0) 2022.10.13
[K8S] 오브젝트 - 2  (0) 2022.10.12
[K8S] 오브젝트 - 1  (0) 2022.10.12
[K8S] 쿠버네티스란  (0) 2022.10.12
[K8S] 컨테이너 런타임  (0) 2022.10.12