kubernetes對象之Ingress


系列目錄

概述

向外網暴露集群內服務,以使客戶端能夠訪問,有以下幾種方法,本文重點描述Ingress。

LoadBalancer

LoadBalancer一般由雲服務供應商提供或者用戶自定義,運行在集群之外。在創建service時為其配置LoadBalancer相關參數,當從外網訪問集群內servcie時,用戶直接連接到LoadBalancer服務器,LoadBalancer服務器再將流量轉發到集群內service。Loadbalancer配置及使用方法與各雲服務供應商有關,本文不詳細描述。

NodePort

這種方式要求集群中部分節點有被外網訪問的能力。Kubernetes為每個NodePort類型的服務在集群中的每個節點上分配至少一個主機網絡端口號。客戶通過能被外網訪問的節點IP加上節點端口的方式訪問服務。大多數情況下不會通過這種方式向集群外暴露服務,原因有四。

  • 其一:大多情況下,為了安全起見,集群中的節點位於完全內網環境中,不應該有被外網直接訪問的能力。一般外網訪問集群中的節點都是通過邊界服務器如網關、跳板等,而這種邊界服務器需要通過各種方式進行安全加固。

  • 其二:如果集群內節點可以從外網直接訪問的話,則會將集群內節點地址、服務名稱、端口號等信息直接暴露在外,非常不安全。

  • 其三:服務端口號一般由系統自動分配,並非固定,而服務名稱也可能發生變更,此時外部客戶端需要跟蹤變更並修改,屬於重試耦合。

  • 其四:這種方式,每個服務至少向外網暴露一個端口號,當服務很多時不易於管理。

Ingress

Ingress不是某種產品、組件的名稱,它應該是kubernetes向集群外暴露服務的一種思路、技術,用戶完全可以根據這種思路提供自己的Ingress實現,當然kubernetes提供了默認Ingress實現還有其它第三方實現,一般無需自己開發。它的思路是這樣的,首先在集群內運行一個服務或者pod也可以是容器,不管是什么它至少應該有一個外網可以訪問的IP,至少向外網開放一個端口號,讓它充當反向代理服務器。當外網想要訪問集群內service時,只需訪問這個反向代理服務器並指定相關參數,代理服務器根據請求參數並結合內部規則,將請求轉發到service。這種思路與LoadBalancer的不同之處是它就位於集群內,而LoadBalancer位於集群外。與NodePort的不同之處是集群只向外暴露一個服務或者pod等,而NodePort是暴露全部service。

Kubernetes用nginx實現反向代理服務器,稱為Ingress Controller,是pod類型資源。同時提供了Ingress類型對象,通過創建Ingress對象配置nginx反向代理服務器的轉發規則。Nginx反向代理服務器收到來自外網的請求后,用請求的URL地址、請求頭字段區別不同service,然后轉發請求。

部署Ingress Controller

在Kubernetes中,Ingress Controller典型是pod類型資源,其部署方式與普通pod相同,通過Deployment、DaemonSet等副本控制器部署,其中更值推薦的是DaemonSet方式。Ingress Controller需要部署在具備連通外網能力的節點上,首先在目標節點打上Ingress Controller專用標簽,然后在DaemonSet的配置文件中配置節點選擇器選中此類標簽,控制pod實例可以部署的節點,通過為節點增減相關標簽控制Ingress Controller的pod實例個數。Ingress Controller一般占用兩個節點主機端口,http用80,https用443。詳細參考:這里。外網通過http://節點外網ip:80/...或者https://節點外網ip:80/...就可以訪問內部服務了,當前首先需要創建Ingress對象配置訪問策略。

創建Ingress對象

本節通過創建各種Ingress對象,展示Ingress的各種典型用法。

Single Service Ingress

配置文件:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
spec:
  backend:
    serviceName: testsvc
    servicePort: 80

然后通過kubectl create -f創建對象,這同創建一般對象並沒有很多區別,前面已經多次提到過,這里不再詳細描述

