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 ก็น่าจะตอบโจทย์เช่นกัน