如何在k8s中实现应用的负载均衡
1.负载均衡是什么?
负载均衡是由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无需其他服务器的辅助。通过某种负载分担技术,将外部发送来的请求按照某种策略分配到服务器集合的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。负载均衡解决了大量并发访问服务问题,其目的就是用最少的投资获得接近于大型主机的性能。
2.在接触k8s之前大家都了解哪些负载均衡方案?
- 四层负载均衡:lvs(软件层面)、F5(硬件层面)
缺点:对网络依赖较大,负载智能化方面没有7层负载好(比如不支持对url个性化负载),F5硬件性格很高但成本也高,需要人民币几十万元,对于小公司就望而止步。 - 七层负载均衡:Nginx、Apache
优点:对网络依赖少,负载智能方案多(比如可根据不同的url进行负载)
3.在k8s中为什么要做负载均衡?
- Pod漂移问题
Kubernetes具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等。通俗地说,这个Pod可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着Pod的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的Pod IP暴露出去?这里借助于Kubernetes的 Service 机制,Service可以以标签的形式选定一组带有指定标签的Pod,并监控和自动负载他们的Pod IP,那么我们向外暴露只暴露Service IP就行了;这就是NodePort模式:即在每个节点上开起一个端口,然后转发到内部Pod IP 上。4.使用service做四层负载均衡
在kubernetes中,Pod是有生命周期的,如果Pod重启IP很有可能会发生变化。如果我们的服务都是将Pod的IP地址写死,Pod的挂掉或者重启,和刚才重启的pod相关联的其他服务将会找不到它所关联的Pod,为了解决这个问题,在kubernetes中定义了service资源对象,Service 定义了一个服务访问的入口,客户端通过这个入口即可访问服务背后的应用集群实例,service是一组Pod的逻辑集合,这一组Pod能够被Service访问到,通常是通过Label Selector实现的。
可以看下面的图:
那我们通过Service访问k8s内部应用的时候数据包走向是什么样的呢?
此时的数据包流向如下:
客户端请求–>node节点的ip:端口 –>service的ip:端口 –> pod的ip:端口
5.在k8s为什么要引入七层负载均衡?
- 端口管理问题
采用service的NodePort方式暴露服务面临的问题是,服务一旦多起来,NodePort在每个节点上开启的端口会及其庞大,而且难以维护。
6.四层负载均衡和七层负载均衡对比分析
1)四层的负载均衡就是基于IP+端口的负载均衡:在三层负载均衡的基础上,通过发布三层的IP地址(VIP),然后加四层的端口号,来决定哪些流量需要做负载均衡,对需要处理的流量进行NAT处理,转发至后台服务器,并记录下这个TCP或者UDP的流量是由哪台服务器处理的,后续这个连接的所有流量都同样转发到同一台服务器处理。
2)七层的负载均衡就是基于虚拟的URL或主机IP的负载均衡:在四层负载均衡的基础上(没有四层是绝对不可能有七层的),再考虑应用层的特征,比如同一个Web服务器的负载均衡,除了根据VIP加80端口辨别是否需要处理的流量,还可根据七层的URL、浏览器类别、语言来决定是否要进行负载均衡。举个例子,如果你的Web服务器分成两组,一组是中文语言的,一组是英文语言的,那么七层负载均衡就可以当用户来访问你的域名时,自动辨别用户语言,然后选择对应的语言服务器组进行负载均衡处理。
7.实战:测试Ingress HTTP代理k8s内部站点
- 部署后端tomcat服务
[root@k8s-master1 tomcat]# cat tomcat.yaml
apiVersion: v1
kind: Service
metadata:
name: tomcat
namespace: default
spec:
selector:
app: tomcat
release: canary
ports:
- name: http
targetPort: 8080
port: 8080
- name: ajp
targetPort: 8009
port: 8009
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: tomcat
release: canary
template:
metadata:
labels:
app: tomcat
release: canary
spec:
containers:
- name: tomcat
image: tomcat:8.5.34-jre8-alpine
ports:
- name: http
containerPort: 8080
name: ajp
containerPort: 8009
[root@k8s-master1 tomcat]# kubectl apply -f tomcat.yaml
service/tomcat unchanged
deployment.apps/tomcat-deploy created
[root@k8s-master1 tomcat]#
[root@k8s-master1 tomcat]# kubectl get pods
NAME READY STATUS RESTARTS AGE
tomcat-deploy-66b67fcf7b-2nt5w 1/1 Running 0 21s
tomcat-deploy-66b67fcf7b-n6nzn 1/1 Running 0 21s
[root@k8s-master1 tomcat]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 34d
tomcat ClusterIP 10.0.0.160 <none> 8080/TCP,8009/TCP 2m12s
[root@k8s-master1 tomcat]#
- 编写ingress规则
[root@k8s-master1 tomcat]# cat ingress-tomcat.yaml
apiVersion: extensions/v1beta1 #api版本
kind: Ingress #清单类型
metadata: #元数据
name: ingress-tomcat #ingress的名称
namespace: default #所属名称空间
annotations: #注解信息
kubernetes.io/ingress.class: "nginx"
spec: #规格
rules: #定义后端转发的规则
- host: tomcat.hebye.com #通过域名进行转发
http:
paths:
- path: #配置访问路径,如果通过url进行转发,需要修改;空默认为访问的路径为"/"
backend: #配置后端服务
serviceName: tomcat
servicePort: 8080
[root@k8s-master1 tomcat]# kubectl apply -f ingress-tomcat.yaml
- 查看ingress
[root@k8s-master1 tomcat]#
[root@k8s-master1 tomcat]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-tomcat <none> tomcat.hebye.com 80 3s
[root@k8s-master1 tomcat]#
[root@k8s-master1 tomcat]# kubectl describe ingress ingress-tomcat
Name: ingress-tomcat
Namespace: default
Address:
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
Host Path Backends
---- ---- --------
tomcat.hebye.com
tomcat:8080 (10.244.2.204:8080,10.244.2.205:8080)
Annotations: kubernetes.io/ingress.class: nginx
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CREATE 38s nginx-ingress-controller Ingress default/ingress-tomcat
[root@k8s-master1 tomcat]#
- 测试访问
8.实战:测试Ingress HTTPS代理tomcat
1.生成自签证书(生产环境到CA机构购买证书)
[root@k8s-master1 tomcat-ssl]# openssl genrsa -out tls.key 2048
[root@k8s-master1 tomcat-ssl]# openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=tomcat.hebye.com
[root@k8s-master1 tomcat-ssl]# ls
tls.crt tls.key
2.创建secret
[root@k8s-master1 tomcat-ssl]# kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key
secret/tomcat-ingress-secret created
[root@k8s-master1 tomcat-ssl]#
[root@k8s-master1 tomcat-ssl]# kubectl get secret
NAME TYPE DATA AGE
default-token-xwj2j kubernetes.io/service-account-token 3 34d
petclinic-secret Quaque 2 29d
tomcat-ingress-secret kubernetes.io/tls 2 17s
[root@k8s-master1 tomcat-ssl]# kubectl describe secrets tomcat-ingress-secret
Name: tomcat-ingress-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: kubernetes.io/tls
Data
====
tls.crt: 1294 bytes
tls.key: 1675 bytes
3.创建ingress规则
[root@k8s-master1 tomcat-ssl]# cat ingress-tomcat-ssl.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-tomcat-tls
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- tomcat.hebye.com
secretName: tomcat-ingress-secret
rules:
- host: tomcat.hebye.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat
port:
number: 8080
[root@k8s-master1 tomcat-ssl]# kubectl apply -f ingress-tomcat-ssl.yaml
ingress.networking.k8s.io/ingress-tomcat-tls created
[root@k8s-master1 tomcat-ssl]#
[root@k8s-master1 tomcat-ssl]# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-tomcat-tls <none> tomcat.hebye.com 80, 443 23s
[root@k8s-master1 tomcat-ssl]#
Ingress规则可以参考官方:
https://kubernetes.io/zh/docs/concepts/services-networking/ingress/
测试访问:https://tomcat.hebye.com/