minikube ingress-dns 插件实战:用集群内 DNS 终结 `/etc/hosts` 污染问题
2026/9/19 22:42:14 网站建设 项目流程

minikube ingress-dns 插件实战:用集群内 DNS 终结/etc/hosts污染问题

【免费下载链接】minikubeRun Kubernetes locally项目地址: https://gitcode.com/gh_mirrors/mi/minikube

本文以 minikube 的ingress-dnsaddon 为对象,讲解如何在不修改宿主机/etc/hosts的情况下,让myservice.test这类本地域名直接解析到minikube ip,从而用 Ingress 替代 NodePort 和minikube tunnel访问本地服务。读完本文,你将掌握ingress-dns的工作原理、完整的安装与宿主机 DNS 配置步骤(覆盖 Linux 的 resolvconf / NetworkManager / systemd-resolved、macOS、Windows 三大平台)、集群内 CoreDNS 转发配置,以及一套可复现的端到端验证方法。

为什么需要 ingress-dns:/etc/hosts污染问题

在本地使用 minikube 时,访问服务的常规手段有两种:minikube tunnel和 NodePort。NodePort 在很多场景下够用,但当你希望用 Ingress 测试某些特性(比如基于 Host 头路由、TLS 终结、灰度发布)时,就必须让 Ingress 控制器能够工作。Ingress 控制器的核心依赖是DNS——你配置的myservice.test这类本地域名必须能解析到minikube ip

传统做法是手动为每个服务在宿主机/etc/hosts中追加一条记录。这会带来一系列问题:

  • 每新增、删除、重命名一个服务,都需要人工维护/etc/hosts
  • 即便用脚本自动化,配置也被分散存储在宿主机操作系统里,而不是保存在集群中,无法随集群一起版本化管理;
  • 条目会持续累积、腐化,形成"/etc/hosts污染"。

解决方案:运行在集群内的 DNS 服务

ingress-dnsaddon 的思路是:把 DNS 服务本身跑进 Kubernetes 集群里。启用后你只需要做两件事:

  1. 安装(启用)该 addon;
  2. minikube ip配置为宿主机的一个 DNS 服务器。

此后每次 DNS 查询到来时,该服务都会向 Kubernetes API Server(master service)发起一次调用,获取集群中全部 Ingress 的列表;如果查询的域名与某个 Ingress rule 的 host 匹配,就返回minikube ip作为解析结果。

minikube ip192.168.99.169、集群内配置了myservice.test的 Ingress 规则为例,宿主机上的查询结果如下:

#bash:~$ nslookup myservice.test $(minikube ip) Server: 192.168.99.169 Address: 192.168.99.169#53 Non-authoritative answer: Name: myservice.test $(minikube ip) Address: 192.168.99.169

从源码看 addon 的构成

仓库中该 addon 的部署模板位于 deploy/addons/ingress-dns/ingress-dns-pod.yaml.tmpl,由 5 个 Kubernetes 对象组成,可以清晰地看到它的权限模型与运行方式:

  • ServiceAccountminikube-ingress-dns(kube-system 命名空间):Pod 以专用服务账户运行;
  • ClusterRoleminikube-ingress-dns:授予对""extensionsnetworking.k8s.io三个 API 组中ingresses资源的getlistwatch权限——这正是"查询集群内全部 Ingress"所需的最小权限集;
  • ClusterRoleBinding:把上述角色绑定到服务账户;
  • Podkube-ingress-dns-minikube:这是核心,注意它的spec.hostNetwork: true,意味着 DNS Pod 直接共享节点网络栈,并通过containerPort: 53 / hostPort: 53 / protocol: UDP将 DNS 端口暴露出来;容器镜像由模板变量{{.CustomRegistries.IngressDNS | default .ImageRepository | default .Registries.IngressDNS }}{{.Images.IngressDNS}}决定,即支持通过自定义镜像仓库覆盖;
  • ConfigMapminikube-ingress-dns:目前包含一个配置项dns-nodata-delay-ms: "20",用于控制无匹配记录(NODATA)时的应答延迟。

从 pkg/minikube/assets/addons.go 可以看到该 addon 在 minikube 中的注册定义:默认镜像为kicbase/minikube-ingress-dns:0.0.4(带 sha256 摘要),并绑定了官方文档地址。另外,pkg/addons/addons.go 中的supportLegacyIngress逻辑专门处理了兼容性问题:当 Kubernetes 版本< 1.19.0时,ingressingress-dns两个 addon 会替换为兼容旧版本的镜像(ingress-dns 使用cryptexlabs/minikube-ingress-dns:0.3.0),从而保证在旧集群上仍可工作。

安装步骤

第 1 步:启动 minikube

