文章目录
- 1. 问题
- 2.解决办法
- 3.扩展说明
- 3.1 DNS解析阶段划分
- 3.2 问题说明
- 3.2.1 先看/etc/resolv.conf说明
- 3.2.2 针对第一个问题
- 3.2.3 针对第二个问题
【后端】Nginx+lua+OpenResty高性能实践
参考: https://blog.csdn.net/u010837612/article/details/123275026
1. 问题
在k8s
中使用nginx
作为后端接口反向代理,大概配置如下:
location /api {proxy_set_header X-Forwarded-Proto $scheme;proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_pass http://api-server-svc:8080/;}
其中api-server-svc
是后端服务的serviceName
这个配置会有两个问题:
1.要求
api-server-svc
这个service
要先创建,否则nginx启动时会因为无法解析api-server-svc
而启动失败
2.·nginx·服役期间,如果后端服务重启
(这里指的容器重新创建,并非更新镜像,因为更新镜像ip不会变动,还是原来容器的),svc
ip改变了,代理会失败,因为nginx缓存了旧ip
2.解决办法
修改nginx
配置如下:
# dns设置缓存时间5s,解决问题2resolver kube-dns.kube-system.svc.cluster.local valid=300s;# 使用变量方式,解决问题1set $apiserver api-server-svc.xxx.svc.cluster.local;location /api {proxy_set_header X-Forwarded-Proto $scheme;proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;rewrite /api/(.*) /$1 break;proxy_pass http://$apiserver:8080;}
set $apiserver api-server-svc.xxx.svc.cluster.local;
中域名一定要写全域名,不能简写成api-server-svc
。
之前之所以可以简写,因为容器/etc/resolv.conf
中有配置了search
,在解析域名时会自动帮你补全域名。
但此处我们使用了resolver
指定了域名服务器,在解析时是不会自动帮我们补全的
3.扩展说明
3.1 DNS解析阶段划分
一般来说,Nginx在
配置解析阶段
(即Nginx启动时读取配置文件并解析配置的阶段)和请求处理阶段
(即Nginx接收并处理客户端请求的阶段)对域名的处理方式是不同的。
配置解析阶段:
- 在这个阶段,如果Nginx配置文件中直接使用了
域名
(而不是通过变量引用),Nginx会在启动时尝试解析这些域名。这个解析过程通常是同步且阻塞的,Nginx会使用系统配置的DNS服务器(如/etc/resolv.conf
中指定的DNS服务器)来解析域名。- 如果在配置文件中使用了变量来引用域名(例如,在set指令中设置了一个变量来存储域名),并且这个变量在请求处理阶段被用于反向代理或重定向等场景,那么域名的解析可能会推迟到
请求处理阶段
进行。请求处理阶段:
- 在请求处理阶段,如果Nginx需要根据变量中的域名进行动态解析(例如,在proxy_pass指令中使用了变量),Nginx可以使用其内置的动态DNS解析机制。这个机制允许Nginx在需要时根据配置的DNS服务器(通过
resolver
指令指定)来解析域名。resolver
指令可以在http块、server块或location块中设置,用于指定Nginx用于动态DNS解析的DNS服务器地址。Nginx会按照这些地址的顺序尝试解析域名,直到成功为止。- 如果在Nginx配置中使用了
resolver
指令,并且变量中的域名在请求处理阶段被用于需要DNS解析的场景,那么Nginx就会根据resolver
指令中指定的DNS服务器来解析这个域名,而不会去读取/etc/resolv.conf
文件。这是因为resolver指令已经明确告诉了Nginx应该使用哪些DNS服务器进行解析。- k8s中一般都是这个DNS解析服务器:
kube-dns.kube-system.svc.cluster.local ;
- 一般配置了set 域名,都要搭配使用resolver:如果
没有配置 resolver
,Nginx可能会依赖于系统默认的DNS解析设置(如/etc/resolv.conf文件)
,但这并不是Nginx直接的行为,而是系统层面的行为。然而,需要注意的是,Nginx在处理域名解析时并不一定会直接读取/etc/resolv.conf
文件,特别是在一些特定配置或环境下
。(配置set 要配置resolver,因为至少我在docker中测试时,如果不配置resovler,在请求处理阶段,并不会去根据/etc/resolv.f
解析域名)
必须配置resolver
:如果Nginx配置中使用了变量来存储需要解析的域名,并且这个域名在请求处理阶段被使用,那么通常需要在Nginx配置中显式地配置resolver指令,以指定用于解析域名的DNS服务器。系统默认行为可能不适用
:虽然Nginx可能会依赖于系统默认的DNS解析设置,但在Nginx配置中明确指定resolver是更可靠和可控的做法。
3.2 问题说明
3.2.1 先看/etc/resolv.conf说明
3.2.2 针对第一个问题
如果是
proxy_pass: http://serviceName:port
,那么启动时默认情况会去根据/etc/resolv.conf
的search字段拼接成serviceName.namespace.svc.cluster.local
,然后根据这个域名去nameserver
指定的域名服务器解析,解析到serviceName的ip地址,会进行缓存,后续访问就会使用,如ip1是:10.96.3.33
但是如果这个服务不存在,ip1就会拿不到,从而导致启动nginx失败。
报错:host not found in upstream “aaa” in /etc/nginx/nginx.conf:63
如果使用
set
指定域名,那么这个域名会到请求阶段才会解析
3.2.3 针对第二个问题
需要用到
set
自定义变量,请求时才解析域名,这里按理说只配置serviceName
解析即可,(按照理解,默认会去根据/etc/resolv.conf
解析),但是请求时并没有去解析/etc/resolv.conf
,从而无法根据search
自动补全,所以这里需要配置完整的路径serviceName.namespace.svc.cluster.local
; 同时也需要指定resolver
,去明确指定DNS服务器,否则会报错(no resolver defined to resolve throwbill.zj-ywxt-ns.svc.cluster.local)
resolver kube-dns.kube-system.svc.cluster.local valid=120s;