原文:https://segmentfault.com/a/1190000019908991
文章目錄
k8s ingress原理
但是,單獨用service暴露服務的方式,在實際生產環境中不太合適
ClusterIP的方式只能在集羣內部訪問。
NodePort方式的話,測試環境使用還行,當有幾十上百的服務在集羣中運行時,NodePort的端口管理是災難。
LoadBalance方式受限於雲平臺,且通常在雲平臺部署ELB還需要額外的費用。
ingress可以簡單理解爲service的service,他通過獨立的ingress對象來制定請求轉發的規則,把請求路由到一個或多個service中。這樣就把服務與請求規則解耦了,可以從業務維度統一考慮業務的暴露,而不用爲每個service單獨考慮。
舉個例子,現在集羣有api、文件存儲、前端3個service,可以通過一個ingress對象來實現圖中的請求轉發:
ingress與ingress-controller
要理解ingress,需要區分兩個概念,ingress和ingress-controller:
- ingress對象:
指的是k8s中的一個api對象,一般用yaml配置。作用是定義請求如何轉發到service的規則,可以理解爲配置模板。 - ingress-controller:
具體實現反向代理及負載均衡的程序,對ingress定義的規則進行解析,根據配置的規則來實現請求轉發。
簡單來說,ingress-controller纔是負責具體轉發的組件,通過各種方式將它暴露在集羣入口,外部對集羣的請求流量會先到ingress-controller,而ingress對象是用來告訴ingress-controller該如何轉發請求,比如哪些域名哪些path要轉發到哪些服務等等。
ingress-controller
ingress-controller並不是k8s自帶的組件,實際上ingress-controller只是一個統稱,用戶可以選擇不同的ingress-controller實現,目前,由k8s維護的ingress-controller只有google雲的GCE與ingress-nginx兩個,其他還有很多第三方維護的ingress-controller,具體可以參考官方文檔。但是不管哪一種ingress-controller,實現的機制都大同小異,只是在具體配置上有差異。一般來說,ingress-controller的形式都是一個pod,裏面跑着daemon程序和反向代理程序。daemon負責不斷監控集羣的變化,根據ingress對象生成配置並應用新配置到反向代理,比如nginx-ingress就是動態生成nginx配置,動態更新upstream,並在需要的時候reload程序應用新配置。爲了方便,後面的例子都以k8s官方維護的nginx-ingress爲例。
ingress
ingress是一個API對象,和其他對象一樣,通過yaml文件來配置。ingress通過http或https暴露集羣內部service,給service提供外部URL、負載均衡、SSL/TLS能力以及基於host的方向代理。ingress要依靠ingress-controller來具體實現以上功能。前一小節的圖如果用ingress來表示,大概就是如下配置:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: abc-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
tls:
- hosts:
- api.abc.com
secretName: abc-tls
rules:
- host: api.abc.com
http:
paths:
- backend:
serviceName: apiserver
servicePort: 80
- host: www.abc.com
http:
paths:
- path: /image/*
backend:
serviceName: fileserver
servicePort: 80
- host: www.abc.com
http:
paths:
- backend:
serviceName: feserver
servicePort: 8080
與其他k8s對象一樣,ingress配置也包含了apiVersion、kind、metadata、spec等關鍵字段。有幾個關注的在spec字段中,tls用於定義https密鑰、證書。rule用於指定請求路由規則。這裏值得關注的是metadata.annotations字段。在ingress配置中,annotations很重要。前面有說ingress-controller有很多不同的實現,而不同的ingress-controller就可以根據"kubernetes.io/ingress.class:"來判斷要使用哪些ingress配置,同時,不同的ingress-controller也有對應的annotations配置,用於自定義一些參數。列如上面配置的’nginx.ingress.kubernetes.io/use-regex: “true”’,最終是在生成nginx配置中,會採用location ~來表示正則匹配。
ingress的部署
ingress的部署,需要考慮兩個方面:
- ingress-controller是作爲pod來運行的,以什麼方式部署比較好
- ingress解決了把如何請求路由到集羣內部,那它自己怎麼暴露給外部比較好
Deployment+LoadBalancer模式的Service
如果要把ingress部署在公有云,那用這種方式比較合適。用Deployment部署ingress-controller,創建一個type爲LoadBalancer的service關聯這組pod。大部分公有云,都會爲LoadBalancer的service自動創建一個負載均衡器,通常還綁定了公網地址。只要把域名解析指向該地址,就實現了集羣服務的對外暴露。
Deployment+NodePort模式的Service
同樣用deployment模式部署ingress-controller,並創建對應的服務,但是type爲NodePort。這樣,ingress就會暴露在集羣節點ip的特定端口上。由於nodeport暴露的端口是隨機端口,一般會在前面再搭建一套負載均衡器來轉發請求。該方式一般用於宿主機是相對固定的環境ip地址不變的場景。
NodePort方式暴露ingress雖然簡單方便,但是NodePort多了一層NAT,在請求量級很大時可能對性能會有一定影響。
DaemonSet+HostNetwork+nodeSelector
用DaemonSet結合nodeselector來部署ingress-controller到特定的node上,然後使用HostNetwork直接把該pod與宿主機node的網絡打通,直接使用宿主機的80/433端口就能訪問服務。這時,ingress-controller所在的node機器就很類似傳統架構的邊緣節點,比如機房入口的nginx服務器。該方式整個請求鏈路最簡單,性能相對NodePort模式更好。缺點是由於直接利用宿主機節點的網絡和端口,一個node只能部署一個ingress-controller pod。比較適合大併發的生產環境使用。
ingress測試
我們來實際部署和簡單測試一下ingress。測試集羣中已經部署有2個服務gowebhost與gowebip,每次請求能返回容器hostname與ip。測試搭建一個ingress來實現通過域名的不同path來訪問這兩個服務:
1.什麼是反向代理與負載均衡器:https://www.nginx.com/resources/glossary/reverse-proxy-vs-load-balancer/
2.什麼是第7層負載平衡:https://www.nginx.com/resources/glossary/layer-7-load-balancing/
3.負載均衡基礎知識:https://www.cnblogs.com/danbing/p/7459224.html