Skip to content

Split View: vCluster로 구현하는 Kubernetes 멀티 테넌시: 가상 클러스터 격리와 운영 가이드

✨ Learn with Quiz
|

vCluster로 구현하는 Kubernetes 멀티 테넌시: 가상 클러스터 격리와 운영 가이드

vCluster Multi-Tenancy

들어가며

Kubernetes를 운영하다 보면 반드시 마주치는 과제가 멀티 테넌시(Multi-Tenancy) 문제이다. 하나의 물리 클러스터 위에서 여러 팀, 프로젝트, 또는 고객사의 워크로드를 안전하게 격리하면서도 인프라 비용을 최적화해야 하는 요구사항은 조직 규모가 커질수록 절박해진다. 전통적으로 네임스페이스 기반 격리, RBAC 정책, NetworkPolicy 등을 조합하여 멀티 테넌시를 구현해왔지만, CRD 설치 권한 충돌, API Server 공유로 인한 noisy neighbor 문제, 테넌트별 독립적인 클러스터 업그레이드 불가 등 본질적인 한계가 존재한다.

vCluster는 Loft Labs(현 vCluster Labs)가 개발한 오픈소스 프로젝트로, 호스트 클러스터의 네임스페이스 안에서 가상 Kubernetes 클러스터를 실행하는 방식으로 이 문제를 해결한다. 각 가상 클러스터는 독립적인 API Server, Controller Manager, 데이터 저장소(etcd 또는 SQLite)를 갖추고 있어 테넌트에게 완전한 클러스터 관리 권한을 부여하면서도 실제 컴퓨팅 리소스는 호스트 클러스터에서 공유한다. CNCF 프로젝트로서 2025년에는 KubeCon EU에서 vNode를 발표하며 노드 수준의 가상화 격리 계층을 추가했고, 같은 해 Standalone vCluster를 통해 호스트 클러스터 없이도 독립적으로 가상 클러스터를 운영할 수 있는 기능까지 선보였다.

이 글에서는 vCluster의 아키텍처 원리부터 시작하여 설치, 구성, Syncer 메커니즘, RBAC 정책, 리소스 쿼터, 네트워크 격리, 모니터링 통합, 그리고 실제 프로덕션 환경에서 겪을 수 있는 실패 사례와 복구 절차까지 종합적으로 다룬다.

vCluster 아키텍처

vCluster의 핵심 아이디어는 호스트 클러스터의 네임스페이스 하나를 가상 클러스터의 실행 환경으로 활용하는 것이다. 가상 클러스터 내부에서 생성된 워크로드는 Syncer 컴포넌트를 통해 호스트 클러스터의 해당 네임스페이스에 실제 Pod로 스케줄링된다.

구성 요소

vCluster는 다음과 같은 주요 컴포넌트로 구성된다.

  1. Control Plane: 가상 클러스터 전용 API Server와 Controller Manager를 실행한다. 기본적으로 k3s를 사용하지만, k0s, vanilla k8s(EKS distro 포함)도 선택할 수 있다.
  2. Data Store: etcd, SQLite, 또는 외부 데이터베이스(PostgreSQL, MySQL)를 데이터 저장소로 사용한다. k3s 기반 배포 시 기본값은 내장 SQLite이다.
  3. Syncer: 가상 클러스터와 호스트 클러스터 간 리소스 동기화를 담당하는 핵심 컴포넌트이다.
  4. CoreDNS: 가상 클러스터 내부의 DNS 해석을 담당한다. 호스트 클러스터의 DNS와 연동되어 서비스 디스커버리를 지원한다.

격리 수준 계층

vCluster는 세 가지 격리 수준을 제공한다.

  • Shared (공유): 기본 모드. 가상 클러스터가 호스트 클러스터의 네임스페이스 안에서 실행되며, 호스트 클러스터의 노드를 공유한다.
  • Private (전용): 가상 클러스터 전용 노드를 할당하여 컴퓨팅 리소스를 물리적으로 격리한다.
  • Standalone (독립): 호스트 클러스터 없이 독립적으로 실행되는 가상 클러스터이다. 2025년에 도입된 기능으로, 완전한 클러스터 자율성을 보장한다.

네임스페이스 기반 격리 vs vCluster 비교표

기존 네임스페이스 기반 멀티 테넌시와 vCluster 기반 가상 클러스터 접근 방식을 다양한 관점에서 비교한다.

항목네임스페이스 기반 격리vCluster 가상 클러스터
API Server공유 (모든 테넌트 동일 API Server)독립 (테넌트별 전용 API Server)
CRD 설치클러스터 전역 영향, 충돌 위험가상 클러스터 내 독립 설치 가능
RBAC 복잡도테넌트 증가 시 정책 폭발적 증가테넌트별 독립 RBAC, 관리 단순화
리소스 격리ResourceQuota/LimitRange 기반 소프트 격리가상 클러스터 + 호스트 쿼터 이중 격리
네트워크 격리NetworkPolicy 필수 구성기본 네임스페이스 격리 + NetworkPolicy 추가 가능
클러스터 업그레이드전체 클러스터 동시 영향가상 클러스터별 독립 업그레이드 가능
Admission Webhook전역 적용, 테넌트 간 영향가상 클러스터별 독립 구성
비용 효율성높음 (최소 오버헤드)중간 (컨트롤 플레인 오버헤드 존재)
구현 난이도낮음중간 (Syncer, 네트워크 이해 필요)
테넌트 자율성낮음 (클러스터 관리자 의존)높음 (가상 cluster-admin 가능)

설치 및 구성

CLI를 이용한 빠른 설치

vCluster CLI를 사용하면 가장 빠르게 가상 클러스터를 생성할 수 있다.

# vCluster CLI 설치
curl -L -o vcluster "https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64"
chmod +x vcluster
sudo mv vcluster /usr/local/bin/

# 가상 클러스터 생성 (기본 k3s 기반)
vcluster create my-vcluster --namespace team-alpha

# 가상 클러스터에 접속 (kubeconfig 자동 구성)
vcluster connect my-vcluster --namespace team-alpha

