相关术语

为清楚起见,本指南定义了以下术语:

  • Node(节点): kubernetes集群中的一台虚拟机或物理机。
  • Cluster(集群): 一组与因特网通过隔离的节点,他们是是Kubernetes管理的主要计算资源。
  • Edge router(边界路由器): 为您的集群强制执行防火墙策略的路由器。这可以是由云提供商管理的网关,也可以是物理硬件。
  • Cluster network(集群网络): 根据Kubernetes网络模型,促进集群内通信的一组逻辑上的或物理上的链路。
  • Service(服务): 一种Kubernetes服务,它使用标签选择器标识一组pod。除非另有说明,否则假定服务只有在集群网络中可路由的虚拟ip。

什么是ingress

ingress(在kubernetes v1.1时添加)暴露从集群外到集群内服务的HTTPHTTPS路由。定义在ingress资源上的规则控制流量的路由。

管理对集群中的服务(通常是HTTP)的外部访问的API对象。Ingress可以提供负载平衡、SSL终端和基于名称的虚拟主机。

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

一个ingress可以配置用于提供外部可访问的服务url、负载均衡流量、SSL终端和提供虚拟主机名配置。ingress controller负责实现(通常使用负载均衡器(loadbalancer))入口(ingress)。但是它也可以配置你的边缘路由器或额外的前端来帮助处理流量。
ingress不暴露任何端口或协议。将HTTP和HTTPS之外的服务公开到因特网通常使用类型是NodePort或loadbalance的service。

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需要apiVersionkindmetadata字段。
Ingress spec包含配置负载均衡器或代理服务器所需的所有信息。最重要的是,它包含一个针对所有传入请求匹配的规则列表。ingress资源只支持用于指导HTTP通信的规则

ingress 规则

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

  • 一个可选的host。在本例中没有host,因此,该规则适用于通过指定的IP地址进行的所有入站HTTP通信。如果提供一个host(例如,foo.bar.com),这个规则是适用于这一个host
  • 一个paths(例如 /testpath)的列表。每一个path都有与之关联的serviceNameservicePort,在负载均衡器将流量导向所引用的服务之前,主机和路径必须匹配传入请求的内容
  • 后端是服务和端口名称的组合。对与规则的主机和路径匹配的入口的HTTP(和HTTPS)请求将发送到列出的后端。

默认后端通常配置在一个Ingress控制器中,该控制器将服务于任何与规范中的路径不匹配的请求。(404页面)

默认后端

没有规则的ingress把所有的流量都转发到一个默认后端。默认后端通常是Ingress控制器的一个配置选项,并没有在Ingress资源中指定。
如果没有任何主机或路径匹配Ingress对象中的HTTP请求,则流量将路由到默认后端。

ingress的类型

单service的ingress

现有的Kubernetes概念允许您公开单个服务。您还可以通过指定一个没有规则的默认后端来对一个入口执行此操作。

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

通过kubectl apply -f <文件名>创建后,你可以看到:

1
2
3
kubectl get ingress test-ingress
NAME HOSTS ADDRESS PORTS AGE
test-ingress * 107.178.254.228 80 59s

其中107.178.254.228是入口控制器为满足该入口而分配的IP。

根据请求URI匹配

根据所请求的HTTP URI,扇出配置将流量从单个IP地址路由到多个服务。一个入口允许您将负载平衡器的数量保持到最小。例如,设置如下:

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

通过kubectl apply -f <文件名>创建后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

只要服务(s1, s2)存在,Ingress控制器提供一个满足Ingress的特定于实现的负载均衡器。当它这样做时,您可以在address字段中看到负载均衡器的地址。

基于不同域名的虚拟主机

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

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

下面的ingress告诉后台负载均衡器根据主机头路由请求。

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,将任何没有在request中定义主机名(即没有显示请求头)的流量路由到service3。

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私钥和证书的秘密来保护ingress。目前,入口只支持一个TLS端口443,并假设TLS终端。如果一个入口中的TLS配置部分指定了不同的主机,那么它们将根据通过SNI TLS扩展指定的主机名在同一个端口上进行多路复用(前提是入口控制器支持SNI)。TLS密钥必须包含名为TLS的密钥。crt和tls。包含用于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 secret来自一个包含sslexample.foo.com CN的证书。

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

Loadbalancing

一个ingress controller 通过一些应用于所有入口的负载平衡策略设置来引导,例如负载平衡算法、后端权重方案等。更高级的负载平衡概念(例如持久会话、动态权重)还没有通过ingress公开。同样值得注意的是,尽管健康检查不是直接通过入口暴露的,但是在Kubernetes中也存在类似的概念,比如就绪探测,它允许您实现相同的最终结果。

部署Ingress-nginx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 下载ingress-nginx部署yaml文件
[root@k8s-master ~]$ wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/deploy.yaml
[root@k8s-master ~]$ cat deploy.yaml | grep image
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.33.0
image: docker.io/jettech/kube-webhook-certgen:v1.2.0

# 手动下载ingress镜像
[root@k8s-master ~]$ docker pull docker.io/jettech/kube-webhook-certgen:v1.2.0
[root@k8s-master ~]$ docker pull quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.33.0

