Kubernetes Services vs. Ingress มันต่างกันยังไงนะ?
บทความนี้เป็นเวอร์ชั่นเก่าแล้ว เวอร์ชั่นที่ถูกปรับปรุงใหม่จะถูกย้ายไปที่ Kubernetes Services และ Kubernetes Ingress ต่างกันยังไง? ครับ
และหลังจากนี้ผมจะเขียนบทความที่ nopnithi.com เป็นหลักครับ
อัพเดทล่าสุด: 4 Mar 2024
มือใหม่บางคนที่พึ่งเริ่มศึกษา Kubernetes อาจจะสับสนระหว่าง Service กับ Ingress ว่ามันต่างกันยังไง ใช้ใน use cases แบบไหนบ้าง ลองอ่านบทความนี้ดูครับ
ก่อนจะเริ่ม…รบกวนกด Like/Follow/Subscribe ให้ผมด้วยนะครับ 🙏
- 💙 Facebook: Nopnithi Tech
- ❤️ YouTube: Nopnithi Tech
- 💙 LinkedIn: Nopnithi (Game) Khaokaew
Introduction
บทความนี้เหมาะสำหรับผู้ใช้ Kubernetes มือใหม่และกำลังสับสนว่า Kubernetes Services กับ Kubernetes Ingress มันต่างกันยังไง โดยผมจะค่อย ๆ อธิบายรวมถึงยกตัวอย่าง application ขึ้นมาลอง deploy ในใจดู ทั้งแบบที่ “ไม่ใช้ Ingress” และ “ใช้ Ingress” เพื่อให้ทุกคนเห็นภาพความแตกต่างและประโยชน์ของ ingress
Table of Contents
- Introduction
- Kubernetes Services คืออะไร?
- ชนิดของ Kubernetes Services (Recap สั้น ๆ)
- [V.1] ลอง Deploy App (ในใจ) โดยใช้แค่ Services
- Kubernetes Ingress คืออะไร?
- [V.2] ลอง Deploy App (ในใจ) โดยใช้ Ingress มาช่วย
- Conclusion
Kubernetes Services คืออะไร?
Kubernetes Services คือ endpoint หรือ interface ของ pod (หรือกลุ่มของ pods) ที่ทำงานเดียวกันอยู่ พูดง่าย ๆ มันคือประตูนั่นแหละ แต่เป็นประตูขาเข้าเท่านั้น
การสร้าง service จึงเป็นการสร้างประตูให้ traffic จากข้างนอกสามารถเข้ามาพูดคุยกับ pod เจ้าของประตูได้ง่ายขึ้น
ลองคิดถึงเบอร์โทรศัพท์ 191 ว่าเป็น service ก็ได้ครับ ซึ่งเป็นเบอร์ที่เราทุกคนรู้ว่ามันใช้โทรหาตำรวจ (pod)
เราไม่จำเป็นต้องรู้ชื่อ (DNS name) ของตำรวจ ไม่ต้องรู้ว่าเบอร์โทรศัพท์ส่วนตัว (IP) ของเค้าคืออะไร เราไม่สนว่าจะมีตำรวจกี่นายที่กำลังทำงานอยู่หรือใครบ้างที่ลา (จำนวนของ pods)
ในมุมประชาชน (user) ถ้าเราต้องการจะคุยกับตำรวจก็แค่โทรไปที่ 191 เท่านั้น
ชนิดของ Kubernetes Services (Recap สั้น ๆ)
1. ClusterIP
เมื่อเราสร้าง ClusterIP
service, Kubernetes จะสร้าง virtual IP ให้กับ service นั้นโดยดึง IP มาจาก pool ที่ reserve เอาไว้ ทำให้ pods หรือ services อื่น ๆ ภายใน cluster สามารถ access service นี้ได้ผ่าน IP นั้น
ClusterIP
เหมาะสำหรับ expose service ที่คุยกันแค่ภายใน เช่น database, cache หรือพวก message queue (ไม่มีใครจากข้างนอกไปคุยกับมัน)
ยกเว้นกรณีที่เรามี Kubernetes Ingress ซึ่งเดี๋ยวผมจะอธิบายต่อไป
2. NodePort
เมื่อเราสร้าง NodePort
service ขึ้นมา, Kubernetes จะ reserve port หนึ่งขึ้นมาบน node ใน cluster ทุกตัว (โดยทั่วไปจะใช้ port 30000–32767) และ traffic ที่ถูกส่งมาด้วย node IP + port จะถูก forward เข้ามายัง service นั้น ซึ่งจะเป็น IP ของ node ใดก็ได้
เช่น
- [Node1] IP X.X.X.X Port 30000 จะ forward ไปที่ shopping cart
- [Node2] IP Y.Y.Y.Y Port 30000 ก็จะ forward ไปที่ shopping cart เช่นกัน
- [Node1] IP X.X.X.X Port 30001 จะถูก forward ไปที่ product catalog
NodePort
service เหมาะสำหรับใช้ในการ expose service ตัวเดียวออกไปเพื่อ test หรือ debug ระหว่างการพัฒนา app
3. LoadBalancer
เมื่อเราสร้าง LoadBalancer
service, Kubernetes จะสร้าง load balancer จริง ๆ ขึ้นมานอก cluster (ถ้าใช้ cloud มันก็สร้างขึ้นมาบน cloud platform) ทำให้ user จากข้างนอกสามารถ access เข้ามายัง service ของเราผ่าน load balancer IP
LoadBalancer
service เหมาะสำหรับใช้ในการ expose service ใน production ที่ต้องการให้ access มาจากข้างนอก Kubernetes หรือจาก public internet ได้ เช่น simple web app ที่ไม่ได้ซับซ้อน
ที่จริง Kubernetes ยังมี service อีกชนิดที่อาจจะไม่ค่อยได้พูดถึงกันโดยทั่วไปอย่าง
ExternalName
ซึ่งผมขอไม่ลงรายละเอียดนะครับ เอาเป็นว่ามันใช้ map service เข้ากับ DNS name (redirection) และไม่ได้ทำ load balancing แต่อย่างใด
[V.1] ลอง Deploy App (ในใจ) โดยใช้แค่ Services
สมมุติผมมี e-commerce app ซึ่งประกอบด้วย 4 ส่วน ได้แก่
- Frontend
- Product Catalog
- Shopping Cart
- PostgresSQL Database
ถ้าผมจะ deploy app นี้ด้วย Kubernetes services ก็อาจจะเลือก service ดังนี้
- Frontend service ใช้
LoadBalancer
เพราะ user จากข้างนอกจะเรียกเข้ามา - Catalog service ใช้
LoadBalancer
เพราะ user จากข้างนอกจะเรียกเข้ามา - Cart service ใช้
LoadBalancer
เพราะ user จากข้างนอกจะเรียกเข้ามา - Database service ใช้
ClusterIP
เพราะเรียกจาก service ข้างในด้วยกันเอง
อันนี้แค่ยกตัวอย่างนะครับ เพราะในความเป็นจริง product catalog service หรือ shopping cart service อาจจะไม่ได้ถูก expose ตรงไปหา public user ก็ได้ (อยู่หลัง frontend อีกที) ขึ้นอยู่กับ design ของแต่ละ app ครับ
และผมจะต้องสร้าง record จาก DNS ข้างนอกแบบนี้
nopnithi.tech
ชี้ไปหา load balancer IP ของ frontend serviceproducts.nopnithi.tech
ชี้ไปหา load balancer IP ของ catalog servicecart.nopnithi.tech
ชี้ไปหา load balancer IP ของ cart service
ซึ่งมันก็ใช้ได้นะ แต่ปัญหาคือ…
- เปลือง: ต้องเสียค่า load balancer ถึง 3 ตัว
- ยุ่งยาก: ต้องจัดการ DNS record ถึง 3 records
- มีข้อจำกัด: ไม่สามารถทำ URL path routing ได้ ต้องใช้ subdomain แทน เช่น
- ใช้nopnithi.tech/products
ไม่ได้ → ต้องใช้products.nopnithi.tech
- ใช้nopnithi.tech/cart
ไม่ได้ → ต้องใช้cart.nopnithi.tech
- (อาจจะ)วุ่นวาย: ถ้า load balancer IP เปลี่ยนขึ้นมาก็ต้องแก้ DNS record ใหม่ (ยกเว้นบน cloud ที่เรามักชี้ DNS ไปที่ load balancer DNS name)
ที่จริงเรื่อง URL path routing เราสามารถ deploy proxy ขึ้นมาทำได้เหมือนกัน ลดความยุ่งยากเรื่อง DNS record ด้วย แต่มันก็ต้องมาคอยดูแล proxy และยังคงเปลืองค่า load balancer อยู่ดีครับ
และเดี๋ยวลองมาดูว่า Kubernetes Ingress จะเข้ามาช่วยอะไรเราได้บ้าง
Kubernetes Ingress คืออะไร?
Kubernetes Ingress คือ traffic controller ตัวหนึ่งใน Kubernetes cluster ซึ่งมาแทรกอยู่ด้านหน้า services อื่น ๆ ทำหน้าที่รับ traffic จาก load balancer แล้วส่ง traffic ให้ service ต่าง ๆ ตาม routing rules
การจะใช้ Ingress ต้องมี 2 ส่วน (ผมไม่ได้ลงรายละเอียดนะครับ)
- Ingress Controller ซึ่งเราก็ต้อง deploy controller (เช่น NGINX, Traefik, HAProxy, etc.) ขึ้นมาก่อน โดยมาทำงานเสมือนเป็น proxy ให้เรา
- Ingress Resource คือการ configure ให้ controller ทำงานตามที่เราต้องการ โดยตัวนี้เป็น Kubernetes resource เหมือนกับพวก pods หรือ deployments
[V.2] ลอง Deploy App (ในใจ) โดยใช้ Ingress มาช่วย
ย้ำอีกครั้ง อันนี้แค่ยกตัวอย่างนะครับ เพราะในความเป็นจริง product catalog service หรือ shopping cart service อาจจะไม่ได้ถูก expose ตรงไปหา public user ก็ได้ (อยู่หลัง frontend อีกที) ขึ้นอยู่กับ design ของแต่ละ app ครับ
ผมจะเปลี่ยน services ทั้ง 3 ตัว (frontend, catalog, cart) จาก LoadBalancer
เป็น ClusterIP
ให้หมด เพราะจะใช้ load balancer ของ ingress ตัวเดียวในการ expose ออกไปข้างนอก cluster
และ DNS ก็จะเหลือแค่ 1 record ชี้ไปหา load balancer IP ของ ingress
และนี่สิ่งที่ได้หลังจากนำ ingress เข้ามาช่วย
- จากที่ต้องใช้ load balancer 3 ตัว ก็เหลือ 1 ตัว
- จัดการ DNS record เดียว โดยชี้มาที่ ingress
- สามารถทำ routing จาก URL path ได้ เช่น
-nopnithi.tech
→ frontend service
-nopnithi.tech/products
→ catalog service
-nopnithi.tech/cart
→ cart service - Configuration เกี่ยวกับ URL routing หรือ TLS สามารถทำที่ ingress ได้หมด และเก็บเป็น code (Kubernetes manifest) อยู่กับ manifest อื่น ๆ ได้ที่เดียว
ตัวอย่าง Ingress Manifest (ไม่รวม Ingress Controller)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nopnithi-shop-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: nopnithi.tech
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
- path: /products
pathType: Prefix
backend:
service:
name: catalog-service
port:
number: 80
- path: /cart
pathType: Prefix
backend:
service:
name: cart-service
port:
number: 80
Conclusion
Services และ Ingress หากมองผ่าน ๆ จะรู้สึกคล้ายกัน แต่ความเป็นจริงนั้นต่างกัน และมันไม่ได้มาแทนที่กัน แต่มาช่วยเสริมกันและกัน
เราอาจจะใช้แค่ Kubernetes Services ถ้า…
- Service ของเราคุยกันแค่ภายใน
- ต้องการ access เข้า service เพื่อ test หรือ debug ในขั้นตอนการพัฒนา
- เป็นแค่ service ที่เราต้องการ expose ให้ข้างนอกสามารถเข้าไปได้ตรง ๆ เช่น database หรือแม้แต่ simple web app
แต่เมื่อใดก็ตามที่เราต้องการ…
- จัดการหลาย ๆ services จากที่เดียว
- ทำ URL path-based routing
- ทำ SSL/TLS termination ง่าย ๆ
อันนี้ Kubernetes Ingress จะเข้ามาช่วยได้ และใช่ครับ…ส่วนมากเราก็มักจะได้ใช้ Ingress อยู่แล้วแหละ 😂
#Kubernetes, #DevOps, #Cloud, #Ingress, #Microservices
บทความนี้เป็นเวอร์ชั่นเก่าแล้ว เวอร์ชั่นที่ถูกปรับปรุงใหม่จะถูกย้ายไปที่ Kubernetes Services และ Kubernetes Ingress ต่างกันยังไง? ครับ
และหลังจากนี้ผมจะเขียนบทความที่ nopnithi.com เป็นหลักครับ