查看對象:

$ kubectl get ing
NAME                RULE          BACKEND        ADDRESS
test-ingress        -             testsvc:80     107.178.254.228

以上配置中沒有具體的rule,所以諸如http(s)😕/107.178.254.228/xxx之類的請求都轉發到testsvc的80端口。

其於URL轉發(Simple fanout)

假如要實現以下目標:

foo.bar.com -> 178.91.123.132 -> / foo    s1:80
                                 / bar    s2:80

其中foo.bar.com是http請求體頭部中的host字段,178.91.123.132是Ingress Controller外網地址,當請求路徑與/foo匹配時轉發到s1服務的80端口,當與/bar匹配時轉發到s2服務的80端口,其最核心邏輯是用URL區分不同服務。

配置如下:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        backend:
          serviceName: s1
          servicePort: 80
      - path: /bar
        backend:
          serviceName: s2
          servicePort: 80

查看對象:

$ kubectl get ing
NAME      RULE          BACKEND   ADDRESS
test      -
          foo.bar.com
          /foo          s1:80
          /bar          s2:80

基於名稱的虛擬主機(Name based virtual hosting)

實現如下目錄:

foo.bar.com --|                 |-> foo.bar.com s1:80
              | 178.91.123.132  |
bar.foo.com --|                 |-> bar.foo.com s2:8

這種方式的核心邏輯是用http請求中的host字段區分不同服務,而不是URL。如host: foo.bar.com的請求被轉發到s1服務80端口,如host: bar.foo.com的請求被轉發到s2服務80端口。

配置:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          serviceName: s1
          servicePort: 80
  - host: bar.foo.com
    http:
      paths:
      - backend:
          serviceName: s2
          servicePort: 80
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          serviceName: s1
          servicePort: 80
  - host: bar.foo.com
    http:
      paths:
      - backend:
          serviceName: s2
          servicePort: 80

TLS

利用Secret類型對象為Ingress Controller提供私鑰及證書,對通信鏈路加密。

Secret配置:

apiVersion: v1
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
kind: Secret
metadata:
  name: testsecret
  namespace: default
type: Secret

在Ingress對象中引用

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: no-rules-map
spec:
  tls:
  - secretName: testsecret
  backend:
    serviceName: s1
    servicePort: 80
** 更新Ingress對象**

使用kubectl edit命令編輯Ingress實時對象:

$ kubectl get ing
NAME      RULE          BACKEND   ADDRESS
test      -                       178.91.123.132
          foo.bar.com
          /foo          s1:80
$ kubectl edit ing test

在彈出的編輯器中修改:

spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          serviceName: s1
          servicePort: 80
        path: /foo
  - host: bar.baz.com
    http:
      paths:
      - backend:
          serviceName: s2
          servicePort: 80
        path: /foo
..

保存關稍后確認更新:

$ kubectl get ing
NAME      RULE          BACKEND   ADDRESS
test      -                       178.91.123.132
          foo.bar.com
          /foo          s1:80
          bar.baz.com
          /foo          s2:80

參考:

$ kubectl get ing
NAME      RULE          BACKEND   ADDRESS
test      -                       178.91.123.132
          foo.bar.com
          /foo          s1:80
          bar.baz.com
          /foo          s2:80

Ingress-NginX傳遞自定義header

問題現場:

配置好Ingress之后可以通過Ingress正常訪問系統,但是輸入用戶名密碼之后登陸失敗。但是通過NodePort暴露服務時可以正常訪問和登錄。接下來進過調試發現是在獲取用戶信息時出錯,無法從Request header中取到自定義的用戶信息字段。

參考此文章發現,NginX默認會將用戶自定義的header過濾掉,除非開啟 underscores_in_headers ,經過測試,在NginX中開啟 underscores_in_headers 之后系統登錄正常。那么如何在Ingress-NginX中開啟此項呢:

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app: ingress-nginx
data:
  enable-underscores-in-headers: "true"

參考鏈接1

參考鏈接2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM