ข้ามไปยังเนื้อหา

Ingress และ Gateway API

Ingress อธิบาย rule การ route HTTP(S) แบบ Layer-7 เพื่อพา traffic ภายนอกไปหา Service ภายใน แต่ rule พวกนั้นจะไม่ทำงานเลยจนกว่าจะมี Ingress controller รันอยู่จริงเพื่อ implement rule พวกนั้น

LoadBalancer Service ใช้ได้ดีกับแอปเดียว แต่การ provision cloud load balancer แยกต่อแอปนั้นแพง แถมยัง route ตาม hostname หรือ URL path ไม่ได้ด้วย Ingress แก้ปัญหานี้ที่ Layer 7 จุดเข้าเดียวที่ตรวจ HTTP request แล้ว route ตาม host กับ path

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: shop.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-svc
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend-svc
port:
number: 80

manifest นั้นแสดงสองอย่างพร้อมกัน host-based routing (มีแค่ request ที่ยิงไปหา shop.example.com เท่านั้นที่ match rule นี้) และ path-based routing (/api ไปที่ Service หนึ่ง ที่เหลือทั้งหมดไปอีก Service หนึ่ง)

ตรงนี้คือจุดที่คนสับสนกันบ่อย การสร้าง Ingress object เฉย ๆ ไม่ทำให้ traffic ถูก route ไปไหนเลยด้วยตัวเอง Ingress เป็นแค่การประกาศ intent เท่านั้น ต้องพึ่ง Ingress controller ที่เป็น software แยกต่างหากที่รันอยู่จริงใน cluster (เช่น controller ที่ใช้ nginx, controller ของ cloud provider หรือตัวอื่น ๆ) คอย watch Ingress object แล้วเขียน proxy หรือ load balancer จริงให้ตรงตามนั้น ถ้าไม่มี controller รันอยู่ Ingress resource ก็แค่นอนเฉย ๆ ไม่มีผลอะไร

Terminal window
# An Ingress with no controller watching it accomplishes nothing
kubectl get ingress shop
kubectl get pods -n ingress-nginx # this is what actually does the routing

เวลามี controller ติดตั้งมากกว่าหนึ่งตัวใน cluster ingressClassName (ที่อิงกับ IngressClass object) จะบอก Kubernetes ว่า controller ตัวไหนควร implement Ingress ตัวนั้น

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
spec:
controller: k8s.io/ingress-nginx

Gateway API เป็นโมเดลใหม่กว่าที่แก้ปัญหาเดียวกัน แต่แยก role ชัดเจน สร้างจากสาม resource แทนที่จะเป็นตัวเดียว

  • GatewayClass implementation คล้าย ๆ กับ IngressClass (มาจาก vendor ของ controller)
  • Gateway listener จุดเข้าจริง (protocol, port, hostname) ปกติดูแลโดยทีม platform/infrastructure
  • HTTPRoute (และ GRPCRoute) rule การ route ที่ผูกกับ Gateway ปกติดูแลโดยทีม application
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shop-gateway
spec:
gatewayClassName: example-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: shop-route
spec:
parentRefs:
- name: shop-gateway
hostnames:
- "shop.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-svc
port: 80

การแยกแบบนี้มีประโยชน์จริง ทีม platform เป็นเจ้าของและคุม Gateway ได้ (ว่าเปิด port ไหน TLS certificate ไหน) ส่วนแต่ละทีม application เป็นเจ้าของ HTTPRoute ของตัวเองได้อย่างปลอดภัย โดยไม่ต้องมีสิทธิ์เข้าถึง listener ที่ใช้ร่วมกันเลย Gateway, GatewayClass และ HTTPRoute (พร้อมกับ GRPCRoute) เข้าสู่ General Availability แล้วที่ gateway.networking.k8s.io/v1 และ Gateway API คือทิศทางที่ ecosystem กำลังมุ่งไปสำหรับความต้องการ routing ที่ซับซ้อนขึ้น แต่ Ingress ก็ยังถูกใช้กันแพร่หลายมาก ยังได้รับ support เต็มที่ และเหมาะมากพอสำหรับการ route แบบ host/path ตรงไปตรงมา ไม่มีตัวไหนกำลังจะหายไปในเร็ว ๆ นี้

flowchart LR
  ext["External client"] --> ctrl["Ingress controller\n(e.g. nginx)"]
  ctrl -->|"host/path rules"| ing["Ingress object"]
  ing --> svcA["Service: api-svc"] --> podA["Pods"]
  ing --> svcB["Service: frontend-svc"] --> podB["Pods"]
Traffic ภายนอกผ่าน Ingress controller ไปยัง Service และ Pod ภายใน
ทำไมการสร้าง Ingress object เดี่ยว ๆ ถึงไม่ทำให้ traffic ถูก route
host-based routing กับ path-based routing ใน Ingress rule ต่างกันยังไง
ใน Gateway API HTTPRoute ทำหน้าที่อะไร
GatewayClass, Gateway และ HTTPRoute สัมพันธ์กันยังไง