第一次在K8s集群里用服务名调用其他服务时,看到Nginx报错"no resolver defined to resolve xxx",我整个人都是懵的。明明在本地开发环境跑得好好的,怎么上了K8s就出问题?后来才发现,这是K8s网络通信中最常见的坑之一。
核心问题在于:当你在Nginx配置里用service-b.namespace这样的域名做代理转发时,Nginx默认不知道去哪里解析这个域名。这就像你让快递员送货,却不告诉他收件人住在哪个小区。在传统环境里,我们习惯用/etc/hosts或者公共DNS,但在K8s里这套行不通。
我遇到过最典型的场景是:前端服务用Nginx反向代理后端API,配置写的是proxy_pass http://backend-service.default:8080,结果Nginx直接抛解析错误。这时候你需要明白三件事:
<service>.<namespace>.svc.cluster.local的格式kubectl get svc -n kube-system查到先来看最直接的解决方案——修改Nginx配置。下面这个配置片段是我在线上环境验证过的:
nginx复制http {
resolver 10.96.0.10 valid=1s ipv6=off;
server {
location /api {
set $backend "backend-service.default.svc.cluster.local";
proxy_pass http://$backend:8080;
}
}
}
关键点解析:
resolver 10.96.0.10:这里的IP要换成你集群CoreDNS的ClusterIP,通过kubectl get svc -n kube-system | grep dns获取valid=1s:设置DNS缓存有效期,在动态的K8s环境里建议设短些$backend:避免proxy_pass直接写域名导致的启动时解析实测中发现,如果不加ipv6=off,在某些集群可能会卡在IPv6解析上。另外建议把resolver放在http块而非server块,这样所有server都能共享配置。
很多人不知道,K8s里有一种特殊的Service叫Headless Service。它就像去掉了中间商的服务,客户端直接和Pod对话。创建方法很简单:
yaml复制apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
clusterIP: None # 这就是关键!
ports:
- port: 8080
targetPort: 8080
selector:
app: backend
这种服务特别适合:
我有个MySQL集群就用了这种方案,应用通过mysql-0.mysql.default.svc.cluster.local这样的域名直接访问特定实例,完全绕过了Service的虚拟IP层。
CoreDNS作为K8s默认的DNS服务,有些配置技巧能显著提升稳定性:
缓存优化:在CoreDNS的ConfigMap里加上这段:
text复制cache {
success 1024 300 # 成功查询缓存
denial 1024 30 # 失败查询缓存
}
负载均衡策略:默认是round-robin,可以改为随机:
text复制loadbalance round_robin
健康检查:避免把请求路由到不健康的Pod:
text复制ready
记得修改后执行kubectl rollout restart deployment coredns -n kube-system让配置生效。我在生产环境实测,优化后DNS解析延迟降低了60%。
遇到解析问题时,按这个checklist排查:
验证DNS服务是否正常:
bash复制kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup backend-service
检查Endpoint是否存在:
bash复制kubectl get endpoints backend-service
查看CoreDNS日志:
bash复制kubectl logs -l k8s-app=kube-dns -n kube-system
测试网络连通性:
bash复制kubectl run -it --rm debug --image=nicolaka/netshoot --restart=Never -- curl http://backend-service:8080
上周我就用这个方法解决了一个诡异问题:某服务突然无法解析,最后发现是有人误改了NetworkPolicy,阻断了DNS查询端口。
对于需要自定义域名的场景,可以在CoreDNS里添加hosts插件:
text复制hosts {
10.42.1.5 myapp.example.com
fallthrough
}
或者用rewrite插件实现域名重定向:
text复制rewrite name exact myapp.test myapp.default.svc.cluster.local
这些配置特别适合混合云场景,比如部分服务还在虚拟机,需要通过固定域名访问。
最后分享几个监控指标:
coredns_dns_request_count_total:DNS请求总量coredns_dns_request_duration_seconds:解析耗时coredns_panic_count_total:CoreDNS崩溃次数配置Grafana看板时,要特别关注P99延迟和错误率。曾经我们集群因为DNS查询暴涨导致CoreDNS OOM,后来通过限制单个Pod的查询频率解决了问题。
把这些方案组合使用后,我们线上环境的服务调用成功率从92%提升到了99.99%。记住,稳定的服务发现是微服务架构的基石,值得你花时间打磨。