前言:
此刻你们对“nginx负载外网”大体比较关注,大家都想要了解一些“nginx负载外网”的相关资讯。那么小编也在网摘上收集了一些关于“nginx负载外网””的相关知识,希望我们能喜欢,大家一起来学习一下吧!ingress-nginx是K8S中众多Ingress controller的其中一个,使用NGINX作为反向代理和负载均衡器,可将外部请求转发到K8S集群内部,以实现七层代理。
在生产环境中,一般使用外部的Nginx作为公网的统一访问入口,通过与ingress-nginx对接可以将请求转发到K8S集群。在不使用公有云的情况下,我们可以选择以下两种方式ingress-nginx部署方式。
Over a NodePort Service
一、部署
默认使用Deployment+nodePort部署
1. 先决条件通用部署命令
# yaml文件 wget 部署kubectl apply -f mandatory.yaml# 查看pod# kubectl get pod -n ingress-nginxNAME READY STATUS RESTARTS AGEnginx-ingress-controller-5bb8fb4bb6-kdvbg 1/1 Running 0 2m10s # 此时还没有svc# kubectl get svc -n ingress-nginxNo resources found in ingress-nginx namespace.
2.创建servcie,接收集群外部流量
wget apply -f service-nodeport.yaml# 查看svckubectl get svc -n ingress-nginxNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEingress-nginx NodePort 10.1.9.57 <none> 80:31596/TCP,443:30524/TCP 109s
3. 新建ingress规则
与其关联的service、deployment暂且忽略。
# vim ingress.yaml# 注意使用的是自定义namespace:testapiVersion: extensions/v1beta1kind: Ingressmetadata: name: helloworld namespace: testspec: rules: - host: hello.test.cn http: paths: - path: / backend: serviceName: helloworld servicePort: 8080# 应用kubectl apply -f ingress.yaml# kubectl get ing -n testNAME CLASS HOSTS ADDRESS PORTS AGEhelloworld <none> hello.test.cn 10.1.9.57 80 13s
4.测试
# 通过svc访问# curl -x 10.1.9.57:80 hello.test.cnHello,world!# 通过nodePort访问# curl -x 192.168.3.218:31596 hello.test.cnHello,world!
二、源地址转换
默认情况下,NodePort类型的服务执行源地址转换。 这意味着HTTP请求的源IP始终是从nginx接收到该请求的Kubernetes节点的IP地址。
通过查看service日志,我们发现访问来源地址的确都是集群内部IP,而不是实际的客户端IP。
# kubectl logs -f svc/ingress-nginx -n ingress-nginx10.244.0.0 - - [23/Jul/2020:07:48:33 +0000] "GET HTTP/1.1" 200 12 "-" "curl/7.29.0" 127 0.072 [test-helloworld-8080] [] 10.244.2.96:8080 12 0.072 200 1d2b39f8b24caace07ef56d7c22e13e710.244.1.0 - - [23/Jul/2020:07:48:59 +0000] "GET HTTP/1.1" 200 12 "-" "curl/7.29.0" 127 0.003 [test-helloworld-8080] [] 10.244.2.96:8080 12 0.004 200 9f912e99f7de3443deb62ba57ef0ff2510.244.1.0 - - [24/Jul/2020:00:09:30 +0000] "GET HTTP/1.1" 200 12 "-" "curl/7.58.0" 127 0.025 [test-helloworld-8080] [] 10.244.2.96:8080 12 0.025 200 da0a3886f5257769035003a96967e61e
此时我们可以在service上设置externalTrafficPolicy: Local解决。
vim service-nodeport.yaml# 在spec中添加如下一行externalTrafficPolicy: Local# 应用修改kubectl replace -f service-nodeport.yaml --force# 查看日志kubectl logs -f svc/ingress-nginx -n ingress-nginx# 此时真正的源IP已能够正常记录192.168.3.133 - - [24/Jul/2020:00:29:18 +0000] "GET HTTP/1.1" 200 12 "-" "curl/7.29.0" 127 0.002 [test-helloworld-8080] [] 10.244.2.96:8080 12 0.001 200 71518b244339f7ff945e1b5e3fd8279310.11.2.102 - - [24/Jul/2020:00:29:54 +0000] "GET HTTP/1.1" 200 12 "-" "curl/7.58.0" 127 0.002 [test-helloworld-8080] [] 10.244.2.96:8080 12 0.002 200 4dffef85c5765a5c8776bbd7965c9ea8
后遗症:
在未设置externalTrafficPolicy: Local前,nodePort允许我们访问任何node节点都可访问到service,但是在设置externalTrafficPolicy: Local后,我们只能通过访问实际运行ingress-nginx pod所在节点的node IP 。
# 未设置前curl -x 192.168.3.217:31596 hello.test.cnHello,world!curl -x 192.168.3.218:31596 hello.test.cnHello,world!curl -x 192.168.3.219:31596 hello.test.cnHello,world!# 设置后,由于replace重启了service,因此端口会更换# curl -x 192.168.3.217:30643 hello.test.cncurl: (7) Failed connect to 192.168.3.217:30643; Connection refused# curl -x 192.168.3.218:30643 hello.test.cncurl: (7) Failed connect to 192.168.3.218:30643; Connection refused# curl -x 192.168.3.219:30643 hello.test.cnHello,world!# kubectl get pod -n ingress-nginx -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESnginx-ingress-controller-5bb8fb4bb6-kdvbg 1/1 Running 0 17h 10.244.2.97 node-3-219 <none> <none>
ingress-nginx pod运行在192.168.3.219上,只能通过192.168.3.219:30643访问服务。
问题思考:
如果通过nodePort 方式接入外部负载均衡,由于设置`externalTrafficPolicy: Local`导致访问的node节点无法固定,再加上一旦service重启端口变化,势必会影响外部负载均衡无法正确转发流量。
下面我们通过解决pod单点故障问题,使pod在所有node节点运行,那么IP就可以固定了。
三、单点故障
基于Deployment+nodePort部署我们发现ingress-nginx 只有一个pod,由于`mandatory.yaml`中定义副本数为1,因此存在单点故障。
虽然我们可以将副本数改为2或多个解决单点问题,但是由于pod的端口固定为80//443,当pod调度分配到同一个节点时,会出现端口分配问题,这也正是Deployment类型的副本数默认为1的原因。
$ kubectl -n ingress-nginx describe pod <unschedulable-ingress-nginx-controller-pod>...Events: Type Reason From Message ---- ------ ---- ------- Warning FailedScheduling default-scheduler 0/3 nodes are available: 3 node(s) didn't have free ports for the requested pod ports.
这种情况我们可以通过将pod设置为DaemonSet解决,利用DaemonSet特性,保证每个节点运行pod。
注意:DaemonSet会在node、master点都运行,但因为master节点默认有污点NoSchedule,表示k8s将不会将pod调度到具有该污点的master节点上。
# vim mandatory.yaml # 1.将Deployment更改为DaemonSetapiVersion: apps/v1kind: DaemonSet# 2.删除replicas: 1# 3.应用kubectl apply -f mandatory.yaml # 注意:通过replace重载配置,并不会在节点上新建daemon类型pod;但是通过重新部署(delete后重新apply)才可以在node节点上创建DaemonSet类型的pod的。# 4.查看pod,应分布在集群的两个node节点上了。# kubectl get pod -n ingress-nginx -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESnginx-ingress-controller-gnx8l 1/1 Running 0 66m 10.244.2.98 uvmsvr-3-219 <none> <none>nginx-ingress-controller-sdn86 1/1 Running 0 66m 10.244.1.59 uvmsvr-3-218 <none> <none># 5.访问service# curl -x 192.168.3.218:31516 hello.test.cnHello,world!# curl -x 192.168.3.219:31516 hello.test.cnHello,world!
设置externalTrafficPolicy: Local并使用DaemonSet后,我们就可以在所有的node节点访问service了,但是由于nodeport暴露的端口是随机端口,即使在前面再搭建一套负载均衡器来转发请求,也需维护因service重启导致的端口变化问题。
NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定影响。下面我们来介绍Via the host network。
Via the host network
hostNetwork方式允许使用主机网络,即可以将pod的端口80和443直接绑定到Kubernetes宿主机网络上,直接通过宿主机IP+端口80/443访问服务,而无需NodePort Services施加额外的网络转换。
注意:由于此时外部请求直接访问pod所在节点的IP+port,并没有通过service访问,因此service可忽略,官方建议删除。
结合前面使用DaemonSet+hostNetwork部署。
# vim mandatory.yaml# 1.更改DaemonSetapiVersion: apps/v1kind: DaemonSet# 2.更改hostNetworktemplate: spec: hostNetwork: true# 应用,可不必应用service-nodeport.yamlkubectl apply -f deploy.yaml# 查看pod# kubectl get pod -n ingress-nginx -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESnginx-ingress-controller-7frnd 1/1 Running 0 10s 192.168.3.218 uvmsvr-3-218 <none> <none>nginx-ingress-controller-gqvrz 1/1 Running 0 10s 192.168.3.219 uvmsvr-3-219 <none> <none>```此时两个pod的IP不再是10.244.0.0段集群内部IP,而是node节点IP。我们可直接使用pod的80或443端口直接访问。```bash# 直接访问pod# curl -x 192.168.3.219:80 hello.test.cnHello,world! # curl -x 192.168.3.218:80 hello.test.cnHello,world!
通过HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/433端口就能访问服务。由于IP和端口固定,我们可以将pod直接暴露给外部的负载均衡使用。
这种方式没有经过nodePort的NAT,而是直接利用宿主机节点的网络和端口,性能会更高些。比较适合大并发的生产环境使用。
使用DaemonSet,当集群新加入新的node节点时会自动创建新的pod,由于hostNetwork下没有使用service,也就无法使用便签选择器selector自动添加新增的pod。如果接入外部负载均衡时,需手动添加新节点,这是此种部署的一个缺点。
总结
1. ingress-nginx通过调用k8s api 动态感知集群中pod的变化,动态更新配置文件nginx并重载nginx。配合外部负载均衡,可以很好的实现nginx配置的自动管理。
2. ingress-nginx接入外部负载均衡的要点是IP和端口尽量固定,否则外部负载均衡就无法定位到ingress-nginx。
通过以上两种部署方式,学习到了ingress-nginx的一些细节,帮助我们更好的了解并使用K8S。
参考:
标签: #nginx负载外网