TL;DR
- Ingress Overview: เป็น L7 load balancer หลักๆ มี GCE, Nginx, HAProxy และ Traefix เป็นต้น
-
Ingress Controller: เป็น controller ที่ monitor URI
/ingresses
ของ API server เพื่อนำมา configure rule - Nginx: เป็น Ingress Controller ที่ใช้ Nginx เป็น reverse proxy
- Google Load Balancer Controller (GLBC): เป็น reverse proxy ของ Google ใช้งานได้บน Goole Cloud ทั้ง GCE และ GKE
- Ingress API Resources: แสดง YAML file ในการสร้าง Ingress
- Deploying the Ingress Controller: แสดงการ setup Nginx Ingress
- Creating an Ingress Rule: สร้าง rule และทำสอบ Nginx Ingress
- Multiple Rules: สร้าง rule แบบ multi-domain และทำสอบ
- Intelligent Connected Proxies: คือ service mesh เช่น Istio, Enovy และ Linkerd
Ingress Overview
ใน article ก่อนหน้านี้ เราได้เรียนรู้เกี่ยวกับ Service ซึ่งใช้ในการ expose application ให้ client ที่อยู่นอก cluster ใช้งานได้ ในบทนี้เราจะเรียนรู้เกี่ยวกับ Ingress Controllers และ Rules ซึ่งทำหน้าที่เดียวกัน แต่ต่างกันที่ประสิทธิภาพ แทนที่จะต้องใช้ load balancer เป็นตัวช่วย Ingress สามารถทำแบบนั้นได้เลย ไม่ว่าจะเป็น route ตาม domain หรือ URI Path
Ingress Controllers ไม่ได้เป็นส่วนหนึ่งของ kube-controller-manager
binary แต่มันจะมี controller เป็นของตัวเอง ซึ่งก็มีได้หลาย controller โดย controller จะใช้ Ingress Rules ในการจัดการกับ traffic ทั้งขาเข้าและขาออก
Ingress รองรับ 2 controllers หลัก คือ GCE และ nginx จริงๆ แล้ว tool อื่นที่ทำหน้าที่เป็น reverse proxy เช่น HAProxy และ Traefix ก็ใช้งานได้ โดยมันจะ route traffic มายัง Service ที่ on แบบ ClusterIP
ได้เลยตาม Ingress Rule ที่เรา configure ไว้
Ingress Controller
Ingress Controller อยู่ใน networking.k8s.io/v1beta1
resource group เป็น daemon ที่ run ใน Pod ซึ่งจะคอย monitor การเปลี่ยนแปลงของ /ingresses
บน kube-apiserver
ถ้าหากพบการเปลี่ยนแปลง มันจะไป configure rules เพื่อ support ให้ โดย traffic ส่วนใหญ่จะเป็น HTTP วิธีนี้จะทำให้สามารถเข้าถึง Services ได้ โดยไม่ต้องสนใจว่า Pods นั้นถูก deploy ไว้ที่ node ไหน
เราสามารถ deploy Ingress Controller ได้มากกว่า 1 controller ใน cluster เดียวกัน traffic จะใช้ annotation
ในการเลือก controller ทีละตัวจนกว่าจะพบตัวที่เหมาะสม
Nginx
การ deploy Nginx Controller สามารถดูตัวอย่างของหลากหลาย platform ได้จาก ingress-nginx
เราสามารถ configure Nginx Controller ได้ผ่านทาง ConfigMap
และ Annotations
แต่ถ้ายังไม่พอใจเราสามารถ configure จาก custom template
ได้ด้วย
คุณสมบัติของ Nginx Controller
- integrate กับ RBAC ได้ง่าย
- ใช้ annotation
kubernetes.io/ingress.class: "nginx"
- ถ้าจะใช้เป็น L7 revere proxy ต้องระบุ
proxy-real-ip-cidr
ด้วย - ถ้าจะใช้ feature session affinity ต้อง bypass
kube-proxy
- ไม่ได้ใช้
conntrack
ที่เกิดจาก DNAT ของ iptables - ถ้าจะให้ terminate TLS ให้ต้องระบุุ host field ด้วย
Google Load Balancer Controller (GLBC)
GLBC คือ GCE L7 load balancer controller ที่จัดการ external loadbalancers ด้วย Kubernetes Ingress API
ในสร้าง 1 Ingress ต้องมี cloud resource เหล่านี้
- Global Forwarding Rule: เป็นตัว manage VIP ของ Ingress
- TargetHttpProxy: เป็นตัว manage SSL certs และ proxy ระหว่าง VIP และ Backend
- URL Map: routing rules
- Backend Service: รวม หลายๆ Instance Groups เป็น 1 Service Node Port
- Instance Group: VM ที่ เป็น kubernetes node
Pipeline เป็นแบบนี้
โดย
- แต่ละ Backend Service ต้องทำการ health check ไปยัง NodePort ของ Service
- แต่ละ port ของ Backend Service ต้องตรงกับ Instance Group
- แต่ละ port ของ Backend Service จะถูก expose ผ่าน firewall บน GCE LB IP ranges (130.211.0.0/22 and 35.191.0.0/16)
ตอนนี้ Ingress สามารถใช้ TLS และ TLS termination ที่ port 443 และยังไม่ support SNI
Ingress API Resources
Ingress object ยังเป็น extension API มีตัวอย่าง YAML file ดังนี้
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ghost
spec:
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
serviceName: test
servicePort: 80
เราสามารถ manage มันได้ดังนี้
$ kubectl get ingress
$ kubectl delete ingress <ingress_name>
$ kubectl edit ingress <ingress_name>
Deploying the Ingress Controller
ในการ deploy Nginx Ingress ทำได้ง่ายๆ โดย ดูได้จาก Github
ในตัวอย่างจะขอ install แบบ Bare-Metal โดยใช้ NodePort ดังนี้
# Install
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
namespace/ingress-nginx created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
deployment.apps/nginx-ingress-controller created
limitrange/ingress-nginx created
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
service/ingress-nginx created
# Verify
$ kubectl get pods --all-namespaces -l app.kubernetes.io/name=ingress-nginx --watch
NAMESPACE NAME READY STATUS RESTARTS AGE
ingress-nginx nginx-ingress-controller-7f74f657bd-9fm44 1/1 Running 0 82s
Creating an Ingress Rule
-
ทำการ create deployment และ expose service ที่ port 2368
$ kubectl create deployment ghost --image=ghost deployment.apps/ghost created $ kubectl expose deployment ghost --port 2368 service/ghost exposed $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/ghost ClusterIP 10.107.189.29 <none> 2368/TCP 11s service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 74d $ kubectl get pods NAME READY STATUS RESTARTS AGE pod/ghost-577564ddbd-nfqrc 1/1 Running 0 178m
-
ทำการสร้าง ingress rule โดย request ที่เข้ามา domain เป็น "ghost.192.168.99.100.nip.io" ให้ส่งไปที่ service
ghost
$ cat > ingress.yaml << EOF apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: ghost spec: rules: - host: ghost.192.168.99.100.nip.io http: paths: - backend: serviceName: ghost servicePort: 2368 EOF $ kubectl create -f ingress.yaml ingress.networking.k8s.io/ghost created $ kubectl get ingress NAME HOSTS ADDRESS PORTS AGE ghost ghost.192.168.99.100.nip.io 80 20s $ kubectl describe ingress/ghost Name: ghost Namespace: default Address: 10.107.151.119 Default backend: default-http-backend:80 (<none>) Rules: Host Path Backends ---- ---- -------- ghost.192.168.99.100.nip.io ghost:2368 (192.168.32.59:2368) Annotations: Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 3m12s nginx-ingress-controller Ingress default/ghost Normal UPDATE 2m40s nginx-ingress-controller Ingress default/ghost
-
ทำการ test ดูซิว่าถ้า doamin เป็น ghost.192.168.99.100.nip.io จะวิ่งไปที่ service
ghost
หรือไม่ โดยถ้าไปใช่ต้องได้ page ที่มี title เป็น ghost
$ curl -v -H 'host: ghost.192.168.99.100.nip.io' http://10.107.151.119:80 -o /dev/null <title>Ghost</title>
Multiple Rules
-
ทำการ create deployment ชื่อ nginx และ expose service ที่ port 80
$ kubectl create deployment nginx --image=nginx deployment.apps/nginx created $ kubectl expose deployment nginx --port 80 service/nginx exposed $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ghost ClusterIP 10.107.189.29 <none> 2368/TCP 12m kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 74d nginx ClusterIP 10.106.200.39 <none> 80/TCP 29s $ kubectl get pods NAME READY STATUS RESTARTS AGE ghost-577564ddbd-nfqrc 1/1 Running 0 3h11m nginx-86c57db685-vb6gk 1/1 Running 0 63s
-
ทำการ update ingress rule โดย เพิ่มให้ request ที่มี domain เป็น "nginx.192.168.99.100.nip.io" ให้ส่งไปที่ service
nginx
$ cat > ingress-2.yaml << EOF apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: ghost spec: rules: - host: ghost.192.168.99.100.nip.io http: paths: - backend: serviceName: ghost servicePort: 2368 - host: nginx.192.168.99.100.nip.io http: paths: - backend: serviceName: nginx servicePort: 80 EOF $ kubectl apply -f ingress-2.yaml ingress.networking.k8s.io/ghost configured $ kubectl get ingress NAME HOSTS ADDRESS PORTS AGE ghost ghost.192.168.99.100.nip.io,nginx.192.168.99.100.nip.io 10.107.151.119 80 10m $ kubectl describe ingress/ghost Name: ghost Namespace: default Address: 10.107.151.119 Default backend: default-http-backend:80 (<none>) Rules: Host Path Backends ---- ---- -------- ghost.192.168.99.100.nip.io ghost:2368 (192.168.32.59:2368) nginx.192.168.99.100.nip.io nginx:80 (192.168.52.65:80) Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"networking.k8s.io/v1beta1","kind":"Ingress","metadata":{"annotations":{},"name":"ghost","namespace":"default"},"spec":{"rules":[{"host":"ghost.192.168.99.100.nip.io","http":{"paths":[{"backend":{"serviceName":"ghost","servicePort":2368}}]}},{"host":"nginx.192.168.99.100.nip.io","http":{"paths":[{"backend":{"serviceName":"nginx","servicePort":80}}]}}]}} Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal CREATE 10m nginx-ingress-controller Ingress default/ghost Normal UPDATE 79s (x2 over 9m50s) nginx-ingress-controller Ingress default/ghost
-
ทำการ test ดูซิว่า
- ถ้า doamin เป็น ghost.192.168.99.100.nip.io จะต้องวิ่งไปที่ service
ghost
- ถ้า doamin เป็น nginx.192.168.99.100.nip.io จะต้องวิ่งไปที่ service
nginx
$ curl -s -H 'host: ghost.192.168.99.100.nip.io' http://10.107.151.119:80 | grep '<title>' <title>Ghost</title> $ curl -s -H 'host: nginx.192.168.99.100.nip.io' http://10.107.151.119:80 | grep '<title>' <title>Welcome to nginx!</title>
- ถ้า doamin เป็น ghost.192.168.99.100.nip.io จะต้องวิ่งไปที่ service
Intelligent Connected Proxies
ในกรณีที่ต้องการ feaature ที่เพิ่มขึ้น เช่น service discovery, rate limiting, traffic management หรือ advanced metric เราต้องเปลี่ยนมาใช้ service mesh โดย มันจะประกอบด้วย edge proxy และ embeded proxy ซึ่งจะทำงานร่วมกันเพื่อจักการ traffic ตาม rules ที่มาจาก control plane ตัวอย่างของ service mesh เช่น
- Envoy: เป็น proxy ที่มีการออกแบบแบบ modular และ extensible มักถูกใช้เป็น data plane ของ tool อื่นๆ ของ service mesh
-
Istio: เป็น tool ที่ช่วยเพิ่มความสามารถของ Envoy ด้วยการมี control plane ได้มากกว่า 1 ตัว เป็นตัวที่ทำให้ service mesh flexible ขึ้นและมี feature มากขึ้น
Linkerd: เป็นอีกหนึ่ง service mesh ที่ออกแบบมาให้่ใช้งานได้ง่าย เร็ว และ เบา
Top comments (0)