멀티 테넌시
멀티 테넌시 (Multi-tenancy)
이 페이지는 클러스터 멀티 테넌시(multi-tenancy)에 대한 사용 가능한 구성 옵션과 모범 사례에 대한 개요를 제공해요.
클러스터를 공유하면 비용을 절약하고 관리를 단순화할 수 있어요. 하지만 클러스터 공유는 보안, 공정성, 시끄러운 이웃(noisy neighbors) 관리 같은 과제를 제시하기도 해요.
클러스터는 여러 방식으로 공유될 수 있어요. 어떤 경우에는 서로 다른 애플리케이션이 같은 클러스터에서 실행될 수 있어요. 다른 경우에는 같은 애플리케이션의 여러 인스턴스가 엔드 유저 한 명마다 하나씩 같은 클러스터에서 실행될 수 있어요. 이런 모든 공유 유형은 흔히 멀티 테넌시 라는 포괄적인 용어로 설명돼요.
쿠버네티스는 엔드 유저나 테넌트에 대한 일급(first-class) 개념을 갖고 있지는 않지만, 다양한 테넌시 요구 사항을 관리하는 데 도움이 되는 여러 기능을 제공해요. 이에 대해서는 아래에서 다룰 거예요.
출처: 문서
본문
사용 사례 (Use cases)
클러스터를 어떻게 공유할지 결정하는 첫 단계는 사용 사례를 이해하는 거예요. 그래야 사용 가능한 패턴과 도구를 평가할 수 있으니까요. 일반적으로 쿠버네티스 클러스터의 멀티 테넌시는 두 가지 광범위한 범주로 나뉘지만, 많은 변형과 하이브리드도 가능해요.
여러 팀 (Multiple teams)
멀티 테넌시의 흔한 형태는 조직 내 여러 팀 간에 클러스터를 공유하는 것으로, 각 팀은 하나 이상의 워크로드를 운영할 수 있어요. 이런 워크로드는 서로 통신해야 하는 경우가 많으며, 같은 클러스터나 다른 클러스터에 있는 다른 워크로드와도 통신해야 해요.
이 시나리오에서 팀 구성원은 kubectl 같은 도구를 통해 쿠버네티스 리소스에 직접 접근하거나, GitOps 컨트롤러나 다른 유형의 릴리스 자동화 도구를 통해 간접적으로 접근하는 경우가 많아요. 서로 다른 팀의 구성원 사이에는 어느 정도 신뢰가 있는 경우가 많지만, RBAC, 쿼터, 네트워크 정책 같은 쿠버네티스 정책은 클러스터를 안전하고 공정하게 공유하는 데 필수적이에요.
여러 고객 (Multiple customers)
멀티 테넌시의 또 다른 주요 형태는 Software-as-a-Service(SaaS) 벤더가 고객을 위해 워크로드의 여러 인스턴스를 실행하는 경우가 많아요. 이 비즈니스 모델은 이 배포 스타일과 강하게 연관되어 있어 많은 사람들이 이를 "SaaS 테넌시" 라고 불러요. 하지만 "멀티 고객 테넌시" 라는 용어가 더 나을 수도 있어요. SaaS 벤더가 다른 배포 모델을 사용할 수도 있고 이 배포 모델이 SaaS 외부에서도 사용될 수 있기 때문이에요.
이 시나리오에서 고객은 클러스터에 접근할 수 없어요. 쿠버네티스는 그들의 관점에서는 보이지 않고 벤더가 워크로드를 관리하는 데만 사용돼요. 비용 최적화는 종종 중요한 관심사이며, 워크로드가 서로 강하게 격리되도록 보장하기 위해 쿠버네티스 정책이 사용돼요.
용어 (Terminology)
테넌트 (Tenants)
쿠버네티스의 멀티 테넌시를 논할 때 "테넌트" 에 대한 단일 정의는 없어요. 오히려 테넌트의 정의는 멀티 팀 테넌시인지 멀티 고객 테넌시인지를 논하는지에 따라 달라질 거예요.
멀티 팀 사용에서 테넌트는 일반적으로 팀이며, 각 팀은 보통 서비스의 복잡성에 따라 확장되는 소수의 워크로드를 배포해요. 하지만 "팀" 의 정의 자체도 모호할 수 있는데, 팀이 더 높은 수준의 부서로 조직되거나 더 작은 팀으로 세분될 수 있기 때문이에요.
대조적으로 각 팀이 새 고객마다 전용 워크로드를 배포한다면 그들은 멀티 고객 테넌시 모델을 사용하는 거예요. 이 경우 "테넌트" 는 단순히 단일 워크로드를 공유하는 사용자 그룹이에요. 이는 회사 전체만큼 클 수도 있고 회사의 단일 팀만큼 작을 수도 있어요.
많은 경우 같은 조직이 다른 맥락에서 "테넌트" 의 두 정의를 모두 사용할 수 있어요. 예를 들어 플랫폼 팀이 보안 도구와 데이터베이스 같은 공유 서비스를 여러 내부 "고객" 에게 제공하고, SaaS 벤더가 개발 클러스터를 공유하는 여러 팀을 가질 수도 있어요. 마지막으로 하이브리드 아키텍처도 가능한데, 예를 들어 SaaS 제공자가 민감한 데이터용 고객별 워크로드와 멀티 테넌트 공유 서비스를 결합해 사용하는 경우예요.
격리 (Isolation)
쿠버네티스로 멀티 테넌트 솔루션을 설계하고 구축하는 방법은 여러 가지가 있어요. 각 방법은 격리 수준, 구현 노력, 운영 복잡성, 서비스 비용에 영향을 주는 자체적인 트레이드오프 집합을 갖고 있어요.
쿠버네티스 클러스터는 쿠버네티스 소프트웨어를 실행하는 컨트롤 플레인과 테넌트 워크로드가 파드로 실행되는 워커 노드로 구성된 데이터 플레인으로 구성돼요. 테넌트 격리는 조직 요구 사항에 따라 컨트롤 플레인과 데이터 플레인 모두에 적용될 수 있어요.
제공되는 격리 수준은 때로 "하드(hard)" 멀티 테넌시(강한 격리를 의미)와 "소프트(soft)" 멀티 테넌시(더 약한 격리를 의미) 같은 용어로 설명돼요. 특히 "하드" 멀티 테넌시는 종종 테넌트가 서로 신뢰하지 않는 경우를 설명하는 데 사용돼요. 흔히 보안과 리소스 공유 관점에서요(예: 데이터 유출이나 DoS 같은 공격 방어). 데이터 플레인은 일반적으로 훨씬 더 큰 공격 표면을 가지므로 "하드" 멀티 테넌시는 종종 데이터 플레인 격리에 추가 주의가 필요하지만, 컨트롤 플레인 격리도 여전히 중요해요.
하지만 "하드" 와 "소프트" 용어는 모든 사용자에게 적용되는 단일 정의가 없기 때문에 혼란스러울 수 있어요. 오히려 "경도" 나 "연도" 는 광범위한 스펙트럼으로 이해하는 것이 더 좋으며, 요구 사항에 따라 클러스터에서 다양한 유형의 격리를 유지하는 데 사용할 수 있는 많은 다른 기법이 있어요.
더 극단적인 경우에는 클러스터 수준 공유를 완전히 포기하고 각 테넌트에게 전용 클러스터를 할당하는 것이 더 쉽거나 필요할 수도 있어요. VM이 적절한 보안 경계로 간주되지 않는다면 전용 하드웨어에서 실행할 수도 있어요. 이것은 클러스터 생성·운영의 오버헤드를 어느 정도 클라우드 제공자가 대신하는 관리형 쿠버네티스 클러스터에서 더 쉬울 수 있어요. 더 강한 테넌트 격리의 이점은 여러 클러스터를 관리하는 비용과 복잡성에 대해 평가되어야 해요. Multi-cluster SIG 가 이런 유형의 사용 사례를 담당해요.
이 페이지의 나머지는 공유 쿠버네티스 클러스터에 사용되는 격리 기법에 초점을 맞출 거예요. 하지만 전용 클러스터를 고려하더라도 이 권장 사항을 검토하는 것이 가치 있을 수 있어요. 필요나 역량이 변하면 미래에 공유 클러스터로 전환할 수 있는 유연성을 주기 때문이에요.
컨트롤 플레인 격리 (Control plane isolation)
컨트롤 플레인 격리는 서로 다른 테넌트가 서로의 쿠버네티스 API 리소스에 접근하거나 영향을 줄 수 없도록 보장해요.
네임스페이스 (Namespaces)
쿠버네티스에서 Namespace 는 단일 클러스터 내에서 API 리소스 그룹을 격리하는 메커니즘을 제공해요. 이 격리는 두 가지 핵심 차원을 가져요:
멀티 테넌트 환경에서 Namespace는 테넌트의 워크로드를 논리적이고 뚜렷한 관리 단위로 분리하는 데 도움이 돼요. 실제로 모든 워크로드를 각자의 네임스페이스에 격리하는 것이 일반적인 관행이에요. 같은 테넌트가 여러 워크로드를 운영하더라도 말이에요. 이렇게 하면 각 워크로드가 자신의 정체성을 갖고 적절한 보안 정책으로 구성될 수 있음을 보장해요.
네임스페이스 격리 모델은 테넌트 워크로드를 제대로 격리하려면 여러 다른 쿠버네티스 리소스, 네트워킹 플러그인, 그리고 보안 모범 사례 준수의 구성이 필요해요. 이러한 고려 사항은 아래에서 논의돼요.
접근 제어 (Access controls)
컨트롤 플레인에 대한 가장 중요한 격리 유형은 인가(authorization)예요. 팀이나 그 워크로드가 서로의 API 리소스에 접근하거나 수정할 수 있다면, 다른 모든 유형의 정책을 변경하거나 비활성화할 수 있어서 그 정책들이 제공하는 보호를 무효화할 수 있어요. 결과적으로 각 테넌트가 필요한 네임스페이스에만 적절한 접근 권한을 갖고 그 이상은 갖지 않도록 보장하는 것이 중요해요. 이를 "최소 권한 원칙(Principle of Least Privilege)" 이라고 해요.
역할 기반 접근 제어(RBAC)는 사용자와 워크로드(서비스 어카운트) 모두에 대해 쿠버네티스 컨트롤 플레인에서 인가를 시행하는 데 흔히 사용돼요. Role 과 RoleBinding 은 네임스페이스 수준에서 애플리케이션의 접근 제어를 시행하는 데 사용되는 쿠버네티스 객체예요. 클러스터 수준 객체에 대한 접근을 인가하는 유사한 객체도 존재하지만 멀티 테넌트 클러스터에는 덜 유용해요.
멀티 팀 환경에서 RBAC는 테넌트의 접근을 적절한 네임스페이스로 제한하고, 클러스터 전체 리소스는 클러스터 관리자 같은 권한 있는 사용자만 접근하거나 수정할 수 있도록 보장하는 데 사용되어야 해요.
정책이 사용자에게 필요한 것보다 더 많은 권한을 부여하게 된다면, 이는 영향을 받는 리소스를 포함한 네임스페이스를 더 세밀한 네임스페이스로 리팩터링해야 한다는 신호일 가능성이 높아요. 네임스페이스 관리 도구는 공통 RBAC 정책을 다른 네임스페이스에 적용하면서 필요할 때 세밀한 정책을 허용함으로써 이렇게 더 세밀한 네임스페이스의 관리를 단순화할 수 있어요.
쿼터 (Quotas)
쿠버네티스 워크로드는 CPU와 메모리 같은 노드 리소스를 소비해요. 멀티 테넌트 환경에서 Resource Quotas 를 사용해 테넌트 워크로드의 리소스 사용을 관리할 수 있어요. 테넌트가 쿠버네티스 API에 접근할 수 있는 여러 팀 사용 사례에서는 리소스 쿼터를 사용해 테넌트가 만들 수 있는 API 리소스의 수(예: Pod 수, ConfigMap 수)를 제한할 수 있어요. 객체 수 제한은 공정성을 보장하고 시끄러운 이웃 문제가 컨트롤 플레인을 공유하는 다른 테넌트에 영향을 주는 것을 피하는 것을 목표로 해요.
리소스 쿼터는 네임스페이스 범위의 객체예요. 테넌트를 네임스페이스에 매핑함으로써 클러스터 관리자는 쿼터를 사용해 테넌트가 클러스터의 리소스를 독점하거나 컨트롤 플레인을 압도하지 못하도록 보장할 수 있어요. 네임스페이스 관리 도구는 쿼터 관리를 단순화해요. 또한 쿠버네티스 쿼터는 단일 네임스페이스 내에서만 적용되지만, 일부 네임스페이스 관리 도구는 네임스페이스 그룹이 쿼터를 공유할 수 있게 해서 관리자에게 내장 쿼터보다 훨씬 더 많은 유연성을 적은 노력으로 제공해요.
쿼터는 단일 테넌트가 할당된 리소스 몫보다 더 많이 소비하는 것을 방지해 "시끄러운 이웃" 문제를 최소화해요. 여기서 한 테넌트가 다른 테넌트의 워크로드 성능에 부정적인 영향을 미치는 상황을 말해요.
네임스페이스에 쿼터를 적용하면 쿠버네티스는 각 컨테이너에 대한 리소스 요청(request)과 상한(limit)도 지정하도록 요구해요. 상한은 컨테이너가 소비할 수 있는 리소스 양의 상한값이에요. 구성된 상한을 초과하는 리소스를 소비하려는 컨테이너는 리소스 유형에 따라 제한(throttle)되거나 종료(kill)될 거예요. 리소스 요청이 상한보다 낮게 설정되면 각 컨테이너는 요청된 양이 보장되지만 워크로드 간 약간의 영향 가능성은 여전히 있을 수 있어요.
쿼터는 네트워크 트래픽 같은 모든 종류의 리소스 공유를 보호할 수는 없어요. 이 문제에는 노드 격리(아래에서 설명)가 더 나은 솔루션일 수 있어요.
데이터 플레인 격리 (Data Plane Isolation)
데이터 플레인 격리는 서로 다른 테넌트의 파드와 워크로드가 충분히 격리되도록 보장해요.
네트워크 격리 (Network isolation)
기본적으로 쿠버네티스 클러스터의 모든 파드는 서로 통신할 수 있게 허용되며 모든 네트워크 트래픽은 암호화되지 않아요. 이는 트래픽이 우연히 또는 악의적으로 의도하지 않은 목적지로 전송되거나 손상된 노드의 워크로드에 의해 가로채질 수 있는 보안 취약점으로 이어질 수 있어요.
파드 간 통신은 Network Policies 를 사용해 제어할 수 있는데, 이는 네임스페이스 레이블이나 IP 주소 범위를 사용해 파드 간 통신을 제한해요. 테넌트 간 엄격한 네트워크 격리가 필요한 멀티 테넌트 환경에서는 파드 간 통신을 거부하는 기본 정책으로 시작하고, 모든 파드가 이름 해석을 위해 DNS 서버를 쿼리할 수 있게 하는 다른 규칙을 두는 것이 권장돼요. 이런 기본 정책을 갖춘 상태에서 네임스페이스 내 통신을 허용하는 더 허용적인 규칙을 추가하기 시작할 수 있어요. 네임스페이스 간 트래픽 허용이 필요한 경우에는 네트워크 정책 정의의 namespaceSelector 필드에 빈 레이블 셀렉터 {} 를 사용하지 않는 것도 권장돼요. 이 방식은 필요에 따라 더 세분화할 수 있어요. 이것은 단일 컨트롤 플레인 내의 파드에만 적용된다는 점에 유의해요. 서로 다른 가상 컨트롤 플레인에 속한 파드는 쿠버네티스 네트워킹을 통해 서로 통신할 수 없어요.
네임스페이스 관리 도구는 기본 또는 공통 네트워크 정책의 생성을 단순화할 수 있어요. 또한 이러한 도구 중 일부는 클러스터 전반에 걸쳐 일관된 네임스페이스 레이블 집합을 강제해 정책의 신뢰할 수 있는 기반이 되도록 보장할 수 있어요.
경고 (Warning):
더 고급 네트워크 격리는 네임스페이스 외에도 워크로드 정체성에 기반한 OSI 레이어 7 정책을 제공하는 서비스 메시(service mesh)에 의해 제공될 수 있어요. 이러한 더 높은 수준의 정책은 특히 여러 네임스페이스가 단일 테넌트에 전용될 때 네임스페이스 기반 멀티 테넌시를 더 쉽게 관리하게 만들 수 있어요. 또한 상호 TLS를 사용한 암호화를 제공해 손상된 노드가 있더라도 데이터를 보호하고 전용 또는 가상 클러스터에서 작동해요. 하지만 관리가 훨씬 더 복잡할 수 있고 모든 사용자에게 적합하지 않을 수 있어요.
스토리지 격리 (Storage isolation)
쿠버네티스는 워크로드용 영구 스토리지로 사용할 수 있는 여러 유형의 볼륨을 제공해요. 보안과 데이터 격리를 위해 동적 볼륨 프로비저닝 이 권장되며 노드 리소스를 사용하는 볼륨 유형은 피해야 해요.
StorageClass 는 클러스터 관리자가 결정한 서비스 품질 수준, 백업 정책 또는 커스텀 정책에 따라 클러스터가 제공하는 커스텀 "클래스" 의 스토리지를 설명할 수 있게 해줘요.
파드는 PersistentVolumeClaim 을 사용해 스토리지를 요청할 수 있어요. PersistentVolumeClaim은 네임스페이스 범위의 리소스로, 스토리지 시스템의 일부를 격리하고 공유 쿠버네티스 클러스터 내에서 테넌트에게 전용할 수 있게 해줘요. 하지만 PersistentVolume은 클러스터 전체 리소스이며 워크로드와 네임스페이스와 독립적인 수명 주기를 갖는다는 점에 유의하는 것이 중요해요.
예를 들어 각 테넌트에 대해 별도의 StorageClass를 구성하고 이를 사용해 격리를 강화할 수 있어요. StorageClass가 공유된다면 PersistentVolume이 다른 네임스페이스 간에 재사용될 수 없도록 Delete 회수 정책 을 설정해야 해요.
컨테이너 샌드박싱 (Sandboxing containers)
쿠버네티스 파드는 워커 노드에서 실행되는 하나 이상의 컨테이너로 구성돼요. 컨테이너는 OS 수준 가상화를 활용하므로 하드웨어 기반 가상화를 활용하는 가상 머신보다 더 약한 격리 경계를 제공해요.
공유 환경에서 애플리케이션과 시스템 계층의 패치되지 않은 취약점은 공격자가 컨테이너 탈출(container breakout)과 호스트 리소스에 대한 접근 권한을 부여하는 원격 코드 실행에 악용될 수 있어요. 콘텐츠 관리 시스템(CMS) 같은 일부 애플리케이션에서는 고객이 신뢰할 수 없는 스크립트나 코드를 업로드·실행할 수 있게 허용될 수 있어요. 두 경우 모두 강한 격리를 사용해 워크로드를 추가로 격리하고 보호하는 메커니즘이 바람직해요.
샌드박싱은 공유 클러스터에서 실행되는 워크로드를 격리하는 방법을 제공해요. 일반적으로 각 파드를 가상 머신이나 사용자 공간 커널 같은 별도의 실행 환경에서 실행하는 것을 포함해요. 샌드박싱은 신뢰할 수 없는 코드를 실행할 때 자주 권장되는데, 워크로드가 악의적이라고 가정되기 때문이에요. 이런 유형의 격리가 필요한 이유 중 하나는 컨테이너가 공유 커널에서 실행되는 프로세스이기 때문이에요. 컨테이너는 /sys 와 /proc 같은 파일 시스템을 기본 호스트에서 마운트하므로 자체 커널을 가진 가상 머신에서 실행되는 애플리케이션보다 덜 안전해요. seccomp, AppArmor, SELinux 같은 제어가 컨테이너의 보안을 강화하는 데 사용될 수 있지만, 공유 클러스터에서 실행되는 모든 워크로드에 보편적인 규칙 집합을 적용하기는 어려워요. 샌드박스 환경에서 워크로드를 실행하면 공격자가 취약점을 악용해 호스트 시스템과 그 호스트에서 실행되는 모든 프로세스/파일에 접근 권한을 얻는 컨테이너 탈출로부터 호스트를 보호하는 데 도움이 돼요.
가상 머신과 사용자 공간 커널은 샌드박싱의 두 가지 인기 있는 접근 방식이에요.
노드 격리 (Node Isolation)
노드 격리는 테넌트 워크로드를 서로 격리하는 데 사용할 수 있는 또 다른 기법이에요. 노드 격리를 사용하면 노드 집합이 특정 테넌트의 파드를 실행하는 데 전용되고 테넌트 파드의 혼재가 금지돼요. 이 구성은 노드에서 실행되는 모든 파드가 단일 테넌트에 속하게 되므로 시끄러운 테넌트 문제를 줄여요. 정보 공개 위험은 노드 격리로 약간 낮아지는데, 컨테이너에서 탈출하는 공격자는 해당 노드에 마운트된 컨테이너와 볼륨에만 접근할 수 있기 때문이에요.
서로 다른 테넌트의 워크로드가 다른 노드에서 실행되지만 kubelet과 (가상 컨트롤 플레인을 사용하지 않는 한) API 서버는 여전히 공유 서비스라는 점을 인지하는 것이 중요해요. 숙련된 공격자는 노드에서 실행되는 kubelet이나 다른 파드에 할당된 권한을 사용해 클러스터 내에서 측면 이동(lateral movement)하고 다른 노드에서 실행되는 테넌트 워크로드에 접근할 수 있어요. 이것이 주요 우려 사항이라면 seccomp, AppArmor, SELinux 같은 보완 제어를 구현하거나 샌드박스 컨테이너를 탐구하거나 각 테넌트에 대해 별도의 클러스터를 만드는 것을 고려해 보세요.
노드 격리는 파드가 아닌 노드당 요금을 청구할 수 있으므로 샌드박싱 컨테이너보다 청구 관점에서 추론하기가 조금 더 쉬워요. 또한 호환성과 성능 문제가 더 적고 샌드박싱 컨테이너보다 구현하기 더 쉬울 수 있어요. 예를 들어 각 테넌트의 노드는 톨러레이션(toleration)이 일치하는 파드만 실행할 수 있도록 테인트(taint)로 구성될 수 있어요. 그런 다음 변경 웹훅(mutating webhook)을 사용해 테넌트 네임스페이스에 배포된 파드에 테인트와 노드 선호도를 자동으로 추가해 해당 테넌트를 위해 지정된 특정 노드 집합에서 실행되도록 할 수 있어요.
노드 격리는 파드 노드 셀렉터 를 사용해 구현할 수 있어요.
추가 고려 사항 (Additional Considerations)
이 섹션은 멀티 테넌시와 관련된 다른 쿠버네티스 구성 요소와 패턴을 논의해요.
API 우선순위와 공정성 (API Priority and Fairness)
API 우선순위와 공정성 은 클러스터 내에서 실행되는 특정 파드에 우선순위를 할당할 수 있게 해주는 쿠버네티스 기능이에요. 애플리케이션이 쿠버네티스 API를 호출하면 API 서버는 파드에 할당된 우선순위를 평가해요. 더 높은 우선순위의 파드에서 온 호출은 더 낮은 우선순위의 호출보다 먼저 처리돼요. 경합이 심할 때 더 낮은 우선순위의 호출은 서버가 덜 바쁠 때까지 대기열에 들어가거나 요청을 거부할 수 있어요.
API 우선순위와 공정성 사용은 고객이 컨트롤러 같은 쿠버네티스 API와 인터페이스하는 애플리케이션을 실행하도록 허용하지 않는 한 SaaS 환경에서는 흔하지 않을 거예요.
서비스 품질 (Quality-of-Service, QoS)
SaaS 애플리케이션을 실행할 때 서로 다른 테넌트에게 서로 다른 서비스 품질(QoS) 등급을 제공할 수 있기를 원할 수 있어요. 예를 들어 더 적은 성능 보장과 기능이 제공되는 프리미엄(freemium) 서비스와 특정 성능 보장이 있는 유료 서비스 등급이 있을 수 있어요. 다행히 공유 클러스터 내에서 이를 달성하는 데 도움이 되는 네트워크 QoS, 스토리지 클래스, 파드 우선순위와 선점(preemption)을 포함한 여러 쿠버네티스 구성 요소가 있어요. 이 각각의 아이디어는 테넌트가 지불한 서비스 품질을 제공하는 것이에요. 먼저 네트워킹 QoS를 살펴보자.
일반적으로 노드의 모든 파드는 네트워크 인터페이스를 공유해요. 네트워크 QoS가 없으면 일부 파드가 다른 파드를 희생해서 사용 가능한 대역폭의 불공정한 몫을 소비할 수 있어요. 쿠버네티스 대역폭 플러그인 은 Linux tc 대기열을 사용해 파드에 속도 제한을 적용하기 위해 쿠버네티스 리소스 구성 요소(즉 요청/상한)를 사용할 수 있게 해주는 확장 리소스 를 네트워킹용으로 만듭니다. 플러그인은 Network Plugins 문서에 따라 실험적인 것으로 간주되며 프로덕션 환경에서 사용하기 전에 철저히 테스트해야 한다는 점을 인지해요.
스토리지 QoS의 경우 성능 특성이 다른 서로 다른 스토리지 클래스나 프로필을 만드는 것을 원할 거예요. 각 스토리지 프로필은 IO, 이중화 또는 처리량 같은 서로 다른 워크로드에 최적화된 서로 다른 서비스 등급과 연관될 수 있어요. 테넌트가 적절한 스토리지 프로필을 워크로드와 연관시킬 수 있도록 추가 로직이 필요할 수 있어요.
마지막으로 파드 우선순위와 선점 이 있는데, 파드에 우선순위 값을 할당할 수 있어요. 스케줄링 중에 더 높은 우선순위가 할당된 파드를 스케줄할 리소스가 부족하면 스케줄러는 더 낮은 우선순위의 파드를 축출하려고 해요. 공유 클러스터에서 테넌트가 서로 다른 서비스 등급(예: 무료와 유료)을 갖는 사용 사례가 있다면 이 기능을 사용해 특정 등급에 더 높은 우선순위를 줄 수 있어요.
DNS
쿠버네티스 클러스터는 모든 Service와 Pod에 대해 이름에서 IP 주소로의 변환을 제공하는 도메인 이름 시스템(DNS) 서비스를 포함해요. 기본적으로 쿠버네티스 DNS 서비스는 클러스터의 모든 네임스페이스에서 조회를 허용해요.
테넌트가 파드와 다른 쿠버네티스 리소스에 접근할 수 있거나 더 강한 격리가 필요한 멀티 테넌트 환경에서는 파드가 다른 Namespace의 서비스를 조회하는 것을 방지하는 것이 필요할 수 있어요. DNS 서비스에 대한 보안 규칙을 구성해 크로스 네임스페이스 DNS 조회를 제한할 수 있어요. 예를 들어 CoreDNS(쿠버네티스의 기본 DNS 서비스)는 쿠버네티스 메타데이터를 활용해 네임스페이스 내의 Pod와 Service에 대한 쿼리를 제한할 수 있어요. 자세한 내용은 CoreDNS 문서 내에서 이를 구성하는 예시 를 읽어보세요.
테넌트별 가상 컨트롤 플레인 모델을 사용할 때는 테넌트별로 DNS 서비스를 구성하거나 멀티 테넌트 DNS 서비스를 사용해야 해요. 다음은 여러 테넌트를 지원하는 CoreDNS의 커스텀 버전 예시예요.
오퍼레이터 (Operators)
Operator 는 애플리케이션을 관리하는 쿠버네티스 컨트롤러예요. Operator는 데이터베이스 서비스 같은 애플리케이션의 여러 인스턴스 관리를 단순화할 수 있어서 멀티 소비자(SaaS) 멀티 테넌시 사용 사례에서 일반적인 구성 요소가 돼요.
멀티 테넌트 환경에서 사용되는 Operator는 더 엄격한 지침 집합을 따라야 해요. 구체적으로 Operator는 다음을 해야 해요:
- Operator가 배포된 네임스페이스뿐만 아니라 다른 테넌트 네임스페이스 내에서도 리소스 생성을 지원해야 해요.
- 스케줄링과 공정성을 보장하기 위해 파드가 리소스 요청과 상한으로 구성되도록 보장해야 해요.
- 노드 격리와 샌드박스 컨테이너 같은 데이터 플레인 격리 기법을 위한 파드 구성을 지원해야 해요.
구현 (Implementations)
멀티 테넌시를 위해 쿠버네티스 클러스터를 공유하는 두 가지 주요 방법이 있어요: Namespace를 사용하거나(즉 테넌트당 하나의 Namespace) 컨트롤 플레인을 가상화하거나(즉 테넌트당 가상 컨트롤 플레인) 하는 거예요.
두 경우 모두 데이터 플레인 격리와 API 우선순위와 공정성 같은 추가 고려 사항의 관리도 권장돼요.
Namespace 격리는 쿠버네티스가 잘 지원하고 리소스 비용이 무시할 수 있으며, 서비스 간 통신 허용 같은 테넌트가 적절히 상호작용할 수 있게 하는 메커니즘을 제공해요. 하지만 구성하기 어려울 수 있고 커스텀 리소스 정의, 스토리지 클래스, 웹훅과 같은 네임스페이스화할 수 없는 쿠버네티스 리소스에는 적용되지 않아요.
컨트롤 플레인 가상화는 다소 더 높은 리소스 사용과 더 어려운 크로스 테넌트 공유의 비용으로 비네임스페이스 리소스의 격리를 허용해요. 이것은 Namespace 격리가 불충분하지만 유지 비용(특히 온프레미스)이 높거나 높은 오버헤드와 리소스 공유 부족 때문에 전용 클러스터가 바람직하지 않을 때 좋은 옵션이에요. 하지만 가상화된 컨트롤 플레인 내에서도 Namespace를 사용하면 이점을 볼 가능성이 높아요.
두 옵션은 다음 섹션에서 더 자세히 논의돼요.
테넌트별 네임스페이스 (Namespace per tenant)
앞서 언급했듯이 전용 클러스터나 가상화된 컨트롤 플레인을 사용하더라도 각 워크로드를 자신의 네임스페이스에 격리하는 것을 고려해야 해요. 이렇게 하면 각 워크로드가 ConfigMap과 Secret 같은 자신의 리소스에만 접근할 수 있고 각 워크로드에 전용 보안 정책을 맞출 수 있게 됩니다. 또한 각 네임스페이스에 전체 플릿에 걸쳐 고유한 이름을 주는 것이 모범 사례예요(즉 별도 클러스터에 있더라도). 이렇게 하면 미래에 전용 클러스터와 공유 클러스터 사이를 전환하거나 서비스 메시 같은 멀티 클러스터 도구를 사용할 수 있는 유연성을 얻을 수 있어요.
반대로 워크로드 수준이 아니라 테넌트 수준에서 네임스페이스를 할당하는 이점도 있는데, 단일 테넌트가 소유한 모든 워크로드에 적용되는 정책이 종종 있기 때문이에요. 하지만 이것은 자신의 문제를 제기해요. 첫째, 개별 워크로드에 정책을 맞춤화하는 것을 어렵거나 불가능하게 만들고, 둘째, 네임스페이스가 주어져야 할 단일 "테넌시" 수준을 정하기 어려울 수 있어요. 예를 들어 조직에 부서, 팀, 하위 팀이 있을 수 있는데 어떤 것이 네임스페이스를 할당받아야 할까요?
한 가지 가능한 접근 방식은 네임스페이스를 계층 구조로 구성하고 그들 사이에서 특정 정책과 리소스를 공유하는 것이에요. 여기에는 네임스페이스 레이블 관리, 네임스페이스 수명 주기, 위임된 접근, 관련 네임스페이스 간 공유 리소스 쿼터 관리가 포함될 수 있어요. 이러한 기능은 멀티 팀과 멀티 고객 시나리오 모두에서 유용할 수 있어요.
테넌트별 가상 컨트롤 플레인 (Virtual control plane per tenant)
컨트롤 플레인 격리의 또 다른 형태는 쿠버네티스 확장을 사용해 각 테넌트에게 클러스터 전체 API 리소스의 분할을 가능하게 하는 가상 컨트롤 플레인을 제공하는 것이에요. 데이터 플레인 격리 기법을 이 모델과 함께 사용해 테넌트 간 워커 노드를 안전하게 관리할 수 있어요.
가상 컨트롤 플레인 기반 멀티 테넌시 모델은 각 테넌트에게 전용 컨트롤 플레인 구성 요소를 제공함으로써 네임스페이스 기반 멀티 테넌시를 확장하고, 따라서 클러스터 전체 리소스와 추가 기능(add-on) 서비스에 대한 완전한 제어를 제공해요. 워커 노드는 모든 테넌트가 공유하며 테넌트가 일반적으로 접근할 수 없는 쿠버네티스 클러스터가 관리해요. 이 클러스터는 종종 슈퍼 클러스터(super-cluster) (때로는 호스트 클러스터(host-cluster)) 라고 불려요. 테넌트의 컨트롤 플레인이 기본 컴퓨팅 리소스와 직접 연관되지 않으므로 가상 컨트롤 플레인 이라고 불러요.
가상 컨트롤 플레인은 일반적으로 쿠버네티스 API 서버, 컨트롤러 매니저, etcd 데이터 저장소로 구성돼요. 그것은 테넌트 컨트롤 플레인과 슈퍼 클러스터의 컨트롤 플레인 사이의 변경을 조정하는 메타데이터 동기화 컨트롤러를 통해 슈퍼 클러스터와 상호작용해요.
테넌트별 전용 컨트롤 플레인을 사용하면 모든 테넌트 간에 단일 API 서버를 공유하는 데 따른 격리 문제의 대부분이 해결돼요. 예로는 컨트롤 플레인의 시끄러운 이웃, 정책 잘못 구성의 통제 불가능한 폭발 반경(blast radius), 웹훅과 CRD 같은 클러스터 범위 객체 간의 충돌이 있어요. 따라서 가상 컨트롤 플레인 모델은 각 테넌트가 쿠버네티스 API 서버에 대한 접근을 요구하고 전체 클러스터 관리성을 기대하는 경우에 특히 적합해요.
개선된 격리는 테넌트당 개별 가상 컨트롤 플레인을 실행·유지하는 비용을 수반해요. 또한 테넌트별 컨트롤 플레인은 노드 수준 시끄러운 이웃이나 보안 위협 같은 데이터 플레인의 격리 문제를 해결하지 못해요. 이것들은 여전히 별도로 해결되어야 해요.