# 접속 확인
kubectl get namespaces
kubectl get nodes

# 가상 클러스터 연결 해제
vcluster disconnect

# 가상 클러스터 삭제
vcluster delete my-vcluster --namespace team-alpha

Helm을 이용한 프로덕션 배포

프로덕션 환경에서는 Helm 차트를 사용하여 세밀한 설정을 적용하는 것이 권장된다. 다음은 프로덕션 수준의 vcluster.yaml 설정 예시이다.

# vcluster.yaml - 프로덕션 설정 예시
controlPlane:
  # k3s 대신 k8s 사용 (프로덕션 권장)
  distro:
    k8s:
      enabled: true
      apiServer:
        extraArgs:
          - '--audit-log-path=/var/log/kubernetes/audit.log'
          - '--audit-log-maxage=30'
          - '--audit-log-maxbackup=10'
          - '--audit-log-maxsize=100'
      controllerManager:
        extraArgs:
          - '--terminated-pod-gc-threshold=50'

  # 컨트롤 플레인 리소스 제한
  statefulSet:
    resources:
      limits:
        cpu: '2'
        memory: 4Gi
      requests:
        cpu: '500m'
        memory: 1Gi
    persistence:
      size: 20Gi

  # 외부 etcd 사용 (고가용성)
  backingStore:
    etcd:
      deploy:
        enabled: true
        statefulSet:
          resources:
            limits:
              cpu: '1'
              memory: 2Gi
            requests:
              cpu: '200m'
              memory: 512Mi

# 리소스 동기화 설정
sync:
  toHost:
    pods:
      enabled: true
    services:
      enabled: true
    configmaps:
      enabled: true
    secrets:
      enabled: true
    endpoints:
      enabled: true
    persistentvolumeclaims:
      enabled: true
    ingresses:
      enabled: true
    storageClasses:
      enabled: false
  fromHost:
    nodes:
      enabled: true
      selector:
        labels:
          team: alpha
    storageClasses:
      enabled: true
    ingressClasses:
      enabled: true

# 네트워킹 설정
networking:
  replicateServices:
    fromHost:
      - from: monitoring/prometheus-server
        to: monitoring/prometheus-server
  resolveDNS:
    - hostname: '*.team-alpha.svc.cluster.local'
      target:
        hostNamespace: team-alpha

# 보안 정책
policies:
  resourceQuota:
    enabled: true
    quota:
      requests.cpu: '8'
      requests.memory: '16Gi'
      limits.cpu: '16'
      limits.memory: '32Gi'
      pods: '50'
      services: '20'
      persistentvolumeclaims: '10'
  limitRange:
    enabled: true
    default:
      cpu: '500m'
      memory: '512Mi'
    defaultRequest:
      cpu: '100m'
      memory: '128Mi'

Helm 차트를 사용하여 배포하는 명령은 다음과 같다.

# Helm 리포지토리 추가
helm repo add loft https://charts.loft.sh
helm repo update

# 네임스페이스 생성
kubectl create namespace team-alpha

# vCluster 배포
helm upgrade --install my-vcluster loft/vcluster \
  --namespace team-alpha \
  --values vcluster.yaml \
  --version 0.24.1

# 배포 상태 확인
kubectl get pods -n team-alpha
kubectl get statefulset -n team-alpha

# vCluster 접속
vcluster connect my-vcluster -n team-alpha

Syncer 동작 원리

Syncer는 vCluster의 핵심 엔진으로, 가상 클러스터와 호스트 클러스터 간의 리소스 동기화를 담당한다. 이 메커니즘을 정확히 이해하는 것이 vCluster 운영의 핵심이다.

동기화 방향과 리소스 유형

Syncer의 동기화는 두 가지 방향으로 이루어진다.

가상 -> 호스트 (toHost): 가상 클러스터에서 생성된 리소스가 호스트 클러스터의 네임스페이스에 실제로 생성된다. Pod, Service, ConfigMap, Secret, PVC 등이 이 방향으로 동기화된다. 가상 클러스터에서 Deployment를 생성하면, Deployment 자체는 가상 클러스터의 etcd에만 존재하지만, 결과적으로 생성되는 Pod는 호스트 클러스터 네임스페이스에 실제 Pod로 스케줄링된다.

호스트 -> 가상 (fromHost): 호스트 클러스터의 리소스를 가상 클러스터 내부에서 사용할 수 있도록 동기화한다. StorageClass, IngressClass, Node 정보, PriorityClass 등이 이 방향으로 동기화된다.

리소스 이름 변환(Name Rewriting)

Syncer는 가상 클러스터의 리소스를 호스트 클러스터에 동기화할 때 이름 충돌을 방지하기 위해 이름을 변환한다. 기본 변환 규칙은 {vcluster-name}-x-{resource-name}-x-{vcluster-namespace} 형식이다. 예를 들어, 가상 클러스터 my-vcluster에서 default 네임스페이스에 nginx Pod를 생성하면 호스트 클러스터에서는 my-vcluster-x-nginx-x-team-alpha 이름으로 생성된다.

라벨과 어노테이션 전파

Syncer는 호스트 클러스터의 리소스에 추가 라벨을 부착하여 가상 클러스터와의 연관 관계를 유지한다. vcluster.loft.sh/managed-by, vcluster.loft.sh/namespace 등의 라벨이 자동으로 추가되어 가비지 컬렉션과 리소스 추적에 활용된다.

고급 동기화: Generic Sync

기본 지원 리소스 외에 커스텀 리소스(CRD)를 동기화해야 할 경우, Generic Sync 기능을 활용할 수 있다. 이를 통해 Cert-Manager의 Certificate, Istio의 VirtualService 등 커스텀 리소스도 가상 클러스터에서 호스트 클러스터로 동기화할 수 있다.

RBAC 및 리소스 쿼터 설정

가상 클러스터 사용자 RBAC

가상 클러스터 내부에서는 테넌트에게 cluster-admin 권한을 부여할 수 있다. 이는 가상 클러스터 범위 내에서만 유효하므로 호스트 클러스터의 보안에는 영향을 미치지 않는다.

# vcluster-tenant-rbac.yaml
# 가상 클러스터 내부에서 테넌트에게 admin 권한 부여
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tenant-admin-binding
subjects:
  - kind: Group
    name: team-alpha-developers
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
---
# 호스트 클러스터에서 vCluster 네임스페이스 접근 제한
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: vcluster-namespace-viewer
  namespace: team-alpha
rules:
  - apiGroups: ['']
    resources: ['pods', 'services', 'configmaps']
    verbs: ['get', 'list', 'watch']
  - apiGroups: ['']
    resources: ['pods/log']
    verbs: ['get']
  - apiGroups: ['apps']
    resources: ['statefulsets']
    verbs: ['get', 'list', 'watch']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: vcluster-namespace-viewer-binding
  namespace: team-alpha
subjects:
  - kind: Group
    name: team-alpha-developers
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: vcluster-namespace-viewer
  apiGroup: rbac.authorization.k8s.io

호스트 클러스터 리소스 쿼터

가상 클러스터가 호스트 클러스터의 리소스를 과도하게 소비하는 것을 방지하기 위해, 가상 클러스터가 실행되는 네임스페이스에 ResourceQuota를 적용한다.

# host-resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: vcluster-team-alpha-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: '8'
    requests.memory: '16Gi'
    limits.cpu: '16'
    limits.memory: '32Gi'
    pods: '50'
    services: '20'
    services.loadbalancers: '2'
    services.nodeports: '5'
    persistentvolumeclaims: '10'
    requests.storage: '100Gi'
    count/deployments.apps: '30'
    count/statefulsets.apps: '10'
    count/jobs.batch: '20'
    count/cronjobs.batch: '10'
---
apiVersion: v1
kind: LimitRange
metadata:
  name: vcluster-team-alpha-limits
  namespace: team-alpha
spec:
  limits:
    - type: Container
      default:
        cpu: '500m'
        memory: '512Mi'
      defaultRequest:
        cpu: '100m'
        memory: '128Mi'
      max:
        cpu: '4'
        memory: '8Gi'
      min:
        cpu: '50m'
        memory: '64Mi'
    - type: Pod
      max:
        cpu: '8'
        memory: '16Gi'
    - type: PersistentVolumeClaim
      max:
        storage: '50Gi'
      min:
        storage: '1Gi'

네트워크 격리 (NetworkPolicy)

vCluster 환경에서 네트워크 격리는 두 가지 계층에서 구현한다. 먼저 호스트 클러스터 수준에서 가상 클러스터 네임스페이스 간의 통신을 제어하고, 추가로 가상 클러스터 내부에서도 워크로드 간의 세분화된 정책을 적용할 수 있다.

호스트 클러스터 수준 NetworkPolicy

# host-networkpolicy.yaml
# 가상 클러스터 네임스페이스 간 통신 차단
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: isolate-vcluster-namespace
  namespace: team-alpha
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    # 같은 네임스페이스 내 통신 허용
    - from:
        - podSelector: {}
    # 인그레스 컨트롤러에서의 트래픽 허용
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
          podSelector:
            matchLabels:
              app.kubernetes.io/name: ingress-nginx
    # 모니터링 시스템의 메트릭 수집 허용
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: monitoring
          podSelector:
            matchLabels:
              app: prometheus
  egress:
    # DNS 조회 허용
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
    # 같은 네임스페이스 내 통신 허용
    - to:
        - podSelector: {}
    # 외부 인터넷 접근 허용 (필요 시)
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 10.0.0.0/8
              - 172.16.0.0/12
              - 192.168.0.0/16

이 NetworkPolicy는 가상 클러스터의 호스트 네임스페이스를 격리하여 다른 테넌트의 네임스페이스와의 직접 통신을 차단한다. 동시에 인그레스 컨트롤러, 모니터링 시스템, DNS 등 필수 인프라 서비스와의 통신은 허용한다.

가상 클러스터 내부 NetworkPolicy

가상 클러스터 내부에서도 마이크로서비스 간의 네트워크 정책을 적용할 수 있다. 가상 클러스터 내부에서 정의한 NetworkPolicy는 Syncer를 통해 호스트 클러스터에 적절히 변환되어 적용된다.

모니터링 통합

Prometheus 메트릭 수집

vCluster의 컨트롤 플레인 및 가상 클러스터 내부 워크로드에 대한 모니터링을 구성하려면 호스트 클러스터의 Prometheus가 가상 클러스터 네임스페이스의 Pod를 스크레이핑할 수 있도록 설정해야 한다.

호스트 클러스터의 Prometheus에 ServiceMonitor를 추가하여 가상 클러스터 컨트롤 플레인의 메트릭을 수집할 수 있다. vCluster의 API Server 메트릭, etcd 메트릭, Syncer의 동기화 상태 메트릭을 포함하여 컨트롤 플레인의 건강 상태를 종합적으로 모니터링한다. 특히 Syncer의 동기화 지연 시간과 오류율은 가상 클러스터의 안정성을 판단하는 핵심 지표이다.

가상 클러스터 내부 워크로드의 메트릭은 호스트 클러스터의 Prometheus가 해당 네임스페이스의 Pod를 직접 스크레이핑하거나, 가상 클러스터 내부에 별도의 Prometheus를 설치하여 수집할 수 있다. 멀티 테넌시 환경에서는 테넌트별 Grafana 대시보드를 구성하여 각 팀이 자신의 워크로드 상태만 확인할 수 있도록 접근 제어를 적용하는 것이 좋다.

알림 설정 권장 사항

프로덕션 환경에서는 다음 항목에 대한 알림을 구성하는 것을 권장한다.

  • vCluster 컨트롤 플레인 Pod의 재시작 횟수가 임계치를 초과하는 경우
  • Syncer의 동기화 지연 시간이 30초를 초과하는 경우
  • 가상 클러스터 네임스페이스의 리소스 쿼터 사용량이 80%를 초과하는 경우
  • etcd 데이터 저장소의 디스크 사용량이 70%를 초과하는 경우
  • 가상 클러스터 API Server의 응답 시간이 비정상적으로 증가하는 경우

실패 사례와 복구 절차

사례 1: Syncer 동기화 실패로 인한 Pod 미스매치

증상: 가상 클러스터에서 Deployment를 삭제했으나 호스트 클러스터에 고아(orphan) Pod가 남아있는 상황. 가상 클러스터의 kubectl get pods와 호스트 클러스터의 실제 Pod 목록이 불일치한다.

원인: Syncer Pod의 OOM Kill 또는 네트워크 파티션으로 인해 삭제 이벤트가 전파되지 않은 경우에 발생한다.

복구 절차:

# 1. 호스트 클러스터에서 고아 Pod 식별
kubectl get pods -n team-alpha -l vcluster.loft.sh/managed-by=my-vcluster \
  --field-selector=status.phase=Running

# 2. 가상 클러스터에서 해당 Pod가 존재하는지 확인
vcluster connect my-vcluster -n team-alpha
kubectl get pods --all-namespaces

# 3. 가상 클러스터에 존재하지 않는 고아 Pod 수동 삭제
vcluster disconnect
kubectl delete pod <orphan-pod-name> -n team-alpha --grace-period=30

# 4. Syncer Pod 재시작으로 동기화 상태 복원
kubectl rollout restart statefulset my-vcluster -n team-alpha

# 5. 동기화 상태 확인 (로그 검토)
kubectl logs statefulset/my-vcluster -n team-alpha -c syncer --tail=100

예방 조치: Syncer의 리소스 요청/제한을 충분히 설정하고, 정기적으로 가상 클러스터와 호스트 클러스터 간의 리소스 일치 여부를 검사하는 CronJob을 구성한다.

사례 2: 가상 클러스터 etcd 데이터 손상

증상: 가상 클러스터 API Server가 시작되지 않고, etcd 컨테이너 로그에 panic: freepages: failed to get all reachable pages 또는 database file is not valid 오류가 표시된다.

원인: PersistentVolume의 디스크 I/O 오류, 비정상적인 Pod 종료, 또는 스토리지 백엔드 장애로 인해 etcd 데이터 파일이 손상된 경우이다.

복구 절차:

  1. 가상 클러스터의 StatefulSet을 replicas: 0으로 스케일 다운한다.
  2. 백업이 있는 경우, PVC의 데이터를 백업 데이터로 교체한다.
  3. 백업이 없는 경우, PVC를 삭제하고 새로운 PVC로 교체한 뒤 가상 클러스터를 재생성한다. 이 경우 가상 클러스터 내부의 모든 메타데이터가 손실되지만, 실제 워크로드 Pod는 호스트 클러스터에서 계속 실행된다.
  4. StatefulSet을 다시 replicas: 1로 스케일 업하고, 호스트 클러스터의 기존 리소스와 다시 동기화되는지 확인한다.

예방 조치: etcd 데이터의 정기적인 스냅샷 백업을 구성하고, 프로덕션 환경에서는 고가용성 etcd 클러스터 구성을 사용한다.

사례 3: 리소스 쿼터 초과로 인한 워크로드 배포 실패

증상: 가상 클러스터 내부에서 Pod 생성이 실패하며, forbidden: exceeded quota 에러가 발생하지 않고 대신 Pod가 Pending 상태에서 멈추는 현상.

원인: 호스트 클러스터의 ResourceQuota가 초과되었지만, 에러 메시지가 가상 클러스터의 이벤트에 제대로 전파되지 않아 테넌트가 원인을 파악하기 어려운 경우이다.

복구 절차:

  1. 호스트 클러스터에서 해당 네임스페이스의 ResourceQuota 사용량을 확인한다: kubectl describe resourcequota -n team-alpha
  2. 불필요한 리소스를 정리하거나 쿼터를 증가시킨다.
  3. vCluster 설정에서 이벤트 동기화를 활성화하여 테넌트가 호스트 클러스터의 이벤트도 확인할 수 있도록 한다.

예방 조치: 쿼터 사용량이 80%를 초과하면 알림을 발생시키고, 가상 클러스터 내부에서도 별도의 ResourceQuota를 구성하여 사전에 제한한다.

사례 4: 가상 클러스터 간 네트워크 격리 실패

증상: 서로 다른 가상 클러스터의 워크로드가 호스트 클러스터에서 같은 네트워크를 공유하여 직접 통신이 가능한 상태.

원인: 호스트 클러스터에 NetworkPolicy가 구성되지 않았거나, CNI 플러그인이 NetworkPolicy를 지원하지 않는 경우(예: Flannel 기본 설정).

복구 절차:

  1. CNI 플러그인이 NetworkPolicy를 지원하는지 확인한다. Calico, Cilium, WeaveNet 등은 NetworkPolicy를 지원하며, Flannel 기본 설정은 지원하지 않는다.
  2. 위의 네트워크 격리 섹션에서 제시한 NetworkPolicy를 각 가상 클러스터의 호스트 네임스페이스에 적용한다.
  3. 격리가 올바르게 작동하는지 테스트 Pod를 생성하여 타 네임스페이스로의 통신이 차단되는지 확인한다.

사례 5: 가상 클러스터 업그레이드 실패

증상: Helm을 통한 vCluster 버전 업그레이드 후, 가상 클러스터의 API Server가 시작되지 않거나 기존 워크로드와의 호환성 문제가 발생한다.

원인: 메이저 버전 간의 API 변경사항이나 Syncer 프로토콜 변경으로 인한 비호환성.

복구 절차:

  1. 업그레이드 전 반드시 etcd 스냅샷 백업을 수행한다.
  2. 실패 시 helm rollback my-vcluster <이전-리비전> -n team-alpha 명령으로 이전 버전으로 롤백한다.
  3. 롤백 후에도 문제가 지속되면 백업에서 etcd 데이터를 복원한다.

예방 조치: 스테이징 환경에서 먼저 업그레이드를 테스트하고, 공식 업그레이드 가이드의 Breaking Changes를 반드시 확인한다. 프로덕션 환경에서는 한 단계씩 점진적으로 업그레이드한다.

