K8S Ingress 七层负载均衡
1 Ingress 控制器介绍
在前面的章节中通过Service对集群之外暴露服务的主要方式有两种:
NotePort:该方式的缺点是会占用集群Node节点的端口,当集群服务变多时,这个缺点就愈发的明显(端口不够用)
LoadBalancer:该方式的缺点是每个service都需要一个外部负载均衡设备的支持才可以
Ingress相当于一个7层的负载均衡器,是k8s对反向代理的一个抽象,它的工作原理类似于Nginx反向代理
Ingress控制器种类有很多(以nginx为例)的工作原理:
用户编写Ingress规则,说明哪个域名对应集群中的Service
Ingress控制器动态感知Ingress服务规则的变化,然后生成一段对应的Nginx反向代理配置进行流量转发
2 Ingress 控制器种类
Kubernetes Ingress Controller
实现:Go/Lua(nginx 是用 C 写的)
许可证:Apache 2.0
Kubernetes 的“官方”控制器(之所以称为官方,是想把它区别于 NGINX 公司的控制器)。这是社区开发的控制器,它基于 nginx Web 服务器,并补充了一组用于实现额外功能的 Lua 插件。
由于 NGINX 十分流行,再加上把它用作控制器时所需的修改较少,它对于 K8s 普通工程师来说,可能是最简单和最直接的选择。
NGINX Ingress Controller
实现:Go
许可证:Apache 2.0
这是 NGINX 公司开发的官方产品,它也有一个基于 NGINX Plus 的商业版。NGINX 的控制器具有很高的稳定性、持续的向后兼容性,且没有任何第三方模块。
由于消除了 Lua 代码,和官方控制器相比,它保证了较高的速度,但也因此受到较大限制。相较之下,它的付费版本有更广泛的附加功能,如实时指标、JWT 验证、主动健康检查等。
NGINX Ingress 重要的优势是对 TCP/UDP 流量的全面支持,最主要缺点是缺乏流量分配功能。
Kong Ingress
实现:Go
许可证:Apache 2.0
Kong Ingress 由 Kong Inc 开发,有两个版本:商业版和免费版。它基于 NGINX 构建,并增加了扩展其功能的 Lua 模块。
最初,Kong Ingress 主要用作 API 网关,用于 API 请求的处理和路由。现在,它已经成为成熟的 Ingress 控制器,主要优点是拥有大量易于安装和配置的附加模块、插件(包括第三方插件)。它开启了控制器具备大量附加功能的先河,其内置函数也提供了许多可能性。Kong Ingress 配置是用 CRD 执行的。
Kong Ingress 的一个重要特性是它只能在一个环境中运行(而不支持跨命名空间)。这是一个颇有争议的话题:有些人认为这是一个缺点,因为必须为每个环境生成实例;而另一些人认为这是一个特殊特性,因为它是更高级别的隔离,控制器故障的影响仅限于其所在的环境。
Traefik
实现:Go
许可证:MIT
最初,这个代理是为微服务请求及其动态环境的路由而创建的,因此具有许多有用的功能:连续更新配置(不重新启动)、支持多种负载均衡算法、Web UI、指标导出、对各种服务的支持协议、REST API、Canary 版本等。
支持开箱即用的 Let’s Encrypt 是它的另一个不错的功能,但它的主要缺点也很明显,就是为了控制器的高可用性,你必须安装并连接其 Key-value store。
在 2019 年 9 月发布的 Traefik v2.0 中,虽然它增加许多不错的新功能,如带有 SNI 的 TCP/SSL、金丝雀部署、流量镜像/shadowing 和经过改进的 Web UI,但一些功能(如 WAF 支持)还在策划讨论中。
与新版本同期推出的还有一个名叫 Mesh 的服务网格,它建在 Traefik 之上,对kubernetes内部服务访问做到受控及被监控。
HAProxy Ingress
实现:Go(HAProxy 是用 C 写的)
许可证:Apache 2.0
HAProxy 是众所周知的代理服务器和负载均衡器。作为 Kubernetes 集群的一部分,它提供了“软”配置更新(无流量损失)、基于 DNS 的服务发现和通过 API 进行动态配置。 HAProxy 还支持完全自定义配置文件模板(通过替换 ConfigMap)以及在其中使用 Spring Boot 函数。
通常,工程师会把重点放在已消耗资源的高速、优化和效率上。而 HAProxy 的优点之一正是支持大量负载均衡算法。值得一提的是,在2020年 6 月发布的 v2.0 中,HAProxy 增加了许多新功能,其即将推出的 v2.1 有望带来更多新功能(包括 OpenTracing 支持)。
Voyager
实现:Go
许可证:Apache 2.0
Voyager 基于 HAProxy,并作为一个通用的解决方案提供给大量供应商。它最具代表性的功能包括 L7 和 L4 上的流量负载均衡,其中,TCP L4 流量负载均衡称得上是该解决方案最关键的功能之一。
在2020年早些时候,尽管 Voyager 在 v9.0.0 中推出了对 HTTP/2 和 gRPC 协议的全面支持,但总的来看,对证书管理(Let’s Encrypt 证书)的支持仍是 Voyager 集成的最突出的新功能。
Contour
实现:Go
许可证:Apache 2.0
Contour 和 Envoy 由同一个作者开发,它基于 Envoy。它最特别的功能是可以通过 CRD(IngressRoute)管理 Ingress 资源,对于多团队需要同时使用一个集群的组织来说,这有助于保护相邻环境中的流量,使它们免受 Ingress 资源更改的影响。
它还提供了一组扩展的负载均衡算法(镜像、自动重复、限制请求率等),以及详细的流量和故障监控。对某些工程师而言,它不支持粘滞会话可能是一个严重缺陷。
Istio Ingress
实现:Go
许可证:Apache 2.0
Istio 是 IBM、Google 和 Lyft 的联合开发项目,它是一个全面的服务网格解决方案——不仅可以管理所有传入的外部流量(作为 Ingress 控制器),还可以控制集群内部的所有流量。
Istio 将 Envoy 用作每种服务的辅助代理。从本质上讲,它是一个可以执行几乎所有操作的大型处理器,其中心思想是最大程度的控制、可扩展性、安全性和透明性。
通过 Istio Ingress,你可以对流量路由、服务之间的访问授权、均衡、监控、金丝雀发布等进行优化。
Ambassador
实现:Python
许可证:Apache 2.0
Ambassador 也是一个基于 Envoy 的解决方案,它有免费版和商业版两个版本。
Ambassador 被称为“Kubernetes 原生 API 微服务网关”,它与 K8s 原语紧密集成,拥有你所期望的从 Ingress controller 获得的功能包,它还可以与各种服务网格解决方案,如 Linkerd、Istio 等一起使用。
顺便提一下,Ambassador 博客日前发布了一份基准测试结果,比较了 Envoy、HAProxy 和 NGINX 的基础性能。
Gloo
实现:Go
许可证:Apache 2.0
Gloo 是在 Envoy 之上构建的新软件(于 2018 年 3 月发布),由于它的作者坚持认为“网关应该从功能而不是服务中构建 API”,它也被称为“功能网关”。其“功能级路由”的意思是它可以为后端实现是微服务、无服务器功能和遗留应用的混合应用路由流量。
由于拥有可插拔的体系结构,Gloo 提供了工程师期望的大部分功能,但是其中一些功能仅在其商业版本(Gloo Enterprise)中可用。
Skipper
实现:Go
许可证:Apache 2.0
Skipper 是 HTTP 路由器和反向代理,因此不支持各种协议。从技术上讲,它使用 Endpoints API(而不是 Kubernetes Services)将流量路由到 Pod。它的优点在于其丰富的过滤器集所提供的高级 HTTP 路由功能,工程师可以借此创建、更新和删除所有 HTTP 数据。
Skipper 的路由规则可以在不停机的情况下更新。正如它的作者所述,Skipper 可以很好地与其他
3 Nginx Ingress 环境搭建
ingress-nginx资源清单文件下载地址:https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml
提示:由于网络原因可能无法下载,直接使用我给大家下载好的文件即可,文件名:deploy.yml
创建目录,并上传文件到目录下
[root@master01 ~]# mkdir /ingress-nginx
[root@master01 ~]# cd /ingress-nginx
创建ingress-nginx
[root@master01 ingress-nginx]# kubectl create -f deploy.yaml
查看ns(会有一个ingress-nginx的命名空间)
[root@master01 ingress-nginx]# kubectl get ns
...
ingress-nginx Active 2m27s
查看详细信息时会出现如下报错:
# kubectl describe pod -n ingress-nginx
MountVolume.SetUp failed for volume "webhook-cert" : secret "ingress-nginx-admission-token-bnrl4" not found
#这个报错原因是当前运行的ingress-nginx-admission-token名称与deploys.yml文件中的名称不一致,需要对文件进行修改
解决方法:查看ingress的secret
[root@master01 ingress-nginx]# kubectl get secret -A | grep ingress
复制这个名称到deploy.yml文件替换默认的名称
[root@master01 ingress-nginx]# vim deploy.yaml
修改后再次更新资源文件
[root@master01 ingress-nginx]# kubectl apply -f deploy.yaml
查看ingress-nginx空间的pod(有两个Pod用于执行一次性任务,状态为Completed(完成),这种Pod执行后即退出。)
[root@master01 ingress-nginx]# kubectl get po -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create-cctfh 0/1 Completed 0 28m
ingress-nginx-admission-patch-rhzrk 0/1 Completed 1 28m
ingress-nginx-controller-9d98d6467-2wtnj 1/1 Running 0 23m
查看service
[root@master01 ingress-nginx]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.99.98.180 <none> 80:31770/TCP,443:31082/TCP 17m
ingress-nginx-controller-admission ClusterIP 10.97.42.155 <none> 443/TCP 17m
#提示:到此为止ingress-nginx的控制器已经安装完毕
4 Nginx Ingress HTTP 应用案例
案例:通过Deployment部署tomcat与nginx的pod,并通过Nginx Ingress 进行HTTPS访问
[root@master01 ~]# vim ingress-httpd.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-nginx
namespace: test
spec:
selector:
app: deploy-nginx
clusterIP: None
type: ClusterIP #service类型
ports:
- port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-tomcat
namespace: test
spec:
selector:
matchLabels:
app: deploy-tomcat
template:
metadata:
labels:
app: deploy-tomcat
spec:
containers:
- name: tomcat
image: tomcat:8.5-jre10-slim
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: svc-tomcat
namespace: test
spec:
selector:
app: deploy-tomcat
clusterIP: None
type: ClusterIP #service类型
ports:
- port: 8080
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-http #自定义ingress名称
namespace: test
annotations:
ingressclass.kubernetes.io/is-default-class: "true" # 指定spec下方的rules的path可以使用正则表达式,如果我们没有使用正则表达式,此项则可不使用
kubernetes.io/ingress.class: nginx #指定控制器的类别为nginx
spec:
rules: #定义主机列表
- host: www.nginx.com #自定义域名
http:
paths:
- pathType: Prefix #路径类型
path: "/" #定义站点路径
backend: #定义后端引用的服务
service: #关联service
name: svc-nginx #对应上面创建的service名称
port:
number: 80 #service端口
- host: www.tomcat.com #自定义域名
http:
paths:
- pathType: Prefix #路径类型
path: "/" #定义站点路径
backend: #定义后端引用的服务
service: #关联service
name: svc-tomcat #对应上面创建的service名称
port:
number: 8080 #service端口
#### 创建ingress报错
[root@master01 data]# kubectl apply -f ingress-nginx.yml
Error from server (InternalError): error when creating "ingress-nginx.yml": Internal error occurred: failed calling webhook "validate.nginx.ingress.kubernetes.io": failed to call webhook: Post "https://ingress-nginx-controller-admission.ingress-nginx.svc:443/networking/v1/ingresses?timeout=10s": remote error: tls: internal error
查看ingress-nginx-admission
# kubectl get validatingwebhookconfigurations
删除ingress-nginx-admission
# kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission
重新创建ingress
# kubectl apply -f ingress-nginx.yml
查看信息
[root@master01 ~]# kubectl get all -n test
查看ingress信息
[root@master01 ~]# kubectl get ing -n test
查看详细信息
[root@master01 ~]# kubectl describe ing -n test
5 测试Ingress HTTP 代理
浏览器访问由于域名无法正常解析,需要在windows内进行解析:C:\Windows\System32\drivers\etc
192.168.1.43 www.nginx.com
192.168.1.43 www.tomcat.com
访问测试:在访问测试时,通过域名与ingress对外暴露的端口进行访问
查看ingress-nginx暴露的端口
[root@master01 ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.97.31.167 <none> 80:30256/TCP,443:31232/TCP 21
访问测试:注意80对应的是HTTP端口,443对应的是HTTPS端口
删除ingress http
[root@master01 ~]# kubectl delete -f ingress-http.yml
6 Nginx Ingress HTTPS 应用案例
案例:通过Deployment部署tomcat与nginx的pod,并通过Nginx Ingress 进行HTTPS访问
生成证书
[root@master01 ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=TJ/O=nginx/CN=thinkmo.com"
创建密钥
[root@master01 ~]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt
创建ingress https
[root@master ~]# vim ingress-https.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-nginx
namespace: test
spec:
selector:
matchLabels:
app: deploy-nginx
template:
metadata:
labels:
app: deploy-nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: svc-nginx
namespace: test
spec:
selector:
app: deploy-nginx
clusterIP: None
type: ClusterIP #service类型
ports:
- port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-tomcat
namespace: test
spec:
selector:
matchLabels:
app: deploy-tomcat
template:
metadata:
labels:
app: deploy-tomcat
spec:
containers:
- name: tomcat
image: tomcat:8.5-jre10-slim
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: svc-tomcat
namespace: test
spec:
selector:
app: deploy-tomcat
clusterIP: None
type: ClusterIP #service类型
ports:
- port: 8080
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-https #自定义ingress名称
namespace: test
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
kubernetes.io/ingress.class: nginx #注释名称需为nginx(不可省略)
spec:
tls:
- hosts:
- www.nginx.com #指定域名使用的密钥
- www.tomcat.com #指定域名使用的密钥
secretName: tls-secret #指定密钥
rules: #定义主机列表
- host: www.nginx.com #自定义域名
http:
paths:
- pathType: Prefix #路径类型
path: "/" #定义站点路径
backend: #定义后端引用的服务
service: #关联service
name: svc-nginx #对应上面创建的service名称
port:
number: 80 #service端口
- host: www.tomcat.com #自定义域名
http:
paths:
- pathType: Prefix #路径类型
path: "/" #定义站点路径
backend: #定义后端引用的服务
service: #关联service
name: svc-tomcat #对应上面创建的service名称
port:
number: 8080 #service端口
创建Pod
[root@master01 ~]# kubectl create -f ingress-https.yml
ingress.extensions/ingress-https created
查看ingress信息
[root@master01 ~]# kubectl get ing ingress-https -n test
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-https <none> www.nginx.com,www.tomcat.com 192.168.0.13 80, 443 5m37s
查看详细信息
[root@master ~]# kubectl describe ing ingress-https -n dev
...
tls-secret terminates www.nginx.com,www.tomcat.com #密钥
...
查看ingress-nginx端口
[root@master01 ~]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.97.31.167 <none> 80:30256/TCP,443:31232/TCP 22h
访问测试(注意协议https):访问443对应的端口
评论区