什么是Ingress
Ingress是k8s以http或https的方式,使用nginx,根据URL规则(这些URL可在集群外访问),将请求转发给对应的service。
使用Ingress的前置条件
需要在k8s中运行ingress controller。使用RKE安装的K8s集群已经支持使用Ingress。
Ingress的描述文件
一个Ingress描述文件的例子如下:
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
此时,我们访问集群节点的/testpath
这个URL,k8s会把请求转发给test服务。
Ingress规则
每一条Ingress规则包含如下信息:
- host(可选):需要填写域名。如果配置了此项,Ingress规则仅对这个host生效。如果没有配置,这条规则对所有的host生效。这里判断标准是Request header里头HOST的值。
- paths列表:列出了所有URL路径和后台service以及端口的对应关系。
- backend:需要指明和path对应的服务和端口号,这样访问这个path的时候,请求会被转发到backend服务中。
查看Ingress的信息
执行
[root@k8s ~]# kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
test-ingress * 192.168.100.128 80 97m
可以得到类似的输出。我们可以通过ADDRESS一栏的地址访问ingress对应的服务。
Ingress使用例子
单服务Ingress
单服务的Ingress只有一个backend。甚至我们可以不用写rules,仅仅指定一个default backend。例子如下:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
backend:
serviceName: testsvc
servicePort: 80
在这个例子中,testsvc是一个default backend。
不匹配所有规则的请求会被转发到default backend。因此使用这种配置方式配置单服务Ingress比较简便。
多服务Ingress
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
配置达到的效果解释如下:
- 一个请求头HOST为foo.bar.com到达该节点,如果请求URL为
/foo
,请求会被转发给service1的4200端口。 - 一个请求头HOST为foo.bar.com到达该节点,如果请求URL为
/bar
,请求会被转发给service2的8080端口。
基于域名的虚拟主机
Ingress使用多个host的例子:
spec:
rules:
- host: foo.example.com
http:
paths:
- path: /
backend:
serviceName: foo
servicePort: 80
- host: bar.example.com
http:
paths:
- path: /
backend:
serviceName: bar
servicePort: 80
k8s会判断请求头的host的内容。如果是foo.example.com
访问foo服务,如果是bar.example.com
则访问bar服务。
下面这个例子和上述的类似,只是如果请求头没有HOST,会被转发给service3。
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支持
Ingress支持加密链接的访问模式。
配置步骤如下:
- 生成TLS证书。
$ openssl genrsa -out tls.key 2048
$ openssl req -new -x509 -key tls.key -out tls.cert -days 360 -subj /CN=kubia.example.com
- 创建一个Secret
kubectl create secret tls tls-secret --cert=tls.cert --key=tls.key
- 创建一个Ingress,使用上一步创建出的Secret
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubia
spec:
tls:
- hosts:
- kubia.example.com
secretName: tls-secret
rules:
- host: kubia.example.com
http:
paths:
- path: /
backend:
serviceName: kubia-nodeport
servicePort: 80
注意:tls配置的hosts需要和TLS证书中CN的值一致。
Ingress Path Rewrite
通常来说访问service内部的URL和它对应的Ingress入口URL是不同的。为了满足这个要求,Kubernetes提供了Path Rewrite(路径重写)。可以通过正则表达式语法,配置Ingress入口URL和访问service URL的对应关系。
配置Path Rewrite的方法为在Ingress中的annotations配置项中,增加如下配置:
nginx.ingress.kubernetes.io/rewrite-target: rewrite规则
下面讲解几个path rewrite规则示例:
apiVersion: networking.extensions/v1beta1
kind: Ingress
metadata:
name: ingress-echo-with-rewrite
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: rewrite.example
http:
paths:
- path: /svc1/
backend:
serviceName: svc1
servicePort: 80
这个配置会将http://rewrite.example/svc1/xxx
重写为访问svc1的/
路径。/svc1/xxx
会全被改写为/
,即原始URL/svc1
后面的东西统统会被丢掉。
如何在访问svc1的时候去掉/svc1
前缀,但又不会丢掉前缀之后的内容呢?下面的例子可以满足这个要求:
apiVersion: networking.extensions/v1beta1
kind: Ingress
metadata:
name: ingress-echo-with-rewrite
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: rewrite.example
http:
paths:
- path: /svc1/(.*)
backend:
serviceName: svc1
servicePort: 80
上面的rewrite规则将http://rewrite.example/svc1/xxx
重写为访问svc1的/xxx
。
其中$1
为path
中的第一个捕获组的内容。意思为将URL/svc1
部分去掉,剩下的部分保留,用于访问svc1。
按照官方文档的说法,我们可以在rewrite规则中使用$1
,$2
或$n
来获取path配置项中的第1个,第二个乃至第n个捕获组。