minikube start

第 2 步:启用 addon

注意需要同时启用ingressingress-dns两个 addon——前者提供 Ingress 控制器,后者提供 DNS 解析:

minikube addons enable ingress minikube addons enable ingress-dns

第 3 步:把minikube ip配置为宿主机 DNS 服务器

首先用minikube ip拿到节点 IP(下文所有示例中的192.168.99.169都替换为该命令的实际输出),然后按你的操作系统选择对应配置。

Linux:先确认 DNS 管理方式

查看/etc/resolv.conf的开头几行,判断你的系统由谁来管理域名解析:

  • 内容中出现resolvconf→ 由resolvconf管理;
  • 内容是# Generated by NetworkManager→ 由NetworkManager管理;
  • 内容类似# This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8)→ 由systemd-resolved管理。
Linux + resolvconf

更新/etc/resolvconf/resolv.conf.d/base,写入以下内容(192.168.99.169替换为minikube ip的输出):

search test nameserver 192.168.99.169 timeout 5

如果系统使用systemctl

sudo resolvconf -u systemctl disable --now resolvconf.service

如果系统不使用systemctl,则需要采用该系统对应的 resolvconf 刷新方式(原文档中该分支尚待补充具体命令)。

Linux + NetworkManager(dnsmasq)

NetworkManager 自带集成的缓存 DNS 服务器dnsmasq插件,可以按域名配置独立的 nameserver。编辑/etc/NetworkManager/NetworkManager.conf,启用 dnsmasq:

[main] dns=dnsmasq

然后配置 dnsmasq 处理以.test结尾的域名:

sudo mkdir -p /etc/NetworkManager/dnsmasq.d/ echo "server=/test/$(minikube ip)" | sudo tee /etc/NetworkManager/dnsmasq.d/minikube.conf

重启 NetworkManager:

systemctl restart NetworkManager.service

最后确认/etc/resolv.conf中只有一个 nameserver:

cat /etc/resolv.conf | grep nameserver nameserver 127.0.0.1
Linux + systemd-resolved

创建 drop-in 配置并重启 systemd-resolved:

sudo mkdir -p /etc/systemd/resolved.conf.d sudo tee /etc/systemd/resolved.conf.d/minikube.conf << EOF [Resolve] DNS=$(minikube ip) Domains=~test EOF sudo systemctl restart systemd-resolved

这里Domains=~test的含义是:仅当查询域名以test结尾(波浪号前缀表示"路由到该 DNS")时才使用 minikube 的 DNS,其余域名仍走系统原有解析,从而避免影响正常上网。

macOS

创建文件/etc/resolver/minikube-test,写入:

domain test nameserver 192.168.99.169 search_order 1 timeout 5

192.168.99.169替换为你的minikube ip。如果你有多个 minikube IP(例如多个集群/多节点),必须为每个 IP 分别配置一个文件。注意:该 resolver 文件的port字段在 macOS 上不生效,与文档描述不符,请勿依赖。

Windows

以管理员身份打开 PowerShell 并执行:

Add-DnsClientNrptRule -Namespace ".test" -NameServers "$(minikube ip)"

NRPT(Name Resolution Policy Table)规则用于按命名空间指定解析服务器。当minikube ip变化时,可先移除旧规则再新建,一条命令完成:

Get-DnsClientNrptRule | Where-Object {$_.Namespace -eq '.test'} | Remove-DnsClientNrptRule -Force; Add-DnsClientNrptRule -Namespace ".test" -NameServers "$(minikube ip)"

第 4 步(可选):让集群内部也能解析本地域名

有时你希望集群内的其他应用(微服务、API、测试)也能通过 Ingress 的本地域名互相访问,此时需要让集群内的 CoreDNS 把test域的查询转发给 ingress-dns。

编辑 CoreDNS 配置:

kubectl edit configmap coredns -n kube-system

在 Corefile 中追加一个针对本地域的 server block(192.168.99.169替换为minikube ip):

test:53 { errors cache 30 forward . 192.168.99.169 }

最终的 ConfigMap 大致如下(省略号部分为原有默认内容):

apiVersion: v1 data: Corefile: | .:53 { errors health { lameduck 5s } ... } test:53 { errors cache 30 forward . 192.168.99.169 } kind: ConfigMap metadata: ...

其中cache 30表示对该域的解析结果缓存 30 秒,forward . 192.168.99.169表示把test域的所有查询转发到 minikube 的 DNS 服务。

验证测试

