原文地址:https://alphahinex.github.io/2021/07/11/ingress-ingress-controller-ingress-class/
description: "集群內(nèi)外溝通的橋梁"
date: 2021.07.11 10:26
categories:
- Cloud Native
tags: [K8s]
keywords: K8s, Cloud Native, Ingress, Nginx, Ingress Controller, Ingress Class
將 k8s 集群中服務(wù)暴露給集群外訪問,最簡單的方式莫過于使用 NodePort,好比在 docker 環(huán)境下為容器的服務(wù)端口綁定宿主機的端口,定義 NodePort 類型的 Service 后,即可通過集群中任意節(jié)點的 IP 加 nodePort 指定的端口訪問到 k8s 集群中的服務(wù)。
但隨著服務(wù)的增多,使用 NodePort 訪問的問題也會逐漸顯現(xiàn)出來:可用作 NodePort 的端口是一個有限的范圍、不容易記憶、不好管理……
有沒有更優(yōu)雅的方式訪問集群內(nèi)的服務(wù)呢?
可以在集群內(nèi)部署一個 Nginx 服務(wù),NodePort 暴露 Nginx 的端口,再由 Nginx 代理訪問集群內(nèi)的服務(wù)。emm,沒錯,這種方式的確更好。在 k8s 中也有這樣的一個資源,能夠起到與這個 Nginx 類似的作用,即 Ingress
。
Ingress
Ingress 在 k8s 集群中的作用,是定義外部對集群內(nèi)服務(wù)的訪問路由,例如:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
service:
name: test
port:
number: 80
上面這個 Ingress 資源的定義,配置了一個路徑為 /testpath
的路由,所有 /testpath/**
的入站請求,會被 Ingress 轉(zhuǎn)發(fā)至名為 test
的服務(wù)的 80 端口的 /
路徑下。
可以將 Ingress 狹義的理解為,Nginx 中的配置文件,如:nginx.conf
。
Ingress Controller
很顯然,只有 Nginx 的配置文件,是起不到轉(zhuǎn)發(fā)請求的作用的,必須還要有 Nginx 程序。
同樣,僅創(chuàng)建 Ingress 資源本身是沒有任何作用的,還需要部署 Ingress Controller。Ingress Controller 的作用就相當于是 Nginx 服務(wù),實際上,k8s 官方支持和維護的三個 Ingress Controller 里,就有基于 nginx 實現(xiàn)的 ingress-nginx,另外兩個是 AWS 和 GCE。
除此之外,還有很多三方實現(xiàn),例如:
- F5 BIG-IP 的 Container Ingress Services for Kubernetes 讓你能夠使用 Ingress 來配置 F5 BIG-IP 虛擬服務(wù)器
- Gloo 是一個開源的、基于 Envoy 的 Ingress 控制器,能夠提供 API 網(wǎng)關(guān)功能
- HAProxy Ingress 針對 HAProxy 的 Ingress 控制器
- Istio Ingress 是一個基于 Istio 的 Ingress 控制器
- NGINX Ingress Controller for Kubernetes 能夠與 NGINX Web 服務(wù)器(作為代理)一起使用
- Traefik Kubernetes Ingress provider 是一個用于 Traefik 代理的 Ingress 控制器
既然有這么多類型的實現(xiàn),我們就有可能會有需要部署多個 Ingress Controller 的場景。當集群中部署了多個 Ingress Controller 的時候,如何知道 Ingress 中的規(guī)則應該使用哪個 Controller 呢?這時就需要用到 Ingress Class 了。
Ingress Class
不同類型的 Ingress Controller 對應的 Ingress 配置通常也是不同的,當集群中存在多于一個的 Ingress Controller 時,就需要為 Ingress 指定對應的 Controller 是哪個。
kubernetes.io/ingress.class
在 Kubernetes 1.18 之前,通常是在 Ingress 資源上通過 kubernetes.io/ingress.class
注解來指定使用的 Ingress Controller。雖然這個注解從未被正式定義過,但確是被各個 Ingress Controller 所廣泛支持的。
這個注解的值,一般是具體 Ingress Controller 所提供的默認值,如 nginx
、gce
、traefik
、kong
等,可使用約定關(guān)鍵字,或查閱對應文檔獲得此默認值,如 Kong 的 Kubernetes Ingress Controller 文檔中 Configuring the controller ingress class 部分。
在創(chuàng)建 Ingress Controller 部署對象時,我們也可以通過 --ingress-class
來指定此 Ingress Controller 具體 Deployment 的對應 class,如:
spec:
template:
spec:
containers:
- name: nginx-ingress-internal-controller
args:
- /nginx-ingress-controller
- '--ingress-class=nginx-internal'
- '--configmap=ingress/nginx-ingress-internal-controller'
Ingress 中指定使用的 Ingress Controller 時,可參考如下方式:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-issue2349
annotations:
kubernetes.io/ingress.class: nginx-internal
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- backend:
serviceName: echoheaders
servicePort: 80
path: /jsonRPC
IngressClass
Kubernetes 1.18 起,正式提供了一個 IngressClass 資源,作用與 kubernetes.io/ingress.class
注解類似,例如:
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb
spec:
controller: nginx-ingress-internal-controller
parameters:
apiGroup: k8s.example.com
kind: IngressParameters
name: external-lb
其中重要的屬性是 metadata.name
和 spec.controller
,前者是這個 IngressClass 的名稱,需要設(shè)定在 Ingress 中,后者是 Ingress Controller 的名稱。
Ingress 中的 spec.ingressClassName
屬性,可以用來指定對應的 IngressClass,并進而由 IngressClass 關(guān)聯(lián)到對應的 Ingress Controller,如:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: spring-k8s
spec:
ingressClassName: external-lb
defaultBackend:
service:
name: spring-k8s
port:
number: 80
注意,spec.ingressClassName
與 metadata.annotations.kubernetes.io/ingress.class
的作用并不完全相同,因為 ingressClassName
字段引用的是 IngressClass 資源的名稱,IngressClass 資源中,除了指定了 Ingress Controller 的名稱之外,還可能會通過 spec.parameters
屬性定義一些額外的配置。
默認 Ingress Class
在集群中,我們可以設(shè)定一個默認的 Ingress Class,以便處理所有沒有指定 Ingress Class 的 Ingress 資源。
在 IngressClass
資源上,我們可以通過將 ingressclass.kubernetes.io/is-default-class
注解的值設(shè)定為 true
,來使沒有設(shè)置 ingressClassName
的 Ingress 使用此默認的 IngressClass
。
注意:當存在多個默認 Ingress Class 時,新的 Ingress 如果沒有指定
ingressClassName
則不會被允許創(chuàng)建。解決這個問題只需確保集群中最多只能有一個 IngressClass 被標記為默認。
多個 Ingress Controller
除了可能會有多個不同類型的 Ingress Controller 之外,還可能存在多個相同類型的 Ingress Controller,比如部署了兩個 NGINX Ingress Controller,一個負責處理外網(wǎng)訪問,一個負責處理內(nèi)網(wǎng)訪問。
此時也可以通過上面的方式,為每個 Controller 設(shè)定唯一的一個 class。
當多個 controller 的 class 不唯一,或者 controller 和 Ingress 都沒有指定 class 又沒有默認的 class 時,會導致所有符合條件的 Ingress Controller 競爭滿足 Ingress 配置,可能會導致不可預測的結(jié)果。