Ingress และ Gateway API
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”Ingress อธิบาย rule การ route HTTP(S) แบบ Layer-7 เพื่อพา traffic ภายนอกไปหา Service ภายใน แต่ rule พวกนั้นจะไม่ทำงานเลยจนกว่าจะมี Ingress controller รันอยู่จริงเพื่อ implement rule พวกนั้น
Ingress: rule การ route ไม่ใช่ router
หัวข้อที่มีชื่อว่า “Ingress: rule การ route ไม่ใช่ router”LoadBalancer Service ใช้ได้ดีกับแอปเดียว แต่การ provision cloud load balancer แยกต่อแอปนั้นแพง แถมยัง route ตาม hostname หรือ URL path ไม่ได้ด้วย Ingress แก้ปัญหานี้ที่ Layer 7 จุดเข้าเดียวที่ตรวจ HTTP request แล้ว route ตาม host กับ path
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: 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: 80manifest นั้นแสดงสองอย่างพร้อมกัน host-based routing (มีแค่ request ที่ยิงไปหา shop.example.com เท่านั้นที่ match rule นี้) และ path-based routing (/api ไปที่ Service หนึ่ง ที่เหลือทั้งหมดไปอีก Service หนึ่ง)
Ingress object เดี่ยว ๆ ไม่ทำอะไรเลย
หัวข้อที่มีชื่อว่า “Ingress object เดี่ยว ๆ ไม่ทำอะไรเลย”ตรงนี้คือจุดที่คนสับสนกันบ่อย การสร้าง Ingress object เฉย ๆ ไม่ทำให้ traffic ถูก route ไปไหนเลยด้วยตัวเอง Ingress เป็นแค่การประกาศ intent เท่านั้น ต้องพึ่ง Ingress controller ที่เป็น software แยกต่างหากที่รันอยู่จริงใน cluster (เช่น controller ที่ใช้ nginx, controller ของ cloud provider หรือตัวอื่น ๆ) คอย watch Ingress object แล้วเขียน proxy หรือ load balancer จริงให้ตรงตามนั้น ถ้าไม่มี controller รันอยู่ Ingress resource ก็แค่นอนเฉย ๆ ไม่มีผลอะไร
# An Ingress with no controller watching it accomplishes nothingkubectl get ingress shopkubectl 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/v1kind: IngressClassmetadata: name: nginxspec: controller: k8s.io/ingress-nginxGateway API: ตัวต่อยอดที่ยืดหยุ่นกว่า
หัวข้อที่มีชื่อว่า “Gateway API: ตัวต่อยอดที่ยืดหยุ่นกว่า”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/v1kind: Gatewaymetadata: name: shop-gatewayspec: gatewayClassName: example-gateway-class listeners: - name: http protocol: HTTP port: 80---apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: shop-routespec: 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"]