k8s ingress原理

原文: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的部署,需要考慮兩個方面:

  1. ingress-controller是作爲pod來運行的,以什麼方式部署比較好
  2. 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章