【k8s】——ingress原理和應用

一、前言

      我們說k8s 的服務(service)時說暴露了service的三種方式ClusterIP、NodePort與LoadBalance,這幾種方式都是在service的維度提供的,service的作用體現在兩個方面,對集羣內部,它不斷跟蹤pod的變化,更新endpoint中對應pod的對象,提供了ip不斷變化的pod的服務發現機制,對集羣外部,他類似負載均衡器,可以在集羣內外部對pod進行訪問。但是,單獨用service暴露服務的方式,在實際生產環境中不太合適:

  • ClusterIP的方式只能在集羣內部訪問。
  • NodePort方式的話,測試環境使用還行,當有幾十上百的服務在集羣中運行時,NodePort的端口管理是災難。
  • LoadBalance方式受限於雲平臺,且通常在雲平臺部署ELB還需要額外的費用。

    所幸k8s還提供了一種集羣維度暴露服務的方式,也就是ingress。ingress可以簡單理解爲service的service,他通過獨立的ingress對象來制定請求轉發的規則,把請求路由到一個或多個service中。這樣就把服務與請求規則解耦了,可以從業務維度統一考慮業務的暴露,而不用爲每個service單獨考慮。
舉個例子,現在集羣有api、文件存儲、前端3個service,可以通過一個ingress對象來實現圖中的請求轉發:

clipboard.png

ingress規則是很靈活的,可以根據不同域名、不同path轉發請求到不同的service,並且支持https/http。

二、ingress與ingress-controller

要理解ingress,需要區分兩個概念,ingress和ingress-controller:

  • ingress對象:
    指的是k8s中的一個api對象,一般用yaml配置。作用是定義請求如何轉發到service的規則,可以理解爲配置模板。
  • ingress-controller:
    具體實現反向代理及負載均衡的程序,對ingress定義的規則進行解析,根據配置的規則來實現請求轉發。

簡單來說,ingress-controller纔是負責具體轉發的組件,通過各種方式將它暴露在集羣入口,外部對集羣的請求流量會先到ingress-controller,而ingress對象是用來告訴ingress-controller該如何轉發請求,比如哪些域名哪些path要轉發到哪些服務等等。

2.1 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爲例。

2.2 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初體驗

      雖然 minikube 支持 LoadBalancer 類型的服務,但它並不會創建外部的負載均衡器,而是爲這些服務開放一個 NodePort。這在使用 Ingress 時需要注意。

3.1 啓動 Ingress Controller

minikube 已經內置了 ingress addon,只需要開啓一下即可

$ minikube addons enable ingress

稍等一會,nginx-ingress-controller 和 default-http-backend 就會起來

$ kubectl get pods -n kube-system
NAME                             READY     STATUS    RESTARTS   AGE
default-http-backend-5374j       1/1       Running   0          1m
kube-addon-manager-minikube      1/1       Running   0          2m
kube-dns-268032401-rhrx6         3/3       Running   0          1m
kubernetes-dashboard-xh74p       1/1       Running   0          2m
nginx-ingress-controller-78mk6   1/1       Running   0          1m

3.2 創建 Ingress

首先啓用一個 echo server 服務

$ kubectl run echoserver --image=gcr.io/google_containers/echoserver:1.4 --port=8080
$ kubectl expose deployment echoserver --type=NodePort
$ minikube service echoserver --url
http://192.168.64.36:31957

然後創建一個 Ingress,將 http://mini-echo.io 和 http://mini-web.io/echo 轉發到剛纔創建的 echoserver 服務上

$ cat <<EOF | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: echo
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  backend:
    serviceName: default-http-backend
    servicePort: 80
  rules:
  - host: mini-echo.io
    http:
      paths:
      - path: /
        backend:
          serviceName: echoserver
          servicePort: 8080
  - host: mini-web.io
    http:
      paths:
      - path: /echo
        backend:
          serviceName: echoserver
          servicePort: 8080
EOF

爲了訪問 mini-echo.io 和 mini-web.io 這兩個域名,手動在 hosts 中增加一個映射

$ echo "$(minikube ip) mini-echo.io mini-web.io" | sudo tee -a /etc/hosts

然後,就可以通過 http://mini-echo.io 和 http://mini-web.io/echo 來訪問服務了。

3.3 使用 xip.io

前面的方法需要每次在使用不同域名時手動配置 hosts,藉助 xip.io 可以省掉這個步驟。

跟前面類似,先啓動一個 nginx 服務

$ kubectl run nginx --image=nginx --port=80
$ kubectl expose deployment nginx --type=NodePort

然後創建 Ingress,與前面不同的是 host 使用 nginx.$(minikube ip).xip.io

$ cat <<EOF | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
 name: my-nginx-ingress
spec:
 rules:
  - host: nginx.$(minikube ip).xip.io
    http:
     paths:
      - path: /
        backend:
         serviceName: nginx
         servicePort: 80
EOF

然後就可以直接訪問該域名了

$ curl nginx.$(minikube ip).xip.io

四、參考資料

1、k8s ingress原理及ingress-nginx部署測試

2、minikube使用ingress

3、馬哥_K8s進階實戰(4)Service/Ingress

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