系列目錄html
向外網暴露集羣內服務,以使客戶端可以訪問,有如下幾種方法,本文重點描述Ingress。node
LoadBalancer通常由雲服務供應商提供或者用戶自定義,運行在集羣以外。在建立service時爲其配置LoadBalancer相關參數,當從外網訪問集羣內servcie時,用戶直接鏈接到LoadBalancer服務器,LoadBalancer服務器再將流量轉發到集羣內service。Loadbalancer配置及使用方法與各雲服務供應商有關,本文不詳細描述。nginx
這種方式要求集羣中部分節點有被外網訪問的能力。Kubernetes爲每一個NodePort類型的服務在集羣中的每一個節點上分配至少一個主機網絡端口號。客戶經過能被外網訪問的節點IP加上節點端口的方式訪問服務。大多數狀況下不會經過這種方式向集羣外暴露服務,緣由有四。git
其一:大多狀況下,爲了安全起見,集羣中的節點位於徹底內網環境中,不該該有被外網直接訪問的能力。通常外網訪問集羣中的節點都是經過邊界服務器如網關、跳板等,而這種邊界服務器須要經過各類方式進行安全加固。github
其二:若是集羣內節點能夠從外網直接訪問的話,則會將集羣內節點地址、服務名稱、端口號等信息直接暴露在外,很是不安全。api
其三:服務端口號通常由系統自動分配,並不是固定,而服務名稱也可能發生變動,此時外部客戶端須要跟蹤變動並修改,屬於重試耦合。安全
其四:這種方式,每一個服務至少向外網暴露一個端口號,當服務不少時不易於管理。服務器
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,而後轉發請求。app
在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的各類典型用法。
配置文件:
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端口。
假如要實現如下目標:
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
實現以下目錄:
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
利用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
使用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以後能夠經過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"