Skip to content

Namespace Isolation & Hierarchical Namespace Controller

Tại sao tổ chức namespace quan trọng ở scale

Khi bạn có 5 namespace, quản lý chúng thủ công không vấn đề gì. Khi bạn có 500 namespace cho 500 tenant, hoặc một tenant cần 10 namespace (frontend, backend, batch, staging...), mô hình namespace phẳng (flat) của Kubernetes trở thành nút thắt vận hành. Mỗi namespace cần RBAC RoleBinding, NetworkPolicy default-deny, ResourceQuota, LimitRange, Pod Security labels — và bạn phải áp dụng nhất quán cho hàng trăm namespace, đồng bộ khi policy thay đổi.

Đây là vấn đề propagation: làm sao đảm bảo mọi namespace của tenant X đều thừa kế cùng một bộ chính sách bảo mật, và khi platform team cập nhật chính sách, nó tự động lan tỏa? Namespace phẳng không có khái niệm "cha-con", nên không có propagation tự nhiên. Hierarchical Namespace Controller (HNC) giải quyết chính xác vấn đề này.

Internal model: namespace bao bọc cái gì và không bao bọc cái gì

Để dùng namespace đúng, phải biết chính xác ranh giới của nó. Tài nguyên Kubernetes chia thành hai loại:

Namespaced resources (bị namespace bao bọc): Pod, Deployment, Service, ConfigMap, Secret, ServiceAccount, Role, RoleBinding, NetworkPolicy, ResourceQuota, LimitRange, PVC, Ingress. Hai namespace có thể có Pod cùng tên api mà không xung đột. RBAC scoped theo namespace áp dụng cho các tài nguyên này.

Cluster-scoped resources (KHÔNG bị namespace bao bọc): Node, PersistentVolume, Namespace (bản thân nó), ClusterRole, ClusterRoleBinding, CustomResourceDefinition, StorageClass, PriorityClass, IngressClass. Các tài nguyên này dùng chung toàn cluster — đây là điểm rò rỉ tiềm năng trong multi-tenancy.

Hệ quả thực tế quan trọng cho multi-tenancy:

  1. CRD là cluster-scoped. Nếu một tenant được cấp quyền tạo CRD, họ ảnh hưởng toàn cluster. Đừng cấp quyền CRD cho tenant. Một CRD do tenant A tạo có thể conflict tên hoặc thay đổi hành vi cho tenant B.

  2. PriorityClass là cluster-scoped. Một tenant tạo PriorityClass giá trị cao có thể khiến Pod của họ preempt Pod của tenant khác. Phải kiểm soát ai được tạo/dùng PriorityClass nào (qua admission policy).

  3. StorageClass là cluster-scoped. Tenant chia sẻ StorageClass; phải đảm bảo reclaimPolicy và quyền truy cập không rò rỉ volume giữa tenant.

  4. PersistentVolume là cluster-scoped (PVC là namespaced). Cần cẩn thận với volume tái sử dụng — dữ liệu của tenant cũ có thể còn trên PV nếu reclaim policy sai.

Shared vs isolated resources: quyết định gì dùng chung

Trong một cluster multi-tenant, một số tài nguyên cố ý dùng chung (để hiệu quả), một số phải cách ly (để bảo mật). Đây là phân loại điển hình:

Tài nguyênChiến lượcLý do
Ingress controllerChia sẻ (platform namespace)Một LB chung tiết kiệm chi phí; phân tách bằng host/path
Monitoring/logging agentsChia sẻ (DaemonSet cluster-wide)Cần chạy trên mọi node
CoreDNSChia sẻ (bắt buộc)Cluster-level service
SecretsCách ly (per-namespace)Không tenant nào được đọc secret của tenant khác
ServiceAccountCách ly (per-namespace)Identity phải scoped theo tenant
ResourceQuotaCách ly (per-namespace)Fair allocation cần ranh giới rõ
NetworkPolicyCách ly (per-namespace)Default-deny phải áp dụng riêng từng namespace

Nguyên tắc: chia sẻ infrastructure (ingress, observability), cách ly identity và data (secrets, SA, quota).

Hierarchical Namespace Controller (HNC)

Vấn đề HNC giải quyết

Namespace của Kubernetes là phẳng — không có quan hệ cha-con. Nhưng tổ chức thực tế có cấu trúc cây: tenant acme có các team con, mỗi team có các môi trường con. Bạn muốn:

  • Một policy (RBAC RoleBinding, NetworkPolicy) gắn ở acme tự động áp dụng cho mọi namespace con của acme.
  • Tenant admin của acme được tự tạo namespace con mà không cần quyền tạo namespace ở cấp cluster (vốn là cluster-scoped và nguy hiểm).
  • Khi platform team cập nhật policy gốc, nó tự lan xuống toàn bộ cây.

HNC là một mở rộng của Kubernetes (open-source, từ nhóm sig-multitenancy, được tích hợp vào GKE qua Config Sync/Hierarchy Controller) tạo ra quan hệ phân cấp giữa các namespace và propagate các đối tượng được chọn từ namespace cha xuống con.

Mental model: cây namespace và propagation

acme (parent namespace)
│   ├── RoleBinding: acme-admins          ──┐
│   ├── NetworkPolicy: default-deny        ──┤ propagate xuống
│   └── ResourceQuota (qua HRQ)            ──┘ tất cả con

├── acme-frontend (subnamespace)
│   └── [tự động nhận] acme-admins, default-deny
├── acme-backend (subnamespace)
│   └── [tự động nhận] acme-admins, default-deny
└── acme-batch (subnamespace)
    └── [tự động nhận] acme-admins, default-deny

Các khái niệm chính:

  • Subnamespace: namespace con được tạo qua một SubnamespaceAnchor đặt trong namespace cha. Người có quyền trong namespace cha có thể tạo subnamespace mà không cần quyền cluster-level create namespace. Đây là điểm cốt lõi cho self-service tenant.

  • Propagated objects: HNC propagate các loại đối tượng được cấu hình — mặc định thường là RBAC Role/RoleBinding, và có thể cấu hình thêm NetworkPolicy, ResourceQuota (qua HierarchicalResourceQuota), LimitRange, Secret, ConfigMap. Đối tượng propagate là bản sao read-only trong namespace con (không sửa được tại con, chỉ sửa ở gốc).

  • Tree labels: HNC tự gắn label <ns>.tree.hnc.x-k8s.io/depth lên các namespace con, cho phép NetworkPolicy dùng namespaceSelector để khớp toàn bộ cây con của một tenant.

  • HierarchicalResourceQuota (HRQ): cho phép đặt quota ở cấp cha bao trùm tổng tiêu thụ của tất cả con — giải quyết hạn chế rằng ResourceQuota thường chỉ áp dụng một namespace.

Use case multi-tenancy với HNC

Self-service namespace cho tenant: Platform team tạo namespace gốc tenant-acme, gắn RBAC cho tenant admin của acme và một SubnamespaceAnchor quyền. Tenant admin acme tự tạo tenant-acme-prod, tenant-acme-dev mà không cần đụng đến platform team hay quyền cluster-level. Mọi namespace con tự thừa kế default-deny NetworkPolicy và RBAC từ gốc — không thể "quên" áp dụng policy.

Policy propagation nhất quán: Khi compliance yêu cầu mọi namespace của một tenant phải có một NetworkPolicy egress mới, platform team chỉ cần cập nhật ở namespace gốc của tenant; HNC propagate xuống toàn bộ cây. Không có drift giữa các namespace.

Cấu hình HNC trên GKE

Trên GKE, Hierarchy Controller được cung cấp như một phần của Config Sync (Anthos Config Management). Tương tác chính qua plugin kubectl-hns:

bash
# Tạo subnamespace dưới namespace cha
kubectl hns create acme-frontend -n acme

# Xem cây phân cấp
kubectl hns tree acme

