Table of Contents
- บทนำ (Introduction)
- Kubernetes Multi-tenancy คืออะไร?
- เหตุผลที่ต้องเป็น Kubernetes Multi-tenancy
- ทำไม Namespace ไม่สามารถทำ Isolation ได้จริง?
- Namespace เหมาะสำหรับ Use Cases แบบไหน?
- ถ้า Namespace ยังไม่ดีพอ มีทางเลือกอื่นหรือไม่?
- บทสรุป (Conclusion)
บทนำ (Introduction)
Kubernetes เริ่มจะเป็นเหมือนดวงอาทิตย์ของระบบ IT ในปัจจุบัน หลายบริษัทเริ่มใช้ Kubernetes ในการ host ระบบหรือ applications ต่าง ๆ มากขึ้น และเมื่อมีจำนวน cluster มากขึ้นก็เริ่มคิดถึงการแชร์ cluster เพื่อประหยัดค่าใช้จ่ายและเพื่อให้ง่ายต่อการดูแล
แต่คำถามคือเราจะแยก resources ระหว่าง tenants (ผู้ใช้งาน) ได้ยังไง? ซึ่งสิ่งแรกที่หลายคนนึกถึงก็คือการใช้ Kubernetes Namespaces เข้ามาช่วย แต่ความจริงแล้ว namespaces นั้นไม่สามารถทำ isolation ได้ดีอย่างที่หลายคนเข้าใจ ซึ่งเหตุผลคืออะไรและจะมีอะไรที่มาแทนได้นั้นเดี๋ยวมาว่ากันต่อไป
Kubernetes Multi-tenancy คืออะไร?
โดยทั่วไปแล้วคำว่า multi-tenancy ในโลกของ IT หมายถึงการที่ระบบ, platform หรือ application หนึ่งให้บริการแก่ผู้ใช้งาน (tenants) หลายรายพร้อมกันบน infrastructure เดียวกัน ซึ่ง tenant แต่ละรายจะต้องมีพื้นที่ของตัวเองแยกออกจากคนอื่นเพื่อความเป็นส่วนตัวของข้อมูล เช่น compute, network หรือ database
ในบริบทของ Kubernetes นั้น multi-tenancy จึงหมายถึงการที่เรามี Kubernetes cluster หนึ่งแล้วให้ tenants หลายรายมาใช้งานร่วมกัน ซึ่ง tenant ในที่นี้อาจจะเป็นทีมต่าง ๆ ภายในบริษัท, แผนก หรือแม้แต่ลูกค้าภายนอกเลยก็ได้
เหตุผลที่ต้องเป็น Kubernetes Multi-tenancy
การนำระบบต่าง ๆ มารวมไว้บน Kubernetes cluster เดียวกันมีข้อดีในแง่ของ…
- ประสิทธิภาพการใช้งาน Resources ดีขึ้น: เราสามารถแชร์ resources ที่มีอยู่ให้ tenants ต่าง ๆ ใช้งานร่วมกันได้ ซึ่งทำให้ราคาที่จ่ายคุ้มค่ากว่าการแยกของใครของมัน
- ความง่ายในการดูแล: แทนที่ admin จะต้องดูแลหลาย clusters การรวมมาที่ cluster เดียวก็ทำให้การดูแลง่ายขึ้น
- การแชร์ Service ต่าง ๆ: Tenants สามารถแชร์ services กันได้หรือทำได้ง่ายขึ้นเมื่ออยู่บน cluster เดียวกัน สามารถสร้างครั้งเดียวใช้ได้หลายคน เช่น Kubernetes Ingress หรือ observability stack เป็นต้น
- ลดค่าใช้จ่าย: ในแง่ของค่า support จาก distro ต่าง ๆ, ค่าบริการ nodes จาก cloud providers รวมถึงค่าใช้จ่ายในส่วนของ operations ที่ซ่อนอยู่อีก
ทำไม Namespace ไม่สามารถทำ Isolation ได้จริง?
เมื่อพูดถึงการแบ่งแยก tenants ระหว่างกัน หลายคนจะนึกถึงการใช้ namespaces ซึ่งเป็น feature พื้นฐานที่ใช้สำหรับการแยก resources อยู่แล้ว ซึ่งข้อดีของมันก็คือ…
- ง่ายและสะดวกในการตั้งค่า (configure) เพราะเป็นสิ่งที่ติดมากับ Kubernetes
- ใช้ resource น้อยมาก รวมถึงมีงานที่ต้องทำ (overhead) น้อยมากในการจัดการ
แต่ namespaces เองก็มาพร้อมกับข้อจำกัดหลายอย่าง ได้แก่
- Tenant อื่น ๆ สามารถมองเห็นและเข้าถึง resources ที่เป็น cluster-scoped ของเราได้ เช่น custom resource definitions (CRDs) หรือ persistent volumes
- สมมุติว่า tenant A สร้าง CRDs ขึ้นมา โดยอาจจะเป็น backup ของ Velero ซึ่งเป็น cluster-scoped ดังนั้น tenant อื่นก็สามารถเห็นหรือเข้าถึง backup ของ tenant A ได้เช่นกัน
- ในกรณีของ persistent volumes ถ้า tenant หนึ่งไปผูก (mount) persistent volume เข้ากับ pod ผ่าน persistent volume claim (PVC) แล้ว tenants อื่น ๆ ก็ยังสามารถสร้าง PVC ไป mount กับ persistent volume เดียวกันนั้นเพื่อเข้าถึงข้อมูลได้
- แม้การใช้ RBAC (Role-based Access Control) ก็อาจจะช่วยป้องกัน 2 ข้อด้านบนได้ก็จริง แต่ก็ต้องมีการกำหนด permissions ให้ดี ซึ่งเมื่อเจอกับ tenants จำนวนมากหรือมีการเปลี่ยนแปลงบ่อยก็อาจจะเกิดข้อผิดพลาดได้
- บาง tenants อาจมีการใช้ resources (CPU หรือ memory) มากเกินไปจนกระทบกับ tenants อื่น ๆ ได้
- เช่น หากเกิด memory leak ใน namespace หนึ่งจะกระทบกับ namespaces อื่นได้
- แม้เราสามารถใช้ resource quota หรือ limit range ในการจำกัดการใช้งาน CPU หรือ memory ของแต่ละ namespace ได้ แต่มันก็ยังมีข้อจำกัดอยู่ดี สมมุติว่าเรามี CPU อยู่ 10 cores กับ 5 namespaces เราสามารถหาร 5 เพื่อแบ่ง namespace ละ 2 cores ได้ แต่มันก็ไม่สามารถเกลี่ย resources ได้ดีพอเพราะบาง namespaces อาจต้องการแค่ 1 core ในขณะที่บาง namespaces อาจใช้มากกว่า 2 cores
- Namespaces ไม่ได้ทำ isolation ในระดับ kernel ดังนั้น containers ที่มี permissions มากเกินไป เช่น เป็น root หรือมี priviledge flags อาจสามารถเข้าถึง resources ใน namespaces อื่นได้
Namespace เหมาะสำหรับ Use Cases แบบไหน?
การแยก tenant ด้วย namespace อาจจะเพียงพอสำหรับในบางกรณีที่ความต้องการ isolation อยู่ในระดับที่ไม่สูงมาก
-
ทุก tenants อยู่ในองค์กรเดียวกันและเป็นทีมที่ไว้ใจกันได้ โดยอาจเป็น application ที่มีทีมหนึ่งดูแลในส่วนของ service A และอีกทีมดูแล service B ซึ่งอยู่บน cluster เดียวกันแต่แยกกันด้วย namespace
- แต่ถ้าเป็นคนละ business unit (BU) หรือคนละแผนกกัน เช่น ทีม HR กับทีม sales ที่ดูแลรับผิดชอบกันคนละ application การแยกด้วย namespace อย่างเดียวก็อาจจะไม่เพียงพอ(ก็ได้) เช่น ข้อมูลของทีม HR อาจจะเป็นสิ่งที่ sensitive มากสำหรับบริษัท
-
ไม่ใช่ production environment เช่น อาจเป็นแค่ dev/test environment ที่ยอมรับความเสี่ยงได้มากกว่า
-
Application ที่เป็น stateless โดยมีการอ่านข้อมูลเท่านั้น ไม่มีการเขียน state หรือข้อมูลสำคัญ เช่น เว็บแสดงข้อมูลทั่วไป
ถ้า Namespace ยังไม่ดีพอ มีทางเลือกอื่นหรือไม่?
ลองทำความเข้าใจตารางเปรียบเทียบนี้เพื่อให้เห็นภาพรวมก่อนครับ แล้วเดี๋ยวมาอธิบายกันต่อ
Namespace | HNC | Virtual Cluster | Cluster | |
---|---|---|---|---|
ระดับ Isolation (น้อย/มาก) | ★ | ★ | ★★★ | ★★★★★ |
ความยืดหยุ่นในการจัดการสำหรับ Tenant (น้อย/มาก) | ★ | ★ | ★★★★ | ★★★★★ |
การแชร์ Resource ร่วมกัน (ง่าย/ยาก) | ★★★★★ | ★★★★★ | ★★★ | ★ |
ความง่ายในการจัดการสำหรับ Admin (น้อย/มาก) | ★★★★★ | ★★★★★ | ★★★ | ★ |
ประหยัดค่าใช้จ่าย (น้อย/มาก) | ★★★★★ | ★★★★★ | ★★★ | ★ |
รวม | 17 | 17 | 16 | 12 |
- HNC คือ Hierarchical Namespace Controller
- ดาว (★) ยิ่งมาก = ยิ่งดี (สำหรับหัวข้อนั้น) แต่ไม่ได้แปลว่าดาวมากที่สุดคือ solution ที่ดีที่สุด
1. ใช้ Hierarchical Namespace Controller (HNC) เข้ามาช่วย
- HNC คือ Kubernetes addon ที่ช่วยให้เราสามารถจัดการ namespace แบบเป็นลำดับชั้น (hierarchy) ได้
- สมมุติเรามี namespace ชื่อ
team-a
และteam-b
เราสามารถสร้าง subnamespaces ย่อยลงไปอีกได้ เช่น
├── team-a
│ ├── team-a-project-1
│ └── team-a-project-2
└── team-b
├── team-b-project-1
└── team-b-project-2
- ถ้าเรากำหนด resource quota ไว้ที่
team-a
ว่าให้ใช้ CPU ได้ไม่เกิน 4 cores ทุก subnamespaces ของteam-a
ก็จะได้รับ quota CPU 4 cores ไปด้วยโดยอัตโนมัติ - หรือกำหนด RBAC ให้ user
nopnithi
เป็น admin ของteam-a
นั่นหมายความว่าnopnithi
ก็จะเป็น admin ของteam-a-project-1
และteam-a-project-2
ด้วยเช่นกัน - แต่ในส่วนข้อจำกัดอื่น ๆ ของ namespace ก็ยังคงเหมือนเดิมครับ
ที่จริงยังมี Capsule ที่เป็น open source ที่ช่วยเรื่องการจัดการ namespace สำหรับ multi-tenancy ด้วย และสิ่งที่เพิ่มมาจาก HNC คือมี proxy ที่ช่วยให้ tenant มองเห็นเฉพาะ namespace ตัวเอง
2. สร้าง Virtual Cluster โดยใช้ vCluster
- vCluster คือ open source project ที่ช่วยให้เราสร้าง virtual clusters ขึ้นมาภายใน Kubernetes cluster หลักได้
- แต่ละ virtual cluster จะมี control plane (API server, etcd หรือ controllers) ของตัวเองและมีการ sync resources บางอย่างระหว่างกัน ทำให้ได้ isolation ที่ดีกว่า namespace
- Tenant แต่ละรายจะเห็น virtual cluster เป็น Kubernetes cluster ปกติ ทำให้ควบคุมอะไรต่าง ๆ ได้ง่ายขึ้นเหมือนการสร้าง cluster แยก
- อย่างไรก็ตาม virtual cluster ก็ยังมีข้อจำกัดในการ isolate physical node อยู่ เพราะ pod ถูกสร้างบน cluster เดียวกัน
ที่จริงระหว่างขั้นที่ 2 และ 3 ยังมี project ชื่อ Karmada อยู่ด้วย แต่ส่วนตัวผมอาจจะยังไม่ได้มีโอกาสได้ลองใช้มันเท่าที่ควร
3. สร้าง Kubernetes Cluster แยกสำหรับแต่ละ Tenant
- เป็นวิธีที่ทำ isolation ได้แบบเบ็ดเสร็จที่สุด และมีอิสระในการจัดการ cluster ของตัวเองมากที่สุด
- แต่ก็ต้องแลกมาด้วยค่าใช้จ่ายที่สูงขึ้น ทั้งในแง่ของ resources และ operations ที่ต้องจัดการหลาย clusters
บทสรุป (Conclusion)
การเลือกใช้ namespace, virtual cluster หรือการแยก Kubernetes cluster ในการทำ multi-tenancy นั้นไม่มี solution ที่ดีที่สุด (one-size-fits-all) แต่ขึ้นอยู่กับความต้องการและข้อจำกัดของแต่ละองค์กร โดยปัจจัยที่ต้องคำนึงถึง คือ…
- ระดับของการ Isolate ที่ต้องการ
- Resources หรืองบประมาณที่มี
- ความยากง่ายในการดูแล Clusters
- ความยืดหยุ่นสำหรับ Tenant แต่ละราย (เช่น CRDs หรือเวอร์ชั่นของ cluster)
ถ้าไม่ได้มีข้อจำกัดอะไรเป็นพิเศษ การเลือกใช้ virtual cluster ก็ดูจะเป็นทางเลือกที่น่าสนใจเพราะให้ความสมดุลทั้งในแง่ของ isolation, resource utilization และการบริหารจัดการ cluster ที่ดีกว่าเมื่อเทียบกับ namespace ในขณะที่ค่าใช้จ่ายนั้นก็ยังไม่เยอะเท่ากับการสร้าง Kubernetes cluster แยกไปเลย หรือหากในบริบทที่ไม่ได้ต้องการ isolation แบบเข้มข้นนัก ผมคิดว่า HNC ก็น่าจะตอบโจทย์เช่นกัน