仓库自带了完整的测试样例,位于 deploy/addons/ingress-dns/example/example.yaml。该清单包含 5 个对象:

  • Deploymenthello-world-app:使用docker.io/kicbase/echo-server:1.0镜像,容器端口 8080;
  • Ingressexample-ingress(kube-system):ingressClassName: nginx,包含hello-john.testhello-jane.test两个 host 规则,路径/pathType: Prefix),后端指向 servicehello-world-app的 80 端口;
  • Servicehello-world-app(kube-system):type: ExternalName,externalName 指向hello-world-app.default.svc.cluster.local,用于跨命名空间转发;
  • Servicehello-world-app(default):type: NodePort,端口 80 → targetPort 8080,selector 匹配app: hello-world-app

第 1 步:部署测试 Ingress

kubectl apply -f https://raw.githubusercontent.com/kubernetes/minikube/master/deploy/addons/ingress-dns/example/example.yaml

注意:该示例 Ingress 使用了networking.k8s.io/v1API,最低要求 Kubernetes 1.19。上文提到的 pkg/addons/addons.go 中的supportLegacyIngress正是为< 1.19的集群做兼容降级。

第 2 步:确认 DNS 返回 A 记录

nslookup hello-john.test $(minikube ip) nslookup hello-jane.test $(minikube ip)

第 3 步:确认宿主机能解析域名

ping hello-john.test ping hello-jane.test

预期结果(两域名均解析到minikube ip):

PING hello-john.test (192.168.99.169): 56 data bytes 64 bytes from 192.168.99.169: icmp_seq=0 ttl=64 time=0.361 ms
PING hello-jane.test (192.168.99.169): 56 data bytes 64 bytes from 192.168.99.169: icmp_seq=0 ttl=64 time=0.262 ms

第 4 步:通过 Ingress 访问示例服务

curl http://hello-john.test curl http://hello-jane.test

预期结果(echo-server 返回):

Hello, world! Version: 1.0.0 Hostname: hello-world-app-557ff7dbd8-64mtv

已知问题与注意事项

.localhost总是解析到回环地址

.localhost在多数系统上会被强制解析为回环地址(127.0.0.1),因此不能用于minikube ip。请改用.test.example.invalid这类本地测试保留域。

.local是保留 TLD

不要使用.local作为域名后缀——它是 mDNS(多播 DNS)和 bind9 的保留 TLD,会与局域网内的 mDNS 解析冲突。

macOS:mDNS 重载

每次在/etc/resolver中创建或修改文件后,可能需要重载 macOS 的 mDNS resolver 才能生效:

  • Big Sur 之前的 macOS,使用以下传统命令:
sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist
  • Big Sur 及更新版本,传统命令会报错:
Load failed: 5: Input/output error Try running `launchctl bootstrap` as root for richer errors.

此时应改用以下命令:

sudo launchctl enable system/com.apple.mDNSResponder.reloaded sudo launchctl disable system/com.apple.mDNSResponder.reloaded

已知的待办事项

原文档明确列出了两个计划中的改进方向,说明当前体验仍有优化空间:

  • 增加一个运行在宿主机上的服务,自动维护/etc/resolver下的文件;
  • minikube addons enable ingress-dns时自动启动该服务,在minikube addons disable ingress-dns时自动停止。

也就是说,目前宿主机侧(尤其是 macOS)的 resolver 文件仍需手动维护。

附:addon 使用的镜像

ImageSourceOwner
ingress-nginxkubernetes/ingress-nginxKubernetes ingress-nginx
minikube-ingress-dnscryptexlabs/public/development/minikube-ingress-dnsCryptex Labs

其中minikube-ingress-dns是 ingress-dns addon 的核心实现(DNS 服务器 + Kubernetes Ingress 查询逻辑),minikube 侧通过 pkg/minikube/assets/addons.go 中的默认镜像kicbase/minikube-ingress-dns:0.0.4引用它;在 Kubernetes< 1.19的旧集群中则自动降级为cryptexlabs/minikube-ingress-dns:0.3.0(见 pkg/addons/addons.go)。

小结

ingress-dns把"本地域名 → minikube IP"的映射从宿主机/etc/hosts迁移到了集群内的 DNS 服务,天然解决了手动维护、配置分散的问题,让基于 Ingress 的本地开发体验与生产环境保持一致。核心使用链路可以概括为:启用ingress+ingress-dnsaddon → 把minikube ip配成宿主机 DNS(或 CoreDNS 转发)→ 部署带 host 规则的 Ingress → 用本地域名直接访问。在动手之前,请记住两条铁律:优先使用.test等保留域而非.localhost/.local,并确保宿主机 DNS 配置方式与你的系统(resolvconf / NetworkManager / systemd-resolved / macOS resolver / Windows NRPT)匹配。

【免费下载链接】minikubeRun Kubernetes locally项目地址: https://gitcode.com/gh_mirrors/mi/minikube

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询