使用nginx的ngx_upstream_jdomain模块实现k8s容器的负载均衡
Posted 运维者说
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用nginx的ngx_upstream_jdomain模块实现k8s容器的负载均衡相关的知识,希望对你有一定的参考价值。
使用背景
最近一直在准备k8s上线事宜,目前已经在测试环境中全面部署并通过压力测试环境检验。离正式上线基本只剩下时间问题。我们目前测试环境中的容器负载均衡大量使用到了nginx,就是借助了ngx_upstream_jdomain模块,从而放弃了k8s官方的ingress。
在这里简单说下k8s的ingress。k8s官方的ingress controller其实也是通过nginx来实现的,但是Ingress本身依赖于service,它通过查询service的映射,来找到service后端的pod的真实ip,并将其挂载到ingress controll的upstream中来实现负载均衡。这本身其实并没有什么问题。但由于在我们的k8s中,鉴于标准service基于kube-proxy的转发效率不高,我们放弃了标准service。转而直接采用了headless service的方式。这种方式的好处是,dns解析会直接解析到每个pod的ip,而不再解析到service ip,也不再需要kube-proxy来实现转发。缺点是负载均衡只能依赖dns轮循,没有灵活的调度策略,但毫无疑问,由于去除了kube-proxy这个中间层,转发效率得到了提高。另外,由于我们直接打通了Pod与物理服务器之间的网络,物理网络中的主机可以与Pod之间通信,如果在中间采用标准的service,service的ip反而无法与物理网络直接实现通信。
这样一来,我们外部的负载均衡就没办法再去依赖Ingress了,我们采用了在外部部署nginx来实现负载均衡的方法,由于upstream里的pod ip会动态变化,所以我们不能直接在upstream里写死pod的ip地址,而只能用service的域名来替代,并让nginx自己去解析这个域名,我们知道headless service的域名由于没有内部的service ip,所以是直接解析到pod ip上的,这样就等于动态拿到了pod ip。在这种情况下,nginx_upstream_jdomain模块就登场了。
配置
在具体的配置之前,还得说下,nginx_upstream_jdomain这个模块严重依赖dns解析,另外由于其代理的后端的upstream中的pod ip经常性发生变化,所以dns缓存时间还不能太长。这是一个大坑,在初次配置的时候,以默认值配置resolver,结果我后端pod ip发生变更以后,发现nginx死活还是代理到之前的ip地址,后来一查才发现,默认resolver缓存5分钟,在传统应用中,这个缓存时间甚至可以调的更长,但在docker应用中,这个值需要尽可能的短。
ngx_upstream_jdomain的详细配置可以参考这里:https://www.nginx.com/resources/wiki/modules/domain_resolve/
我这里就给出一个示例配置:
resolver 192.168.1.1 valid=1s; resolver_timeout 3s; upstream www-stress-80 { jdomain www-stress.default.svc.wh01 port=80; } server { server_name www.stress.test.com; listen 80; #set $proxy_upstream_name "-"; location / { #Proxy Settings proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header CDN-SRC-IP $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; proxy_max_temp_file_size 0; proxy_connect_timeout 30; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; proxy_pass http://www-stress-80; } }
另外,还需要说明的是,通过这种方式代理到后端的服务,后端服务接收到的$host的值即为www-stress-80,如果后端服务以主机头的方式来接受服务,这显然是不能接受的。所以在代理配置中,必须加上如下配置以将主机头传递给后端服务器:
proxy_set_header Host $host;
以上是关于使用nginx的ngx_upstream_jdomain模块实现k8s容器的负载均衡的主要内容,如果未能解决你的问题,请参考以下文章