在k8s中Nginx不能解析hostname
1. 简介
1.1 目的
本文档旨在描述 Kubernetes 环境中 Nginx 无法解析 hostname 的问题,提供可能的原因分析、排查步骤以及解决方案,帮助运维人员和开发人员快速解决该问题。
1.2 适用范围
本文档适用于在 Kubernetes 集群中部署 Nginx 作为反向代理或前端服务器,并遇到无法解析 hostname 问题的场景。
1.3 相关人员
运维人员、开发人员和技术支持人员
2. 问题描述
2.1 问题场景
在 Kubernetes 集群中,Nginx 通常用于接收和处理外部请求,并将这些请求代理到内部服务。然而,有时 Nginx 无法解析指定的 hostname,导致无法将请求正确路由到目标服务或外部资源。例如,下面的配置示例展示了一个常见的 Nginx 配置:
server {
listen 80;
server_name _;
index index.jsp index.html index.htm index.php default.html default.htm default.php;
root /usr/share/nginx/html/;
client_max_body_size 500m;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 4 8k;
proxy_busy_buffers_size 12k;
access_log /dev/stdout main;
error_log /dev/stderr info;
location / {
try_files $uri $uri/ /index.html;
}
location /backend/ {
proxy_next_upstream error timeout http_500 http_502 http_503 http_504 http_404;
proxy_read_timeout 60s;
proxy_set_header Connection "";
proxy_connect_timeout 60;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://td-ba-coding-devops-guide-prod.prod.svc.cluster.local:80?$query_string;
}
}
在这种配置下,当客户端访问 /backend/
URL 时,可能会出现如下错误:
[error] 9#9: *5 no resolver defined to resolve td-ba-coding-devops-guide-prod.prod.svc.cluster.local, client: 10.20.102.253, server: _, request: "GET /backend?hi=11 HTTP/1.1", host: "coding-devops-guide.teddymobile.net"
此错误表明 Nginx 无法解析 td-ba-coding-devops-guide-prod.prod.svc.cluster.local
这个 hostname,导致请求无法正确转发到后端服务。可使用kubectl exec -it ** -- nslookup
命令查询svc在k8s中的域名的 DNS 记录时,发现是可以正确解析到相应的IP地址:
2.2 问题原因分析
-
Kubernetes DNS 服务工作原理
在 Kubernetes 集群中,CoreDNS 负责处理所有内部服务的 DNS 解析请求。当 Nginx 作为前端服务器使用时,需要通过 CoreDNS 来解析集群内其他服务的 hostname,以及处理外部域名解析请求。因此,CoreDNS 的正确配置对于 Nginx 能否正常解析 hostname 至关重要。
-
Nginx 配置中的 hostname 解析逻辑
Nginx 使用
resolver
指令来指定要使用的 DNS 服务器,以解析配置文件中定义的 hostname。如果resolver
指令未正确配置,或者未指定合适的 DNS 服务器,Nginx 将无法解析 hostname,从而导致请求失败。 -
常见的 DNS 配置错误
- CoreDNS 配置问题: CoreDNS 配置文件中的错误可能会导致 DNS 解析失败。例如,缺少必要的
upstream
配置可能会导致无法正确解析外部域名。 - Nginx 配置错误: 如果 Nginx 配置文件中的
resolver
指令没有指定正确的 DNS 服务器,或者指定了错误的 IP 地址,Nginx 将无法解析 hostname。这可能导致内部服务之间的通信问题,或者导致无法解析外部域名。
- CoreDNS 配置问题: CoreDNS 配置文件中的错误可能会导致 DNS 解析失败。例如,缺少必要的
3. 排查步骤
3.1 检查 DNS 服务状态
-
检查 CoreDNS Pod 状态 使用
kubectl get pods -n kube-system -l k8s-app=kube-dns
查看 CoreDNS Pod 的运行状态,确保其正常运行。> kubectl get pods -n kube-system -l k8s-app=kube-dns NAME READY STATUS RESTARTS AGE coredns-549dfbdc5c-96ccs 1/1 Running 0 34d coredns-549dfbdc5c-dk47s 1/1 Running 0 34d coredns-549dfbdc5c-jmvjw 1/1 Running 0 34d coredns-549dfbdc5c-kmr95 1/1 Running 0 34d coredns-549dfbdc5c-zb8tz 1/1 Running 0 34d
-
查看 CoreDNS 配置 使用
kubectl -n kube-system describe configmap coredns
查看 CoreDNS 的配置文件,确认配置无误。
3.2 验证 Kubernetes 集群 DNS 解析
-
使用
nslookup
或dig
命令测试解析 在问题 Pod 中运行nslookup <hostname>
或dig <hostname>
,验证 DNS 解析是否正确。> kubectl exec -it td-ba-coding-react-front-devops-guide-prod-f54f5968f-wsnc5 -n prod -- nslookup td-ba-coding-devops-guide-prod.prod.svc.cluster.local Server: 172.16.29.150 Address: 172.16.29.150#53 Name: td-ba-coding-devops-guide-prod.prod.svc.cluster.local Address: 172.16.38.234
nslookup
成功解析表明 Kubernetes 的 DNS 系统正常工作,但 Nginx 由于缺乏resolver
指令,无法利用这套 DNS 系统进行解析。 -
测试不同命名空间的解析 验证其他命名空间中的 DNS 解析是否正常,以排除命名空间特定问题。
3.3 合理的猜测
Nginx 默认在启动时解析配置文件中的域名并将其缓存。如果配置文件中的域名(如 td-ba-coding-devops-guide-prod.prod.svc.cluster.local
)在 Nginx 启动后发生变化,或者在运行时才需要解析,Nginx 将无法动态解析这些域名。resolver
指令用于告诉 Nginx 在请求期间如何解析 DNS,这在处理动态或变化的 DNS 解析时非常重要。
当 Nginx 处理请求时,如果没有配置 resolver
指令,它会无法解析 hostname,从而产生 no resolver defined to resolve
的错误。这意味着 Nginx试图解析一个未缓存或需要动态解析的域名,但没有指定用于解析的 DNS 服务器。
4. 解决方案
在 Nginx 配置中添加 resolver
指令,指向 Kubernetes 集群的 DNS 服务器。例如:
如:
resolver kube-dns.kube-system.svc.cluster.local valid=30s;
或者直接使用 IP 地址:
resolver 172.16.29.150 valid=30s;
这将告诉 Nginx 使用指定的 DNS 服务器来解析 hostname,并且每隔 30
秒重新验证(更新)解析结果。
完整配置示例:
server {
listen 80;
server_name _;
index index.jsp index.html index.htm index.php default.html default.htm default.php;
root /usr/share/nginx/html/;
resolver kube-dns.kube-system.svc.cluster.local valid=30s;
client_max_body_size 500m;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 4 8k;
proxy_busy_buffers_size 12k;
access_log /dev/stdout main;
error_log /dev/stderr info;
location / {
try_files $uri $uri/ /index.html;
}
location /backend/ {
proxy_next_upstream error timeout http_500 http_502 http_503 http_504 http_404;
proxy_read_timeout 60s;
proxy_set_header Connection "";
proxy_connect_timeout 60;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://td-ba-coding-devops-guide-prod.prod.svc.cluster.local:80/hello?$query_string;
}
}