kubernetes Ingress
Ingress介绍
kubernetes使用Ingress控制器作为统一的流量入口,管理内部各种必要的服务,并通过Ingress API资源来描述如何区分流量以及内部的路由逻辑。可以通过Ingress和Ingress控制器定义路由流量的规则来完成服务发布,而无须创建一堆NodePort或LoadBalancer类型的service,而且流量也会又Ingress控制器直接到达Pod对象。
Ingress资源
Ingress资源规范
apiVersion: networking.k8s.io/v1 # 资源所属的API群组和版本
kind: Ingress # 资源类型标识
metadata: # 元数据
name: <string> # 资源名称
annotations: # 资源注解
nginx.ingress.kubernetes.io/rewrite-target: / # URL重写
namespace: <string> # 名称空间
spec:
ingressClassName: <string> # Ingress控制器类别
defaultBackend: <Object> # 默认资源后端
service: <Object> # resource 与 Service 是互斥的,只能二选一,关联后端的service对象
name: <string> -required- # 后端service的名称
port: <Object> # 后端service上的端口对象
name: <string> # 端口名称
number: <integer> # 端口号
resource: <Object> # resource 与 Service 是互斥的,只能二选一,Resource的一种常见用法是将所有入站数据导向带有静态资产的对象存储后端
apiGroup: <string> # API资源组
kind: <string> -required- # 资源类型标识
name: <string> -required- # 资源的名称
rules: <[]Object> # Ingress规则列表
- host: <string> # 虚拟主机的FQDN,支持*前缀通配,不支持IP,不支持指定端口
http: <Object>
paths: <[]Object> -required- # 虚拟主机PATH定义的列表,有pathType和backend组成
- path: <string> # 流量匹配的HTTP PATH,必须以/开头
pathType: <string> -required- # 支持ImplementationSpecific、Exact、Prefix
backend: <Object> -required- # 匹配流量要转发的目标后端
resource: <Object> # resource 与 Service 是互斥的,只能二选一,Resource的一种常见用法是将所有入站数据导向带有静态资产的对象存储后端
apiGroup: <string> # API资源组
kind: <string> -required- # 资源类型标识
name: <string> -required- # 资源的名称
service: # resource 与 Service 是互斥的,只能二选一,关联后端的service对象
name: <string> -required- # 后端service的名称
port: <string> -required- # 后端service上的端口对象
name:<string> # 端口名称
number: <integer> # 端口号
tls:<[]Object> # TLS配置,用于指定上述rules中定义的那些主机需要工作在HTTPS模式下
- hosts:<[]string> # 使用同一组证书的主机名称列表
secretName: <string> # 保存数字证书和私钥信息的secret资源名称
路径类型
说明
Ingress 中的每个路径都需要有对应的路径类型(Path Type)。未明确设置 pathType 的路径无法通过合法性检查。当前支持的路径类型有三种:
ImplementationSpecific:对于这种路径类型,匹配方法取决于 IngressClass。 具体实现可以将其作为单独的 pathType 处理或者与 Prefix 或 Exact 类型作相同处理。
Exact:精确匹配 URL 路径,且区分大小写。
Prefix:基于以 / 分隔的 URL 路径前缀匹配。匹配区分大小写,并且对路径中的元素逐个完成。 路径元素指的是由 / 分隔符分隔的路径中的标签列表。 如果每个 p 都是请求路径 p 的元素前缀,则请求与路径 p 匹配。
示例
多重匹配
在某些情况下,Ingress 中的多条路径会匹配同一个请求。 这种情况下最长的匹配路径优先。 如果仍然有两条同等的匹配路径,则精确路径类型优先于前缀路径类型。
主机名通配符
说明
主机名可以是精确匹配(例如 “foo.bar.com”)或者使用通配符来匹配 (例如 “*.foo.com”)。 精确匹配要求 HTTP host 头部字段与 host 字段值完全匹配。 通配符匹配则要求 HTTP host 头部字段与通配符规则中的后缀部分相同。
示例
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wildcard-host
spec:
rules:
- host: "foo.bar.com"
http:
paths:
- pathType: Prefix
path: "/bar"
backend:
service:
name: service1
port:
number: 80
- host: "*.foo.com"
http:
paths:
- pathType: Prefix
path: "/foo"
backend:
service:
name: service2
port:
number: 80
IngressClass资源
IngressClass
Ingress 可以由不同的控制器实现,通常使用不同的配置。 每个 Ingress 应当指定一个类,也就是一个对 IngressClass 资源的引用。 IngressClass 资源包含额外的配置,其中包括应当实现该类的控制器名称。
apiVersion: networking.k8s.io/v1 # 资源所属的API群组和版本
kind: IngressClass # 资源类型标识
metadata:
labels: <map[string]string> # 标签
name: <string> # 资源名称
annotations: # 资源注解
ingressclass.kubernetes.io/is-default-class: "true" # 是否为默认
namespace: <string> # 名称空间
spec:
controller: <string> # 该类型所关联的ingress控制器
parameters: <Object> # 控制器相关的参数,这些参数由引用的资源定义,可选字段
apiGroup: <string> # 引用目标资源所属的API群组
kind: <string> -required- # 引用的资源类型
name: <string> -required- # 引用的资源名称
namespace: <string> # 引用资源的名称空间
scope: <string> # 引用资源的作用域,可选参数Cluster、Namespace
IngressClass作用域
IngressClass 的参数默认是集群范围的。
集群作用域
如果你设置了 .spec.parameters 字段且未设置 .spec.parameters.scope 字段,或是将 .spec.parameters.scope 字段设为了 Cluster, 那么该 IngressClass 所指代的即是一个集群作用域的资源。 参数的 kind(和 apiGroup 一起)指向一个集群作用域的 API(可能是一个定制资源(Custom Resource)),而它的 name 则为此 API 确定了一个具体的集群作用域的资源。
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb-1
spec:
controller: example.com/ingress-controller
parameters:
# 此 IngressClass 的配置定义在一个名为 “external-config-1” 的
# ClusterIngressParameter(API 组为 k8s.example.net)资源中。
# 这项定义告诉 Kubernetes 去寻找一个集群作用域的参数资源。
scope: Cluster
apiGroup: k8s.example.net
kind: ClusterIngressParameter
name: external-config-1
名称空间作用域
特性状态: Kubernetes v1.23 [stable]
如果你设置了 .spec.parameters 字段且将 .spec.parameters.scope 字段设为了 Namespace,那么该 IngressClass 将会引用一个命名空间作用域的资源。 .spec.parameters.namespace 必须和此资源所处的命名空间相同。
参数的 kind(和 apiGroup 一起)指向一个命名空间作用域的 API(例如:ConfigMap),而它的 name 则确定了一个位于你指定的命名空间中的具体的资源。
命名空间作用域的参数帮助集群操作者将控制细分到用于工作负载的各种配置中(比如:负载均衡设置、API 网关定义)。如果你使用集群作用域的参数,那么你必须从以下两项中选择一项执行:
每次修改配置,集群操作团队需要批准其他团队的修改。
集群操作团队定义具体的准入控制,比如 RBAC 角色与角色绑定,以使得应用程序团队可以修改集群作用域的配置参数资源。
IngressClass API 本身是集群作用域的。
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: external-lb-2
spec:
controller: example.com/ingress-controller
parameters:
# 此 IngressClass 的配置定义在一个名为 “external-config” 的
# IngressParameter(API 组为 k8s.example.com)资源中,
# 该资源位于 “external-configuration” 命名空间中。
scope: Namespace
apiGroup: k8s.example.com
kind: IngressParameter
namespace: external-configuration
name: external-config
默认 Ingress 类
你可以将一个特定的 IngressClass 标记为集群默认 Ingress 类。 将一个 IngressClass 资源的 ingressclass.kubernetes.io/is-default-class 注解设置为 true 将确保新的未指定 ingressClassName 字段的 Ingress 能够分配为这个默认的 IngressClass.
注意: 如果集群中有多个 IngressClass 被标记为默认,准入控制器将阻止创建新的未指定 ingressClassName 的 Ingress 对象。 解决这个问题只需确保集群中最多只能有一个 IngressClass 被标记为默认。
有一些 Ingress 控制器不需要定义默认的 IngressClass。比如:Ingress-NGINX 控制器可以通过参数 --watch-ingress-without-class 来配置。 不过仍然推荐 设置默认的 IngressClass。
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
name: nginx-example
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
spec:
controller: k8s.io/ingress-nginx
Ingress 类型
单service资源型Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
spec:
defaultBackend:
service:
name: test
port:
number: 80
基于URL路径进行流量分发
架构图
simple-fanout-example.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple-fanout-example
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
pathType: Prefix
backend:
service:
name: service1
port:
number: 4200
- path: /bar
pathType: Prefix
backend:
service:
name: service2
port:
number: 8080
基于FQDN的虚拟主机
架构图
name-virtual-host-ingress-no-third-host.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: name-virtual-host-ingress-no-third-host
spec:
rules:
- host: foo.bar.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service1
port:
number: 80
- host: bar.foo.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service2
port:
number: 80
- http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service3
port:
number: 80
TLS类型的Ingress资源
可以通过设定包含 TLS 私钥和证书的Secret 来保护 Ingress。 Ingress 只支持单个 TLS 端口 443,并假定 TLS 连接终止于 Ingress 节点(与 Service 及其 Pod 之间的流量都以明文传输)。 如果 Ingress 中的 TLS 配置部分指定了不同的主机,那么它们将根据通过 SNI TLS 扩展指定的主机名(如果 Ingress 控制器支持 SNI)在同一端口上进行复用。 TLS Secret 的数据中必须包含用于 TLS 的以键名 tls.crt 保存的证书和以键名 tls.key 保存的私钥。
testsecret-tls.yaml
apiVersion: v1
kind: Secret
metadata:
name: testsecret-tls
namespace: default
data:
tls.crt: base64 编码的证书
tls.key: base64 编码的私钥
type: kubernetes.io/tls
tls-example-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- https-example.foo.com
secretName: testsecret-tls
rules:
- host: https-example.foo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
更新 Ingress
要更新现有的 Ingress 以添加新的 Host,可以通过编辑资源来对其进行更新
查看ingress
# kubectl describe ingress test
Name: test
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:80 (10.8.0.90:80)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 35s loadbalancer-controller default/test
编辑ingress
方式一
# kubectl edit ingress test
方式二
# vim example-ingress.yaml
# kubectl replace -f example-ingress.yaml
验证
# kubectl describe ingress test
Ingress 实际应用
生产应用场景中,通常会以DaemonSet结合NodeAffinity、PodAntiAffinity使用,甚至是利用Taints/Tolerations调度机制将Ingress控制器以单实例的方式运行在专用的节点之上,并让Ingress控制器共享相关节点的名称空间,或者在Service上使用externalIP等来解决引入外部流量的问题。
Ingress 控制器
参考文档
https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/