Service的表现形式为IP:Port,即工作在TCP/IP层。而对于基于HTTP的服务来说,不同的URL地址经常对应到不同的后端服务或者虚拟服务器(VirtualHost),这些应用层的转发机制仅通过Kubernetes的Service机制是无法实现的。从Kubernetes 1.1版本开始新增Ingress资源对象,用于将不同URL的访问请求转发到后端不同的Service,以实现HTTP层的业务路由机制。Kubernetes使用了一个Ingress策略定义和一个具体的Ingress Controller,两者结合并实现了一个完整的Ingress负载均衡器。
使用Ingress进行负载分发时,Ingress Controller基于Ingress规则将客户端请求直接转发到Service对应的后端Endpoint(Pod)上,这样会跳过kube-proxy的转发功能,kube-proxy不再起作用。如果Ingress Controller提供的是对外服务,则实际上实现的是边缘路由器的功能。
ingress-nginx工作原理
ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化,然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置,再写到nginx-ingress-controller的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中,然后reload一下使配置生效。以此达到域名分别配置和动态更新的问题。
ingress-nginx组成
-
ingress-nginx-controller:根据用户编写的ingress规则(创建的ingress的yaml文件),动态的去更改nginx服务的配置文件,并且reload重载使其生效(是自动化的,通过lua脚本来实现);
-
ingress资源对象:将Nginx的配置抽象成一个Ingress对象,每添加一个新的Service资源对象只需写一个新的Ingress规则的yaml文件即可(或修改已存在的ingress规则的yaml文件)
定义Ingress策略
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: mywebsite-ingress
spec:
rules:
- host: mywebsite.com
http:
paths:
- backend:
serviceName: webapp
servicePort: 8080
path: /demo
这个Ingress的定义,说明对目标地址http://mywebsite.com/demo的访问将被转发到集群中的Service webapp即webapp:8080/demo上。在Ingress生效之前,需要先将webapp服务部署完成。同时需要注意Ingress中path的定义,需要与后端真实服务提供的path一致,否则将被转发到一个不存在的path上,引发错误。
Ingress的策略配置技巧
1.转发到单个后端服务上
基于这种设置,客户端到Ingress Controller的访问请求都将被转发到后端的唯一Service上,在这种情况下Ingress无须定义任何rule。
apiVersion: v1
kind: Ingress
metadata:
name: test
spec:
backend:
serviceName: myweb
servicePort: 8080
2.同一域名下,不同的URL路径被转发到不同的服务上
这种配置常用于一个网站通过不同的路径提供不同的服务的场景,例如/web表示访问Web页面,/api表示访问API接口,对应到后端的两个服务,通过Ingress的设置很容易就能将基于URL路径的转发规则定义出来
apiVersion: v1
kind: Ingress
metadata:
name: test
spec:
rules:
- host: mywebsite.com
http:
paths:
- path: /web
backend:
serviceName: web-service
servicePort: 80
- path: /api
backend:
serviceName: api-service
servicePort: 8081
3.不同的域名(虚拟主机名)被转发到不同的服务上
这种配置常用于一个网站通过不同的域名或虚拟主机名提供不同服务的场景,例如foo.bar.com域名由service1提供服务,bar.foo.com域名由service2提供服务。
apiVersion: v1
kind: Ingress
metadata:
name: test
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
- host: bar.foo.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
4.不使用域名的转发规则
这种配置用于一个网站不使用域名直接提供服务的场景,此时通过任意一台运行ingress-controller的Node都能访问到后端的服务。
注意,使用无域名的Ingress转发规则时,将默认禁用非安全HTTP,强制启用HTTPS。例如,当使用Nginx作为Ingress Controller时,在其配置文件/etc/nginx/nginx.conf中将会自动设置规则,将全部HTTP的访问请求直接返回301错误;可以在Ingress的定义中设置一个annotation“ingress.kubernetes.io/ssl-redirect=false”来关闭强制启用HTTPS的设置。
apiVersion: v1
kind: Ingress
metadata:
name: test
annotations:
ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- path: /demo
backend:
serviceName: webapp
servicePort: 8080
Ingress的TLS安全设置
为了Ingress提供HTTPS的安全访问,可以为Ingress中的域名进行TLS安全证书的设置。设置的步骤如下。
(1)创建自签名的密钥和SSL证书文件。
可以通过OpenSSL工具直接生成密钥和证书文件,将命令行参数-subj中的/CN设置为网站域名:
上述命令将生成tls.key和tls.crt两个文件
(2)将证书保存到Kubernetes中的一个Secret资源对象上。
根据tls.key和tls.crt文件创建secret资源对象,有以下两种方法。
方法一:使用kubectl create secret tls命令直接通过tls.key和tls.crt文件创建secret对象。
kubectl create secret tls mywebsite-ingress-secret --key tls.key --cert tls.pem -n test
kubectl create secret tls dev-ingress-sceret --key tls.key --cert tls.crt -n dev
方法二:编辑mywebsite-ingress-secret文件,将tls.key和tls.crt文件的内容复制进去,使用kubectl create命令进行创建。
---
apiVersion: v1
kind: Secret
metadata:
name: mywebsite-ingress-secret
type: kubernetes.io/tls
data:
tls.crt:
MIIDAzCCAeugAwIBAgIJALrTg9VLmFgdMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNVBAMMDW15d2Vic2l0ZS5jb20wHhcNMTcwNDIzMTMwMjA1WhcNMzAxMjMxMTMwMjA1WjAYMRYwFAYDVQQDDA1teXdlYnNpdGUu UVT6uLXGhhunsu6bZ/qwsm2HzdPo4WRQ3z2VhgFzHEzHVVX+CEyZ8fJGoSi7njapHb08lRiztQ==
tls.key:
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCkvXLWurUjcRDkTQ+PNbwtzeF5bhZhPKQ86KwNP1mDJz5Ms8aP9gXhCcC6ghQBQ21c+WYg0q4P0XHOaHqrShIFVvjYFTRHM5O29oJU5T66gn0y Aml3sFqjmGKBNkzK+PlrUz2LBvuTjFECy4YKH+MM7x+Pq2AlbhZ/fXXK06uifz6ELfVyY6XZvRA=
(3)将该Secret对象设置到Ingress中。
创建Ingress对象,在tls段引用刚刚创建好的Secret对象
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: mywebsite-ingress-tls
spec:
tls:
- hosts:
- mywebsite.com
secretName: mywebsite-ingress-secret
rules:
- host: mywebsite.com
http:
paths:
- path: /demo
backend:
serviceName: myweb
servicePort: 8080
之后,就可以通过HTTPS来访问mywebsite.com了。
设置白名单:
在 Kubernetes 1.18 版本引入 IngressClass 资源和 ingressClassName 字段之前, Ingress 类是通过 Ingress 中的一个 kubernetes.io/ingress.class 注解来指定的。 这个注解从未被正式定义过,但是得到了 Ingress 控制器的广泛支持。
Ingress 中新的 ingressClassName 字段是该注解的替代品,但并非完全等价。 该注解通常用于引用实现该 Ingress 的控制器的名称, 而这个新的字段则是对一个包含额外 Ingress 配置的 IngressClass 资源的引用, 包括 Ingress 控制器的名称。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-myapp
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/whitelist-source-range: "192.168.8.0/24,203.205.219.128/25" # 访问白名单,多个地址用逗号隔开
spec:
rules:
- host: myapp.klvchen.com
http:
paths:
- path:
backend:
serviceName: myapp
servicePort: 80
版本升级:
Ingress和IngressClass的资源extensions/v1beta1 API和networking.k8s.io/v1beta1 API已经废弃,并且会在1.22版本之后被移除。请使用networking.k8s.io/v1替代。
注意:
如果域名经过了阿里云WAF防火墙(解析到了WAF的CNAME地址),白名单和证书都得在WAF上加才能生效,就算ingress上配置了证书和白名单也是无效的;如果域名不经过阿里云WAF,在ingress里配置白名单和证书是生效的。