Ingress是管理k8s群集中服务的外部访问(通常是HTTP/HTTPS访问请求)的API对象,它可以提供负载均衡和基于域名的虚拟主机服务(实现nginx的功能)。
在了解Ingress之前,我们需要先知道以下术语:

  • Node:k8s集群工作节点
  • Cluster:k8s集群
  • Edge router:为你的集群强制执行防火墙策略的路由器,这可以是由云提供商或物理硬件管理的网关。
  • Cluster network:一组逻辑或物理链接的网络,根据Kubernetes网络模型实现集群内的通信。
  • Service:Kubernetes服务,使用标签选择器标识一组Pod。默认情况下服务具有仅在k8s集群网络内可路由的虚拟IP。

什么是ingress

Ingress将集群外部的HTTP和HTTPS请求路由给集群中的Service服务,路由流量可以通过Ingress资源上定义的规则控制,结构如下:

1
2
3
4
5
 internet
|
[ Ingress ]
--|-----|--
[ Services ]

可以通过Ingress配置为服务提供外部可访问的URL、负载均衡流量、SSL/TLS以及提供基于域名的虚拟主机。Ingress controllers控制器负责实现Ingress配置的功能,通常使用load balancer负载均衡器,同时Ingress也支持配置边缘路由器或其他前端来处理请求流量。

Ingress不会暴露任意端口或协议。 将HTTP和HTTPS以外的服务公开给Internet通常使用Service.Type = NodePort或Service.Type = LoadBalancer类型的服务。

使用ingress的必要条件

必须先创建ingress controller,仅创建Ingress资源无效。Ingress控制器有多种类型,例如常用的ingress-nginx。各种Ingress控制器的运行方式略有不同,请按规范要求配置运行。

Ingress资源

一个ingress资源(请求)示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /testpath
backend:
serviceName: test
servicePort: 80

与所有其他Kubernetes资源一样,Ingress需要apiVersion,kind和metadata字段。Ingress经常使用annotations注释来配置一些选项,具体取决于Ingress控制器类别,上述例子是重写目标路径的注释。不同的Ingress控制器支持不同的注释。详细配置请查看你选择的Ingress控制器的文档。

Ingress spec项具有配置负载均衡器或代理服务器所需的所有信息。最重要的是,它包含与所有传入请求匹配的规则列表。Ingress资源仅支持HTTP流量的规则。

Ingress规则

每个HTTP规则都包含以下信息:

  • 可选主机: 在上述示例中,未指定主机,因此该规则适用于通过指定的IP地址的所有入站HTTP流量。如果提供了主机(例如,foo.bar.com),则规则仅适用于该主机。
  • 路径列表(例如,/testpath):每个路径都有一个使用serviceName和servicePort定义的关联后端。在负载均衡器将流量定向到引用的服务之前,主机和路径都必须与传入请求的内容匹配。
  • 后端为服务和端口名称的组合:向Ingress发出的与主机和规则路径匹配的HTTP(和HTTPS)请求将发送到列出的后端。

默认后端通常在Ingress控制器中配置,以便为与spec规范中的路径不匹配的任何请求提供服务。

默认后端

没有规则的Ingress将所有流量发送到单个默认后端。 默认后端通常是Ingress控制器的配置选项,并且未在Ingress资源中指定。

如果没有任何主机或路径与Ingress对象中的HTTP请求匹配,则流量将路由到您的默认后端。

Ingress类型

单服务ingress

现有的Kubernetes概念允许公开单个服务,也可以通过指定没有规则的默认后端来使用Ingress执行此操作。

示例:ingress.yaml

1
2
3
4
5
6
7
8
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
backend:
serviceName: testsvc
servicePort: 80

创建ingress

1
2
3
4
kubectl apply -f ingress.yaml
kubectl get ingress test-ingress
NAME HOSTS ADDRESS PORTS AGE
test-ingress * 107.178.254.228 80 59s

其中107.178.254.228是Ingress控制器为满足此Ingress需求而分配的IP。(Ingress controllers和load balancers可能需要一两分钟来分配IP地址。在此之前,你经常会看到列为的地址)

多路由配置

多路由配置根据请求的HTTP URI将流量从单个IP地址路由到多个服务。 Ingress允许你将负载均衡器的数量降至最低。例如,请求规划如下:

1
2
foo.bar.com -> 178.91.123.132 -> / foo    service1:4200
/ bar service2:8080

按上述请求配置的ingress如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: service1
servicePort: 4200
- path: /bar
backend:
serviceName: service2
servicePort: 8080

创建后查看此ingress

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
kubectl describe ingress simple-fanout-example
Name: simple-fanout-example
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:4200 (10.8.0.90:4200)
/bar service2:8080 (10.8.0.91:8080)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 22s loadbalancer-controller default/test

只要服务(service1,service2)存在,Ingress控制器就会提供满足Ingress的负载均衡器。 创建完成后,你可以在地址字段中查看负载均衡器的地址。(注意:根据你使用的Ingress控制器类型,有此可能需要创建default-http-backend服务)

基于名称的虚拟主机ingress

基于名称的虚拟主机支持将HTTP流量路由到同一IP地址的多个主机名。

假设请求规划如下:

1
2
3
foo.bar.com --|                 |-> foo.bar.com service1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com service2:80

以下Ingress告诉负载均衡器根据主机header来路由请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
- host: bar.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80

如果你创建的ingress没有在规则中定义任何主机,则可以匹配任何到Ingress控制器的IP地址的Web流量(不需要匹配基于名称的虚拟主机)。

例如,以下Ingress资源会将first.bar.com请求的流量路由到service1,将second.foo.com路由到service2,以及没有在请求中定义的主机名的IP地址的任何流量(即,没有请求头存在)路由到服务3。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: first.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
- host: second.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
- http:
paths:
- backend:
serviceName: service3
servicePort: 80

配置TLS

可以通过指定包含TLS私钥和证书的Secret来保护Ingress。目前,Ingress仅支持单个TLS端口443,如果Ingress中的TLS配置部分指定了不同的主机,则它们将根据通过SNI TLS扩展指定的主机名在同一端口上进行多路复用(前提是Ingress控制器支持SNI)。TLS Secret必须包含名为tls.crt和tls.key的密钥,其中包含用于TLS的证书和私钥。例如:

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Secret
metadata:
name: testsecret-tls
namespace: default
data:
tls.crt: base64 encoded cert
tls.key: base64 encoded key
type: kubernetes.io/tls

在Ingress中引用此Secret告诉Ingress控制器使用TLS将客户端到负载均衡器的通道进行TLS加密通讯。当然了,前提你已经创建好了对应的密钥和证书。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- sslexample.foo.com
secretName: testsecret-tls
rules:
- host: sslexample.foo.com
http:
paths:
- path: /
backend:
serviceName: service1
servicePort: 80

更新ingress

如要对现有的Ingress添加新host主机,可以通过编辑ingress资源来更新它:

1
kubectl edit ingress test

修改如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
path: /foo
- host: bar.baz.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
path: /foo
..

保存更改后,kubectl会更新API服务器中的资源,告知Ingress控制器重新配置负载均衡器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)
bar.baz.com
/foo service2:80 (10.8.0.91:80)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 45s loadbalancer-controller default/test

你可以通过在修改后的Ingress YAML文件上执行kubectl replace -f来实现相同的结果。