운영 시 주의사항 체크리스트

프로덕션 환경에서 vCluster를 운영할 때 반드시 확인해야 할 항목들을 정리한다.

배포 전 점검사항:

  • CNI 플러그인이 NetworkPolicy를 지원하는지 확인 (Calico, Cilium 권장)
  • 호스트 클러스터의 ResourceQuota가 가상 클러스터 네임스페이스에 적용되었는지 확인
  • vCluster 컨트롤 플레인의 리소스 요청/제한이 적절히 설정되었는지 확인
  • PersistentVolume의 스토리지 클래스와 리클레임 정책이 올바른지 확인
  • 가상 클러스터의 kubeconfig 배포 프로세스가 안전한지 확인 (OIDC 연동 권장)

운영 중 모니터링 항목:

  • Syncer의 동기화 지연 시간과 에러율 모니터링
  • 가상 클러스터 컨트롤 플레인의 CPU/메모리 사용량 모니터링
  • etcd 데이터 저장소의 디스크 사용량과 컴팩션 상태 모니터링
  • 가상 클러스터 API Server의 요청 지연 시간과 에러율 모니터링
  • 호스트 클러스터 네임스페이스의 리소스 쿼터 사용량 모니터링

백업 및 재해 복구:

  • etcd 스냅샷의 정기 백업 스케줄이 구성되었는지 확인 (최소 일 1회)
  • 백업 복원 절차를 분기별로 테스트하는지 확인
  • 가상 클러스터의 재생성 절차가 자동화(IaC)되어 있는지 확인
  • 호스트 클러스터 장애 시 가상 클러스터의 복구 절차가 문서화되어 있는지 확인

보안 점검사항:

  • 가상 클러스터 사용자의 인증/인가가 중앙 IdP(OIDC, LDAP)와 통합되어 있는지 확인
  • 호스트 클러스터의 Node 접근 권한이 가상 클러스터 테넌트에게 노출되지 않는지 확인
  • Pod Security Standards(PSS)가 적용되어 privileged 컨테이너 실행을 방지하는지 확인
  • 가상 클러스터 간의 네트워크 격리가 올바르게 동작하는지 정기적으로 테스트하는지 확인

업그레이드 절차:

  • vCluster 버전 업그레이드 전 etcd 스냅샷 백업 수행
  • 스테이징 환경에서 업그레이드 테스트 후 프로덕션 적용
  • 업그레이드 후 Syncer 동기화 상태와 워크로드 정상 동작 확인
  • 롤백 절차와 명령어를 사전에 준비

마무리

vCluster는 Kubernetes 멀티 테넌시의 근본적인 한계를 가상 클러스터라는 추상화 계층으로 해결하는 실용적인 도구이다. 네임스페이스 기반 격리만으로는 충족하기 어려운 CRD 독립성, API Server 격리, 테넌트별 클러스터 관리 자율성 등의 요구사항을 물리 클러스터를 추가하지 않고도 달성할 수 있다.

다만 Syncer의 동작 원리와 리소스 이름 변환 메커니즘을 충분히 이해하지 않으면 운영 시 예상치 못한 문제에 직면할 수 있으므로, 스테이징 환경에서 충분한 검증을 거친 후 프로덕션에 도입하는 것을 권장한다. 특히 네트워크 격리와 리소스 쿼터 설정은 초기 구성 단계에서 반드시 함께 적용해야 한다.

참고자료

Kubernetes Multi-Tenancy with vCluster: Virtual Cluster Isolation and Operational Guide

vCluster Multi-Tenancy

Introduction

When operating Kubernetes, one challenge you'll inevitably encounter is multi-tenancy. The need to safely isolate workloads from multiple teams, projects, or customers on a single physical cluster while optimizing infrastructure costs becomes increasingly urgent as organizations scale. Traditionally, multi-tenancy has been implemented by combining namespace-based isolation, RBAC policies, and NetworkPolicy, but this approach has inherent limitations: CRD installation permission conflicts, noisy neighbor problems from sharing the API Server, and the inability to upgrade clusters independently per tenant.

vCluster is an open-source project developed by Loft Labs (now vCluster Labs) that addresses these issues by running virtual Kubernetes clusters within a namespace of the host cluster. Each virtual cluster has its own dedicated API Server, Controller Manager, and data store (etcd or SQLite), allowing you to grant tenants complete cluster management authority while still sharing actual compute resources from the host cluster. As a CNCF project, vCluster introduced vNode at KubeCon EU 2025, adding a node-level virtualization isolation layer, and later launched Standalone vCluster to enable independent virtual cluster operation without a host cluster.

This article comprehensively covers vCluster architecture, installation, configuration, the Syncer mechanism, RBAC policies, resource quotas, network isolation, monitoring integration, and real production failure cases with recovery procedures.

vCluster Architecture

The core idea of vCluster is to use one namespace of the host cluster as the execution environment for the virtual cluster. Workloads created inside the virtual cluster are actually scheduled as Pods in the host cluster's namespace through the Syncer component.

Components

vCluster comprises the following main components:

  1. Control Plane: Runs a dedicated API Server and Controller Manager for the virtual cluster. By default it uses k3s, but k0s and vanilla k8s (including EKS distro) are also available as options.
  2. Data Store: Uses etcd, SQLite, or external databases (PostgreSQL, MySQL) as the data store. The default for k3s-based deployments is the built-in SQLite.
  3. Syncer: The core component responsible for resource synchronization between the virtual cluster and the host cluster.
  4. CoreDNS: Handles DNS resolution within the virtual cluster. Works in conjunction with the host cluster's DNS to support service discovery.

Isolation Level Tiers

vCluster provides three levels of isolation:

  • Shared (Default): The virtual cluster runs within a namespace of the host cluster and shares the host cluster's nodes.
  • Private (Dedicated): Compute resources are physically isolated by allocating dedicated nodes for the virtual cluster.
  • Standalone (Independent): A virtual cluster that runs independently without a host cluster. This feature was introduced in 2025 and provides complete cluster autonomy.

