Kubernetes 中的 NGINX 无法解析 DNS

Posted

技术标签:

【中文标题】Kubernetes 中的 NGINX 无法解析 DNS【英文标题】:DNS does not resolve with NGINX in Kubernetes 【发布时间】:2017-04-02 15:14:21 【问题描述】:

我有一个使用 kube-aws 设置的 Kubernetes 集群。我正在尝试运行自定义 nginx 配置,该配置使用 DNS 解析来代理_pass。这是 NGINX 代码块

location /api/v1/lead 
  resolver 10.3.0.10 ipv6=off;
  set $container lead-api;
  proxy_pass http://$container:3000;

10.3.0.10 来自 Kubernetes 中找到的 DNS 服务的集群 IP。我还尝试了 127.0.0.11,这是我们在 docker-compose/docker 环境中使用的。

$ kubectl describe --namespace=kube-system service kube-dns
Name:                   kube-dns
Namespace:              kube-system
Labels:                 k8s-app=kube-dns
                        kubernetes.io/cluster-service=true
                        kubernetes.io/name=KubeDNS
Selector:               k8s-app=kube-dns
Type:                   ClusterIP
IP:                     10.3.0.10
Port:                   dns     53/UDP
Endpoints:              10.2.26.61:53
Port:                   dns-tcp 53/TCP
Endpoints:              10.2.26.61:53
Session Affinity:       None

此配置适用于使用 docker-compose 的三种不同环境。但是,我在 Kubernetes 集群的 NGINX 日志中收到以下错误

[error] 9#9: *20 lead-api 无法解析(2:服务器故障),客户端:10.2.26.0,服务器:,请求:“GET /api/v1/lead/661DF757-722B- 41BB-81BD-C7FD398BBC88 HTTP/1.1"

如果我在 NGINX pod 中运行 nslookup,我可以使用相同的 dns 服务器解析主机:

$ kubectl exec nginx-1855584872-kdiwh -- nslookup lead-api
Server:         10.3.0.10
Address:        10.3.0.10#53

Name:   lead-api.default.svc.cluster.local
Address: 10.3.0.167

我不知道这是否重要,但请注意错误的“服务器”部分为空。当我查看 dnsmasq 的 pod 日志时,我看不到任何相关内容。如果我将 NGINX 块更改为对 proxy_pass 进行硬编码,那么它可以很好地解决。但是,我还有其他需要动态代理名称的配置。我可以用这种方式对每个上游进行硬编码,但我想知道如何使 DNS 解析器工作。

location /api/v1/lead 
  proxy_pass http://lead-api:3000;

【问题讨论】:

您可能需要使用完整的限定名称,即lead-api。.svc.cluster.local: 顺便说一句,不知道为什么不使用使用服务来代替这个?该服务将从 NGINX 负载平衡到您后面的任何 pod。 我可以从 nginx 容器中使用 nslookup 仅使用 lead-api 并且它解决得很好。另外,我有几个单独运行的后端 API,我想在单个 url 下运行。我研究过使用入口控制器,但这些对于我想要完成的任务来说太复杂了。 @MrE 我更新了 OP 以显示 nslookup 作品 我不知道 nginx 解析是如何工作的,但我知道有多种方法可以做到这一点,而且我之前遇到过很多 DNS 问题,所以我不会推断,因为 nslookup 有效, nginx 解析应该可以工作。在 nginx 中尝试 FQDN 看看是否有帮助。我仍然不确定您到底在做什么:lead-api 是一项服务,对吗?那么为什么需要使用 resolve 指令呢? 【参考方案1】:

解析名称失败,因为您需要使用完全限定域名。也就是说,您应该使用:

lead-api.<namespace>.svc.cluster.local

不只是

lead-api

只使用主机名通常会起作用,因为在 kubernetes 中,resolv.conf 配置了搜索域,因此您通常不需要提供服务的 FQDN。例如:

search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.3.240.10
options ndots:5

但是,当您告诉 nginx 使用自定义解析器时,必须指定 FQDN,因为它无法从这些域搜索规范中受益。

【讨论】:

这是我的问题。它适用于我们部署到默认 NS 的一个系统,但不适用于我们有自定义 NS 的另一个系统。要解决它,您实际上可以只放 lead-api. 假设其余部分已包含在您的 resolv.conf 中。 像魅力一样工作! 如果您不能使用 FQDN,也就是说您不知道要部署的集群的名称空间和名称,该怎么办?这是一个真正的问题。我尝试在 nginx conf 中删除解析器定义,但它不适用于短名称:( @SeB.Fr 如果您不知道要部署到哪个集群或要部署到的命名空间,我认为您有更大的问题。如果您真的想要进行与集群无关的部署,那么您需要使用带有变量插值的模板。您还可以使用 Init 容器在容器启动时重写 nginx 配置。 我们构建了要部署在客户 K8s 集群上的软件,并且需要一定的部署灵活性。我们依赖 helm 图表,因此命名空间不是问题,因为它是 Helm 中的内置对象。但是不支持集群名称,顺便说一下,如果您知道 K8s API 来获取该信息,我全都听好了。【参考方案2】:

您需要使用Service

http://kubernetes.io/docs/user-guide/services/

kubernetes Service 代理流量到您的 Pods(即您所谓的“服务”,即您的应用程序)

我猜你使用 Kubernetes 来部署和扩展你的应用程序 (Pods),所以一旦你扩展并且你有多个 Pod 可以通信,就需要对它们进行负载平衡。这就是 Service 所做的。

Service 有自己的 IP 地址。只要 Service 存在,在上游引用此 Service 的 Nginx Pod 就可以正常工作。

Nginx(免费版)在无法解析上游时会死掉,但如果定义了Service,它有自己的IP,它会被解析。

如果Service 后面的Pods 没有运行,Nginx 将看不到这一点,并会尝试转发流量但会返回 502(错误网关)

所以,只需定义Service,然后使用适当的标签显示您的Pods,以便Service 将它们拾取。你可以删除、缩放、替换那些Pods而不影响Nginx Pod。只要Service 后面至少有一个 Pod 运行,Nginx 将始终能够连接到您的 API。

【讨论】:

lead-api 是一项服务,我了解服务的工作原理。我也明白我可以将配置更改(并且已经拥有)硬编码“lead-api”。我知道如果我先启动 Lead-api 服务,上游将正常工作。我有其他需要相同解析器配置的动态 nginx 配置。这只是一个例子。我的问题不是“如何让它以其他方式工作”而是“为什么 DNS 解析器不起作用。” 您是否尝试过使用 FQDN? 投反对票,因为这没有抓住重点,服务根本不是这里的问题。 因此为什么在更多细节之后我写了另一个被接受的答案。

以上是关于Kubernetes 中的 NGINX 无法解析 DNS的主要内容,如果未能解决你的问题,请参考以下文章

如果配置文件中的多个站点之一无法解析,nginx 将无法启动。 “在上游找不到主机”

无法设置 kubernetes ingress-nginx

Kubernetes基础_05_StatefulSet全解析(有状态的Pod)

Kubernetes基础_05_StatefulSet全解析(有状态的Pod)

源码解析:Kubernetes 创建 Pod 时,背后发生了什么

Kubernetes中域名解析的异常问题分析