# Cấu hình loại object được propagate
kubectl hns config set-resource networkpolicies --mode Propagate
kubectl hns config set-resource resourcequotas --mode Propagate

Ví dụ SubnamespaceAnchor (cách HNC biểu diễn quan hệ cha-con):

yaml
apiVersion: hnc.x-k8s.io/v1alpha2
kind: SubnamespaceAnchor
metadata:
  name: acme-frontend   # tên namespace con sẽ được tạo
  namespace: acme        # namespace cha

Lưu ý: theo tài liệu Config Sync, Hierarchy Controller đang được khuyến nghị thay thế bằng các pattern dựa trên Config Sync namespace inheritance trong các phiên bản mới hơn; hãy kiểm tra phiên bản và lộ trình trước khi áp dụng cho production.

Production architecture patterns

Pattern 1: Tenant root + subnamespace tree

Mỗi tenant có một namespace gốc do platform team quản lý, chứa toàn bộ policy nền tảng. Tenant tự tạo subnamespace cho các môi trường/dịch vụ của họ. Đây là pattern self-service chuẩn cho internal platform quy mô lớn (hàng trăm namespace).

Pattern 2: Flat namespace + GitOps propagation (thay thế HNC)

Nhiều tổ chức không dùng HNC mà thay bằng GitOps: mọi namespace và policy được định nghĩa trong Git, một controller (Config Sync, ArgoCD, Flux) reconcile. Propagation đạt được bằng templating (Kustomize/Helm) trong pipeline thay vì runtime controller. Ưu điểm: ít moving part runtime, audit trail qua Git. Nhược điểm: không có self-service runtime, mọi namespace mới qua PR.

Đây thực tế là hướng đi được ưa chuộng hiện nay vì HNC thêm một controller runtime cần vận hành, trong khi GitOps đã là tiêu chuẩn cho phần lớn platform team.

Common mistakes / anti-patterns

Anti-pattern 1: Một namespace khổng lồ cho nhiều tenant

Vì sao xảy ra: Đội bắt đầu nhỏ, nhồi nhiều ứng dụng/đội vào namespace default hoặc một namespace apps chung.

Hệ quả ở scale: Không thể áp RBAC, Quota, NetworkPolicy ở mức tenant vì tất cả nằm chung một namespace. Không có ranh giới nào. Mọi Pod thấy mọi Service qua DNS, mọi ServiceAccount nằm chung. Tách ra về sau cực kỳ tốn kém.

Cách phòng tránh: Một tenant tối thiểu một namespace ngay từ đầu. Không bao giờ dùng default cho workload production.

Anti-pattern 2: Quên rằng CRD/PriorityClass là cluster-scoped

Vì sao xảy ra: Đội cấp cho tenant một ClusterRole rộng (ví dụ edit ở cấp cluster) nghĩ rằng namespace sẽ giới hạn.

Hệ quả ở scale: Tenant tạo CRD conflict, hoặc PriorityClass giá trị cao để Pod của họ preempt tenant khác. Một tenant chiếm tài nguyên bằng cách tự nâng priority.

Cách phòng tránh: Không bao giờ cấp ClusterRole có quyền ghi tài nguyên cluster-scoped cho tenant. Kiểm soát PriorityClass qua admission policy (xem Chương 10).

Anti-pattern 3: Tin rằng HNC giải quyết bảo mật

Vì sao xảy ra: Nhầm HNC (công cụ tổ chức/propagation) với một cơ chế isolation bảo mật.

Hệ quả ở scale: HNC chỉ giúp áp dụng nhất quán các policy — nó không tự tạo isolation. Nếu các policy được propagate yếu (ví dụ không có default-deny NetworkPolicy), HNC chỉ propagate sự yếu kém đó một cách nhất quán. Bản thân quan hệ cha-con không cách ly gì.

Cách phòng tránh: Dùng HNC để propagate các policy đã được thiết kế đúng. Sức mạnh isolation đến từ NetworkPolicy/RBAC/PSA, HNC chỉ là cơ chế phân phối.

References