# 将镜像导出到复制到其他node节点
[root@k8s-master opt]$ docker save -o nginx-ingress-controller.tar.gz quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.33.0
[root@k8s-master opt]$ docker save -o kube-webhook-certgen.tar.gz jettech/kube-webhook-certgen:v1.2.0
[root@k8s-master opt]$ scp kube-webhook-certgen.tar.gz nginx-ingress-controller.tar.gz k8s-node01.nnv5.cn:/opt/
[root@k8s-master opt]$ scp kube-webhook-certgen.tar.gz nginx-ingress-controller.tar.gz k8s-node02.nnv5.cn:/opt/

# node节点导入镜像
[root@k8s-node02 opt]$ docker load -i kube-webhook-certgen.tar.gz
[root@k8s-node02 opt]$ docker load -i nginx-ingress-controller.tar.gz

# 部署ingress
[root@k8s-master ~]$ kubectl apply -f deploy.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created
deployment.apps/ingress-nginx-controller created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
serviceaccount/ingress-nginx-admission created

# 验证部署是否成功
~]$ kubectl get pods -o wide -n ingress-nginx
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-controller-58f68f5ccc-5v2qc 1/1 Running 0 10m 10.244.1.18 k8s-node01.nnv5.cn <none> <none>

# 有访问请求时访问ingress的NodePort的31101端口即访问容器的80端口 80:31101
# 有访问请求时访问ingress的NodePort的31123端口即访问容器的443端口 443:31123
~]$ kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.96.249.151 <none> 80:31101 /TCP,443:31123/TCP 84m
ingress-nginx-controller-admission ClusterIP 10.107.8.188 <none> 443/TCP 84m

hostnetwork方式部署Ingress-nginx

1.下载ingress部署文件

1
2
# 下载ingress-nginx部署yaml文件
[root@k8s-node01 ~]# wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml

2.给需要运行ingress的节点打标签

1
2
3
4
[root@k8s-master simple-microservice-dev3]# kubectl label node k8s-node01.nnv5.cn ingress-controller-ready=OK
node/k8s-node01.nnv5.cn labeled
[root@k8s-master simple-microservice-dev3]# kubectl label node k8s-node02.nnv5.cn ingress-controller-ready=OK
node/k8s-node02.nnv5.cn labeled

3.修改deployment为daemonset,添加hostnetwork模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
apiVersion: apps/v1
kind: DaemonSet #Deployment修改为DaemonSet
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec: # 删除掉replicas=1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
annotations:
prometheus.io/port: "10254"
prometheus.io/scrape: "true"
spec:
# wait up to five minutes for the drain of connections
terminationGracePeriodSeconds: 300
serviceAccountName: nginx-ingress-serviceaccount
nodeSelector:
ingress-controller-ready: OK # 新添加的哪些节点运行ingress-nginx
hostNetwork: true # 新添加使用节点主机网络


# 应用资源清单并部署
[root@k8s-node01 ~]# kubectl apply -f mandatory.yaml
namespace/ingress-nginx unchanged
configmap/nginx-configuration unchanged
configmap/tcp-services unchanged
configmap/udp-services unchanged
serviceaccount/nginx-ingress-serviceaccount unchanged
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole unchanged
role.rbac.authorization.k8s.io/nginx-ingress-role unchanged
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding unchanged
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding unchanged
daemonset.apps/nginx-ingress-controller created

4.查看ingress运行的节点,查看节点监听端口号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 查看运行的节点
[root@k8s-node01 ~]# kubectl get pods -n ingress-nginx -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-ingress-controller-9kckx 1/1 Running 0 6m59s 192.168.1.43 k8s-node02.nnv5.cn <none> <none>
nginx-ingress-controller-qhf9b 1/1 Running 0 6m59s 192.168.1.42 k8s-node01.nnv5.cn <none> <none>

# 查看监听的端口号
[root@k8s-node01 ~]# ss -tnl | egrep '80|443'
LISTEN 0 128 *:80 *:*
LISTEN 0 128 *:80 *:*
LISTEN 0 128 *:80 *:*
LISTEN 0 128 *:80 *:*
LISTEN 0 128 *:443 *:*
LISTEN 0 128 *:443 *:*
LISTEN 0 128 *:443 *:*
LISTEN 0 128 *:443 *:*

5.创建一个访问示例进行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# 创建一个deployment关联一个svc,创建一个ingress的域名为web.nnv5.cn关联web这个svc
[root@k8s-node02 ~]# cat deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- image: putianhui/myapp:v2
name: myapp
---
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: web
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: web.nnv5.cn
http:
paths:
- backend:
serviceName: web
servicePort: 80

# 应用资源清单
[root@k8s-node02 ~]# kubectl apply -f deploy.yaml
deployment.apps/web created
service/web created
ingress.networking.k8s.io/name-virtual-host-ingress created

# 查看资源
[root@k8s-node02 ~]# kubectl get deploy,svc,ingress
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/web 3/3 3 3 21s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 41d
service/web ClusterIP 10.108.235.31 <none> 80/TCP 21s

NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.extensions/name-virtual-host-ingress <none> web.nnv5.cn 80 21s


# 节点主机添加一个hosts解析,访问ingress域名进行测试
[root@k8s-node02 ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.1.42 web.nnv5.cn

[root@k8s-node02 ~]# curl web.nnv5.cn/hostname.html
web-6dc57ffff9-67fp8
[root@k8s-node02 ~]# curl web.nnv5.cn/hostname.html
web-6dc57ffff9-vbczr
[root@k8s-node02 ~]# curl web.nnv5.cn/hostname.html
web-6dc57ffff9-94vph