Ingress

在本篇文章中你將會看到一些在其他地方被交叉使用的術語,爲了防止產生歧義,我們首先來澄清下。

  • 節點:Kubernetes 集群中的服務器;

  • 集群:Kubernetes 管理的一組服務器集合;

  • 邊界路由器:爲局域網和 Internet 路由數據包的路由器,執行防火牆保護局域網絡;

  • 集群網絡:遵循 Kubernetes網絡模型 實現集群內的通信的具體實現,比如 flannelOVS

  • 服務:Kubernetes 的服務 (Service) 是使用標籤選擇器標識的一組 pod Service。 除非另有說明,否則服務的虛擬 IP 僅可在集群內部訪問。

什麼是 Ingress?

通常情況下,service 和 pod 的 IP 僅可在集群內部訪問。集群外部的請求需要通過負載均衡轉發到 service 在 Node 上暴露的 NodePort 上,然後再由 kube-proxy 通過邊緣路由器 (edge router) 將其轉發給相關的 Pod 或者丟棄。如下圖所示

   internet
        |
  ------------
  [Services]

而 Ingress 就是爲進入集群的請求提供路由規則的集合,如下圖所示

image-20190316184154726

Ingress 可以給 service 提供集群外部訪問的 URL、負載均衡、SSL 終止、HTTP 路由等。爲了配置這些 Ingress 規則,集群管理員需要部署一個 Ingress controller,它監聽 Ingress 和 service 的變化,並根據規則配置負載均衡並提供訪問入口。

Ingress 格式

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
spec:
  rules:
  - http:
      paths:
      - path: /testpath
        backend:
          serviceName: test
          servicePort: 80

每個 Ingress 都需要配置 rules,目前 Kubernetes 僅支持 http 規則。上面的示例表示請求 /testpath 時轉發到服務 test 的 80 端口。

API 版本對照表

Kubernetes 版本
Extension 版本

v1.5-v1.17

extensions/v1beta1

v1.8-v1.18

networking.k8s.io/v1beta1

v1.19+

networking.k8s.io/v1

Ingress 類型

根據 Ingress Spec 配置的不同,Ingress 可以分爲以下幾種類型:

單服務 Ingress

單服務 Ingress 即該 Ingress 僅指定一個沒有任何規則的後端服務。

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

注:單個服務還可以通過設置 Service.Type=NodePort 或者 Service.Type=LoadBalancer 來對外暴露。

多服務的 Ingress

路由到多服務的 Ingress 即根據請求路徑的不同轉發到不同的後端服務上,比如

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

可以通過下面的 Ingress 來定義:

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

使用 kubectl create -f 創建完 ingress 後:

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

虛擬主機 Ingress

虛擬主機 Ingress 即根據名字的不同轉發到不同的後端服務上,而他們共用同一個的 IP 地址,如下所示

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

下面是一個基於 Host header 路由請求的 Ingress:

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

注:沒有定義規則的後端服務稱爲默認後端服務,可以用來方便的處理 404 頁面。

TLS Ingress

TLS Ingress 通過 Secret 獲取 TLS 私鑰和證書 (名爲 tls.crttls.key),來執行 TLS 終止。如果 Ingress 中的 TLS 配置部分指定了不同的主機,則它們將根據通過 SNI TLS 擴展指定的主機名(假如 Ingress controller 支持 SNI)在多個相同端口上進行復用。

定義一個包含 tls.crttls.key 的 secret:

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

Ingress 中引用 secret:

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

注意,不同 Ingress controller 支持的 TLS 功能不盡相同。 請參閱有關 nginxGCE 或任何其他 Ingress controller 的文檔,以瞭解 TLS 的支持情況。

更新 Ingress

可以通過 kubectl edit ing name 的方法來更新 ingress:

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

這會彈出一個包含已有 IngressSpec yaml 文件的編輯器,修改並保存就會將其更新到 kubernetes API server,進而觸發 Ingress Controller 重新配置負載均衡:

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 replace -f new-ingress.yaml 命令來更新,其中 new-ingress.yaml 是修改過的 Ingress yaml。

Ingress Controller

Ingress 正常工作需要集群中運行 Ingress Controller。Ingress Controller 與其他作爲 kube-controller-manager 中的在集群創建時自動啓動的 controller 成員不同,需要用戶選擇最適合自己集群的 Ingress Controller,或者自己實現一個。

Ingress Controller 以 Kubernetes Pod 的方式部署,以 daemon 方式運行,保持 watch Apiserver 的 /ingress 接口以更新 Ingress 資源,以滿足 Ingress 的請求。比如可以使用 Nginx Ingress Controller

helm install stable/nginx-ingress --name nginx-ingress --set rbac.create=true

其他 Ingress Controller 還有:

Ingress Class

在 Ingress Class 之前,要給 Ingress 選擇具體的 Controller,需要加上特殊的 annotation(如 kubernetes.io/ingress.class: nginx)。而有了 IngressClass,集群管理員就可以預先創建好支持的 Ingress 類型,並可以 Ingress 中直接引用。

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb
spec:
  controller: example.com/ingress-controller
  parameters:
    apiGroup: k8s.example.com
    kind: IngressParameters
    name: external-lb

參考文檔

Last updated