Namespace-Based Isolation vs vCluster Comparison

The following table compares traditional namespace-based multi-tenancy with the virtual cluster approach using vCluster from various perspectives.

ItemNamespace-Based IsolationvCluster Virtual Cluster
API ServerShared (all tenants use the same API Server)Independent (dedicated API Server per tenant)
CRD InstallationGlobal cluster impact, conflict riskIndependent installation within virtual cluster
RBAC ComplexityPolicies explode as tenants increaseIndependent RBAC per tenant, simplified management
Resource IsolationSoft isolation via ResourceQuota/LimitRangeDouble isolation: virtual cluster + host quota
Network IsolationNetworkPolicy requiredDefault namespace isolation + optional NetworkPolicy
Cluster UpgradeAffects entire cluster simultaneouslyCan be upgraded independently per virtual cluster
Admission WebhookGlobal application, impacts across tenantsIndependent configuration per virtual cluster
Cost EfficiencyHigh (minimal overhead)Medium (control plane overhead exists)
Implementation DifficultyLowMedium (requires understanding Syncer and networking)
Tenant AutonomyLow (depends on cluster administrator)High (virtual cluster-admin possible)

Installation and Configuration

Quick Installation with CLI

The vCluster CLI enables the fastest way to create a virtual cluster:

# Install vCluster CLI
curl -L -o vcluster "https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64"
chmod +x vcluster
sudo mv vcluster /usr/local/bin/

# Create virtual cluster (k3s-based by default)
vcluster create my-vcluster --namespace team-alpha

# Access virtual cluster (kubeconfig automatically configured)
vcluster connect my-vcluster --namespace team-alpha

# Verify connectivity
kubectl get namespaces
kubectl get nodes

# Disconnect from virtual cluster
vcluster disconnect

# Delete virtual cluster
vcluster delete my-vcluster --namespace team-alpha

Production Deployment with Helm

For production environments, using Helm charts with fine-grained configuration is recommended. Here's an example of a production-ready vcluster.yaml configuration:

# vcluster.yaml - Production configuration example
controlPlane:
  # Use k8s instead of k3s (production recommended)
  distro:
    k8s:
      enabled: true
      apiServer:
        extraArgs:
          - '--audit-log-path=/var/log/kubernetes/audit.log'
          - '--audit-log-maxage=30'
          - '--audit-log-maxbackup=10'
          - '--audit-log-maxsize=100'
      controllerManager:
        extraArgs:
          - '--terminated-pod-gc-threshold=50'

  # Control plane resource limits
  statefulSet:
    resources:
      limits:
        cpu: '2'
        memory: 4Gi
      requests:
        cpu: '500m'
        memory: 1Gi
    persistence:
      size: 20Gi

  # Use external etcd (high availability)
  backingStore:
    etcd:
      deploy:
        enabled: true
        statefulSet:
          resources:
            limits:
              cpu: '1'
              memory: 2Gi
            requests:
              cpu: '200m'
              memory: 512Mi

# Resource synchronization configuration
sync:
  toHost:
    pods:
      enabled: true
    services:
      enabled: true
    configmaps:
      enabled: true
    secrets:
      enabled: true
    endpoints:
      enabled: true
    persistentvolumeclaims:
      enabled: true
    ingresses:
      enabled: true
    storageClasses:
      enabled: false
  fromHost:
    nodes:
      enabled: true
      selector:
        labels:
          team: alpha
    storageClasses:
      enabled: true
    ingressClasses:
      enabled: true

# Networking configuration
networking:
  replicateServices:
    fromHost:
      - from: monitoring/prometheus-server
        to: monitoring/prometheus-server
  resolveDNS:
    - hostname: '*.team-alpha.svc.cluster.local'
      target:
        hostNamespace: team-alpha

# Security policies
policies:
  resourceQuota:
    enabled: true
    quota:
      requests.cpu: '8'
      requests.memory: '16Gi'
      limits.cpu: '16'
      limits.memory: '32Gi'
      pods: '50'
      services: '20'
      persistentvolumeclaims: '10'
  limitRange:
    enabled: true
    default:
      cpu: '500m'
      memory: '512Mi'
    defaultRequest:
      cpu: '100m'
      memory: '128Mi'

The deployment command using Helm chart is as follows:

# Add Helm repository
helm repo add loft https://charts.loft.sh
helm repo update

# Create namespace
kubectl create namespace team-alpha

# Deploy vCluster
helm upgrade --install my-vcluster loft/vcluster \
  --namespace team-alpha \
  --values vcluster.yaml \
  --version 0.24.1

# Check deployment status
kubectl get pods -n team-alpha
kubectl get statefulset -n team-alpha

# Access vCluster
vcluster connect my-vcluster -n team-alpha

Syncer Operation Mechanism

The Syncer is the core engine of vCluster, responsible for resource synchronization between the virtual cluster and the host cluster. Understanding this mechanism precisely is essential for vCluster operations.

Synchronization Direction and Resource Types

Syncer synchronization occurs in two directions:

Virtual → Host (toHost): Resources created in the virtual cluster are actually created in the host cluster's namespace. Pods, Services, ConfigMaps, Secrets, and PVCs are synchronized in this direction. When you create a Deployment in the virtual cluster, the Deployment itself exists only in the virtual cluster's etcd, but the resulting Pods are actually scheduled as Pods in the host cluster's namespace.

Host → Virtual (fromHost): Resources from the host cluster are made available within the virtual cluster. StorageClass, IngressClass, Node information, and PriorityClass are synchronized in this direction.

Resource Name Rewriting

When the Syncer synchronizes resources from the virtual cluster to the host cluster, it rewrites names to prevent name collisions. The default rewriting rule follows the pattern {vcluster-name}-x-{resource-name}-x-{vcluster-namespace}. For example, if you create an nginx Pod in the default namespace of the my-vcluster virtual cluster, it will be created with the name my-vcluster-x-nginx-x-team-alpha in the host cluster.

Label and Annotation Propagation

The Syncer maintains relationships with the virtual cluster by attaching additional labels to resources in the host cluster. Labels like vcluster.loft.sh/managed-by and vcluster.loft.sh/namespace are automatically added and used for garbage collection and resource tracking.

Advanced Sync: Generic Sync

For custom resources (CRDs) beyond the default supported resources, you can use the Generic Sync feature. This allows you to synchronize custom resources such as Cert-Manager's Certificate or Istio's VirtualService from the virtual cluster to the host cluster.

RBAC and Resource Quota Configuration

Virtual Cluster User RBAC

Within the virtual cluster, you can grant tenants cluster-admin permissions. This is only valid within the virtual cluster scope and doesn't impact the security of the host cluster.

# vcluster-tenant-rbac.yaml
# Grant admin permissions to tenants within the virtual cluster
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tenant-admin-binding
subjects:
  - kind: Group
    name: team-alpha-developers
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
---
# Restrict access to vCluster namespace in host cluster
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: vcluster-namespace-viewer
  namespace: team-alpha
rules:
  - apiGroups: ['']
    resources: ['pods', 'services', 'configmaps']
    verbs: ['get', 'list', 'watch']
  - apiGroups: ['']
    resources: ['pods/log']
    verbs: ['get']
  - apiGroups: ['apps']
    resources: ['statefulsets']
    verbs: ['get', 'list', 'watch']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: vcluster-namespace-viewer-binding
  namespace: team-alpha
subjects:
  - kind: Group
    name: team-alpha-developers
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: vcluster-namespace-viewer
  apiGroup: rbac.authorization.k8s.io

Host Cluster Resource Quota

To prevent the virtual cluster from consuming excessive resources from the host cluster, apply a ResourceQuota to the namespace where the virtual cluster runs.

# host-resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: vcluster-team-alpha-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: '8'
    requests.memory: '16Gi'
    limits.cpu: '16'
    limits.memory: '32Gi'
    pods: '50'
    services: '20'
    services.loadbalancers: '2'
    services.nodeports: '5'
    persistentvolumeclaims: '10'
    requests.storage: '100Gi'
    count/deployments.apps: '30'
    count/statefulsets.apps: '10'
    count/jobs.batch: '20'
    count/cronjobs.batch: '10'
---
apiVersion: v1
kind: LimitRange
metadata:
  name: vcluster-team-alpha-limits
  namespace: team-alpha
spec:
  limits:
    - type: Container
      default:
        cpu: '500m'
        memory: '512Mi'
      defaultRequest:
        cpu: '100m'
        memory: '128Mi'
      max:
        cpu: '4'
        memory: '8Gi'
      min:
        cpu: '50m'
        memory: '64Mi'
    - type: Pod
      max:
        cpu: '8'
        memory: '16Gi'
    - type: PersistentVolumeClaim
      max:
        storage: '50Gi'
      min:
        storage: '1Gi'

Network Isolation (NetworkPolicy)

In vCluster environments, network isolation is implemented at two layers. First, at the host cluster level, you control communication between virtual cluster namespaces, and additionally, you can apply fine-grained policies between workloads within the virtual cluster itself.

Host Cluster Level NetworkPolicy

# host-networkpolicy.yaml
# Block communication between virtual cluster namespaces
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: isolate-vcluster-namespace
  namespace: team-alpha
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    # Allow communication within the same namespace
    - from:
        - podSelector: {}
    # Allow traffic from Ingress controller
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
          podSelector:
            matchLabels:
              app.kubernetes.io/name: ingress-nginx
    # Allow metric collection from monitoring system
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: monitoring
          podSelector:
            matchLabels:
              app: prometheus
  egress:
    # Allow DNS queries
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
    # Allow communication within the same namespace
    - to:
        - podSelector: {}
    # Allow external internet access (if needed)
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 10.0.0.0/8
              - 172.16.0.0/12
              - 192.168.0.0/16

This NetworkPolicy isolates the virtual cluster's host namespace, blocking direct communication with other tenant namespaces. Simultaneously, it permits communication with essential infrastructure services such as the Ingress controller, monitoring system, and DNS.

Network Policy within Virtual Cluster

Within the virtual cluster, you can also apply network policies between microservices. NetworkPolicies defined within the virtual cluster are appropriately transformed and applied through the Syncer to the host cluster.

Monitoring Integration

Prometheus Metrics Collection

To configure monitoring for vCluster's control plane and workloads within the virtual cluster, the Prometheus in the host cluster must be able to scrape Pods in the virtual cluster's namespace.

You can collect metrics from the vCluster control plane by adding ServiceMonitor to the Prometheus in the host cluster. This includes metrics from the vCluster API Server, etcd, and Syncer synchronization status, providing comprehensive monitoring of control plane health. In particular, the Syncer's synchronization delay time and error rate are key indicators for determining virtual cluster stability.

Metrics from workloads within the virtual cluster can be collected either by having the host cluster's Prometheus directly scrape Pods in the namespace, or by installing a separate Prometheus within the virtual cluster. In multi-tenant environments, it's good practice to configure per-tenant Grafana dashboards, applying access controls so each team can only see their own workload status.

Alert Configuration Recommendations

In production environments, it is recommended to configure alerts for the following items:

  • vCluster control plane Pod restart count exceeds threshold
  • Syncer synchronization delay time exceeds 30 seconds
  • Virtual cluster namespace resource quota usage exceeds 80%
  • etcd data store disk usage exceeds 70%
  • vCluster API Server response time increases abnormally

Failure Cases and Recovery Procedures

Case 1: Pod Mismatch Due to Syncer Synchronization Failure

Symptom: You deleted a Deployment in the virtual cluster but orphan Pods remain in the host cluster. The list of Pods from kubectl get pods in the virtual cluster doesn't match the actual Pods in the host cluster.

Cause: This occurs when deletion events are not propagated due to Syncer Pod OOM Kill or network partition.

Recovery Procedure:

# 1. Identify orphan Pods in the host cluster
kubectl get pods -n team-alpha -l vcluster.loft.sh/managed-by=my-vcluster \
  --field-selector=status.phase=Running

# 2. Check if the Pod exists in the virtual cluster
vcluster connect my-vcluster -n team-alpha
kubectl get pods --all-namespaces

# 3. Manually delete orphan Pods that don't exist in the virtual cluster
vcluster disconnect
kubectl delete pod <orphan-pod-name> -n team-alpha --grace-period=30

# 4. Restart the Syncer Pod to restore synchronization state
kubectl rollout restart statefulset my-vcluster -n team-alpha

# 5. Verify synchronization state (review logs)
kubectl logs statefulset/my-vcluster -n team-alpha -c syncer --tail=100

Prevention Measures: Set sufficient resource requests/limits for the Syncer and configure a CronJob that periodically checks for resource consistency between the virtual cluster and host cluster.

Case 2: Virtual Cluster etcd Data Corruption

Symptom: The virtual cluster API Server fails to start, and the etcd container logs show errors like panic: freepages: failed to get all reachable pages or database file is not valid.

Cause: etcd data file becomes corrupted due to disk I/O errors in PersistentVolume, abnormal Pod termination, or storage backend failure.

Recovery Procedure:

  1. Scale down the virtual cluster's StatefulSet to replicas: 0.
  2. If a backup exists, replace the PVC data with the backup data.
  3. If no backup exists, delete the PVC and replace it with a new one, then recreate the virtual cluster. In this case, all metadata within the virtual cluster will be lost, but the actual workload Pods will continue running in the host cluster.
  4. Scale the StatefulSet back up to replicas: 1 and verify that it resynchronizes with the existing resources in the host cluster.

Prevention Measures: Configure regular snapshot backups of etcd data, and use a high-availability etcd cluster configuration in production environments.

Case 3: Workload Deployment Failure Due to Resource Quota Exceeded

Symptom: Pod creation fails within the virtual cluster, but instead of a forbidden: exceeded quota error, the Pod remains stuck in Pending state.

Cause: The ResourceQuota in the host cluster has been exceeded, but the error message is not properly propagated to the virtual cluster's events, making it difficult for tenants to identify the root cause.

Recovery Procedure:

  1. Check the ResourceQuota usage for the namespace in the host cluster: kubectl describe resourcequota -n team-alpha
  2. Clean up unnecessary resources or increase the quota.
  3. Enable event synchronization in the vCluster configuration so tenants can also see events from the host cluster.

Prevention Measures: Generate an alert when quota usage exceeds 80%, and configure a separate ResourceQuota within the virtual cluster for pre-emptive limitation.

Case 4: Network Isolation Failure Between Virtual Clusters

Symptom: Workloads from different virtual clusters can communicate directly because they share the same network in the host cluster.

Cause: NetworkPolicy is not configured on the host cluster, or the CNI plugin doesn't support NetworkPolicy (e.g., Flannel with default settings).

Recovery Procedure:

  1. Verify that the CNI plugin supports NetworkPolicy. Calico, Cilium, and WeaveNet support NetworkPolicy, while Flannel with default settings does not.
  2. Apply the NetworkPolicy presented in the network isolation section to the host namespace of each virtual cluster.
  3. Test isolation by creating test Pods to verify that communication to other namespaces is blocked.

Case 5: Virtual Cluster Upgrade Failure

Symptom: After upgrading the vCluster version via Helm, the virtual cluster API Server fails to start or compatibility issues occur with existing workloads.

Cause: API changes between major versions or Syncer protocol changes causing incompatibility.

Recovery Procedure:

  1. Always perform an etcd snapshot backup before upgrading.
  2. On failure, use helm rollback my-vcluster <previous-revision> -n team-alpha to rollback to the previous version.
  3. If issues persist after rollback, restore etcd data from the backup.

Prevention Measures: Test the upgrade in a staging environment first, and always review Breaking Changes in the official upgrade guide. In production environments, upgrade incrementally one step at a time.

Production Operation Checklist

Key items to verify when operating vCluster in a production environment:

Pre-Deployment Checks:

  • Verify that the CNI plugin supports NetworkPolicy (Calico, Cilium recommended)
  • Verify that ResourceQuota is applied to the virtual cluster namespace in the host cluster
  • Verify that vCluster control plane resource requests/limits are properly configured
  • Verify that PersistentVolume storage class and reclaim policy are correct
  • Verify that the kubeconfig distribution process for the virtual cluster is secure (OIDC integration recommended)

Monitoring During Operation:

  • Monitor Syncer synchronization delay time and error rate
  • Monitor CPU/memory usage of virtual cluster control plane
  • Monitor disk usage and compaction status of etcd data store
  • Monitor request delay time and error rate of virtual cluster API Server
  • Monitor resource quota usage for the host cluster namespace

Backup and Disaster Recovery:

  • Verify that etcd snapshot backup schedule is configured (at least once daily)
  • Verify that backup restoration procedure is tested quarterly
  • Verify that virtual cluster recreation procedure is automated (IaC)
  • Verify that virtual cluster recovery procedure in case of host cluster failure is documented

Security Checks:

  • Verify that virtual cluster user authentication/authorization is integrated with central IdP (OIDC, LDAP)
  • Verify that Node access permissions in the host cluster are not exposed to virtual cluster tenants
  • Verify that Pod Security Standards (PSS) are applied to prevent privileged container execution
  • Verify that network isolation between virtual clusters is tested periodically

Upgrade Procedure:

  • Perform etcd snapshot backup before vCluster version upgrade
  • Test upgrade in staging environment before production deployment
  • Verify Syncer synchronization status and workload normal operation after upgrade
  • Prepare rollback procedure and commands in advance

Conclusion

vCluster solves the fundamental limitations of Kubernetes multi-tenancy through an abstraction layer of virtual clusters. You can achieve requirements like CRD independence, API Server isolation, and per-tenant cluster management autonomy without adding physical clusters, which namespace-based isolation alone cannot fully satisfy.

However, without a thorough understanding of the Syncer operation mechanism and resource name rewriting, you may encounter unexpected issues during operations. It is recommended to conduct sufficient validation in a staging environment before deploying to production. In particular, network isolation and resource quota configuration must be applied together during the initial setup phase.

References