本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 [署名 4.0 国际 (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/deed.zh) 本文作者: 苏洋 创建时间: 2021年08月19日 统计字数: 5374字 阅读时间: 11分钟阅读 本文链接: https://soulteary.com/2021/08/19/dns-for-local-development.html ----- # 用于本地开发使用的 DNS 方案 本篇文章,我将介绍一个方便本地开发和调试的方案,本地 DNS 代理服务器。 ## 写在前面 不论是你做前端还是后端开发,本地调试带有域名的接口或页面是大概率绕不开的事情。甚至,如果你使用了自签名证书或者“虚拟域名”进行 HomeLab 服务搭建,某些不能使用网络默认 DNS 服务器时,也需要一些灵活的方案来动态切换一系列域名的指向。 不过,不能因为手持锤子就哪里都是钉子,简单的场景下,比如就修改一次的情况下,直接修改 hosts 解决问题会是更简单的方案,关于 Hosts Editor 类的工具的推荐,可以阅读文末章节。 言归正传,先来聊一个我使用了六个多月的方案。 ## 方案一:带有界面的 dnsmasq 容器 dnsmasq 作为 DNS Server 被广泛用于 Linux 发行版。我们常见的 Ubuntu Server 版以及 Open WRT 路由器固件中,不少版本默认使用的都是它。 但是它是一个命令行软件,默认并不支持自动重载有修改后的配置文件,配置文件的编辑和我们常规修改 `/etc/hosts` 别无二致,国外有一个工程师为了解决这个问题,开发了一个简单的带有界面的配置工具 [docker-dnsmasq](https://github.com/jpillora/docker-dnsmasq),在配置文件被修改后,能够发送命令重启或重载 dnsmasq 主程序,达到“方便使用”的目的。 因为作者许久不更新软件,在[今年二月的时候](https://github.com/jpillora/docker-dnsmasq/pull/27),我做了一个 fork 版本,[soulteary/docker-dnsmasq](https://github.com/soulteary/docker-dnsmasq),你可以使用下面的配置快速运行一个属于你的本地 DNS 服务器。 以往我们编辑 hosts 文件,会用下面的形式来进行域名绑定: ```yaml 10.11.12.123 docker.lab.com 10.11.12.123 maven.lab.com 10.11.12.123 npm.lab.com 10.11.12.123 pypi.lab.com ... ``` 所以当域名很多的时候,使用起来就会非常麻烦,相比之下 dnsmasq 的配置文件就会简单许多,因为它允许使用“泛解析”的方式,除此之外还能指定上游服务器,近一步扩展能力,下面就是一个 `dnsmasq.conf` 的配置文件的例子: ```yaml # HomeLab ## Use Home DNS Upstream server=10.11.12.13 # HomeLab Domain Example: address=/.lab.com/10.11.12.123 address=/*.lab.com/10.11.12.123 address=/*.demo.lab.com/10.11.12.123 address=/*.api.lab.com/10.11.12.123 address=/*.some.api.lab.com/10.11.12.123 # localhost address=/.lab.io/127.0.0.1 address=/*.lab.io/127.0.0.1 ``` 在上面的例子中,将 lab.com 和一些子域名指向了内网的一台机器,而将 lab.io 全部指向了本机,将上面的内容保存为 `dnsmasq.conf`,我们来编写容器编排文件: ```yaml version: "3" services: dns: image: soulteary/docker-dnsmasq restart: always # 如果你需要一个简单的 Basic Auth 认证 #environment: # - HTTP_USER=user # - HTTP_PASS=pass ports: - "53:53/udp" - "53:53/tcp" - "8080:8080" volumes: - ./dnsmasq.conf:/etc/dnsmasq.conf:rw ``` 将上面的内容保存为 `docker-compose.yml`,然后使用 `docker-compose up -d` 启动服务,接着使用浏览器访问 8080 端口,就能看到控制面板了,开始使用啦。 需要额外注意的是,为了减少后续设置的复杂,我们默认使用 53 端口来提供服务,管理面板默认使用的端口是 8080,如果你有端口冲突,建议进行调整或修改。 【图片】 界面比较简单,这里就不过赘述了,编辑器支持使用快捷键(`CMD+/`)切换注释,所以,如果在配置存放一些不同环境的配置,通过快捷键就能进行批量快速切换啦,最近半年,我是这么解决不同环境的 DNS 记录切换的: ```yaml # HomeLab ## Use Home DNS server=10.11.12.13 # Office ## Use Dev NS Servers # server=219.141.136.10 # server=219.141.140.10 ## Use CloudFlare NS Servers # server=1.0.0.1 # server=1.1.1.1 # Local address=/.lab.io/127.0.0.1 address=/*.lab.io/127.0.0.1 address=/.lab.com/10.11.12.123 address=/*.lab.com/10.11.12.123 address=/*.demo.lab.com/10.11.12.123 address=/*.api.lab.com/10.11.12.123 address=/*.some.api.lab.com/10.11.12.123 # address=/.lab.com/192.11.12.123 # address=/*.lab.com/192.11.12.123 # address=/*.demo.lab.com/192.11.12.123 # address=/*.api.lab.com/192.11.12.123 # address=/*.some.api.lab.com/192.11.12.123 ``` 当然,这个小程序同时会读取容器内的 `/etc/hosts`,你也可以通过左侧侧边栏切换编辑器打开 `hosts` 文件,用传统的方式添加修改 DNS 记录。 在使用过程中,也会有一些体验不好的地方,比如程序重载需要几秒的时间,过程中会有服务不可用的状态,编辑器只有最基础的功能,缺少快捷键等。偶尔有的时候程序会出现一些异常的资源使用,社区里有人[反馈](https://github.com/jpillora/webproc/issues/23),所以,我开始计划将这个方案替换掉。 ### 结合系统使用 以 macOS 为例,打开网络设置,选择当前网络,点击“高级”按钮,然后切换到 DNS 选项卡,在左侧的 DNS 服务器里,添加 “127.0.0.1”即可。 【图片】 这里有一个小技巧,为了保证网络完全不间断(比如重启服务的时候),这里可以除了添加我们指定的 DNS 服务之外,将当前网络的 DNS 服务器也添加进去。 ### 配合Traefik 使用 dnsmasq 如果你是我的老读者,那么应该对 Traefik 不会感到陌生,这里提供一个简单的配置,方便你使用 Traefik: ```yaml version: "3" services: dns: image: soulteary/docker-dnsmasq restart: always # 如果你需要一个简单的 Basic Auth 认证 # 使用 Traefik 推荐使用 Forward Auth 进行取代 #environment: # - HTTP_USER=user # - HTTP_PASS=pass ports: - "53:53/udp" - "53:53/tcp" - "8080:8080" volumes: - ./dnsmasq.conf:/etc/dnsmasq.conf:rw labels: - "traefik.enable=true" - "traefik.docker.network=traefik" - "traefik.http.routers.dnsmasq-web.entrypoints=http" - "traefik.http.routers.dnsmasq-web.rule=Host(`dns.lab.io`)" - "traefik.http.routers.dnsmasq-ssl.entrypoints=https" - "traefik.http.routers.dnsmasq-ssl.tls=true" - "traefik.http.routers.dnsmasq-ssl.rule=Host(`dns.lab.io`)" - "traefik.http.services.dnsmasq-backend.loadbalancer.server.scheme=http" - "traefik.http.services.dnsmasq-backend.loadbalancer.server.port=8080" networks: - traefik networks: traefik: external: true ``` ## 方案二:使用 go-dnsmasq 方案 go-dnsmasq 是一个轻量到只有 1.2MB 的DNS缓存/转发工具,但是可惜的是作者在 16 年之后就没有在继续维护项目,在翻阅了几十个 fork 衍生版之后,我最终将两个国外的改进版本合并成了一个新的版本 [https://github.com/soulteary/go-dnsmasq](https://github.com/soulteary/go-dnsmasq),并制作了一个 2.7 MB 左右的容器镜像。 使用方法其实比上面还要简单,先来看配置文件: ```yaml 127.0.0.1 lab.com 127.0.0.2 *.lab.com ``` 平凡无奇的 hosts 记录的语法中,支持了泛解析,比 `dnsmasq.conf` 少了不少符号记忆的负担。虽然日常使用肯定会使用复制粘贴,但是少一个字符,出错的可能就少了一分,不是吗?将上面的内容保存为 `hosts.conf`,稍后使用。 我们继续编写容器配置文件: ```yaml version: "3" services: dns: image: soulteary/go-dnsmasq command: dnsmasq -l 0.0.0.0:53 -f /hosts.conf -p 1s --nameservers 10.11.12.13:53 restart: always ports: - "53:53/udp" - "53:53/tcp" volumes: - ./hosts.conf:/hosts.conf:rw ``` 相比较方案一,这个方案显然更“轻量环保”。至于切换环境配置,只需要准备多份不同环境的配置文件,使用 docker 挂载的时候切换文件就可以啦。 如何结合系统使用本地 DNS 服务器,上文有提过,这里不再赘述。接着来聊聊文章开头聊到的编辑本地 Hosts 文件。 ## 其他:如何简单的修改 Hosts 文件 如果你只需要管理几个域名,也不太想启动一个服务(哪怕它只有2M),可以尝试编辑系统的 `Hosts` 文件来完成域名指向,如果你厌倦了命令行或者记事本修改文件,也可以考虑下载一些 Hosts Editor 类的工具。 最初的时候,我使用过 [Gas Mask](https://github.com/2ndalpha/gasmask)、[HostsMan](https://www.abelhadigital.com/hostsman/),以及一些类似的软件,在第一次去淘宝工作的时候,被安利了一个内网神器“iHosts”(不是搜索引擎搜索出的同名软件),除了多了清新的界面之外,还支持记录分组,以及本地 DNS 服务器,对于调试移动端场景、或者虚拟机场景还是挺方便的。 在许多年前离开淘宝后,因为无法再从内网下载“ihosts”,于是就切换到了 [“SwitchHosts!”](https://github.com/oldj/SwitchHosts)(最新版本改名字去掉了“!”),虽然没有内置 DNS 服务、请求日志等功能,但是胜在功能简单够用,加上作者靠谱,也就一直用了下来。 为什么说作者靠谱呢?早些时候和刚从淘宝离开的季札大神一起吃饭,聊起招聘困难,当时玩笑的说要不要在 SwitchHosts README 里加个招聘广告,季札大神说希望这个软件能够一直纯粹下去,然后这些年这个软件,至今为止就一直这么干净纯粹着,还是挺难得的。 但是,在使用过程中难免会遇到需要做“泛解析”的场景,批量改动记录总归是比较麻烦的事情,以及我的电脑常年不关机,经常休眠唤醒,基于 Electron 的 SwitchHosts 总是会出现内存溢出的问题,所以只好忍痛把主力方案切换到了上文中的 DNS 方式。其实解决的方案也很简单,就是每次使用完 SwitchHosts 之后,把它的进程彻底关掉。 后续我应该会继续使用 SwitchHosts 这个功能,不过不会再作为主力工具。 ## 最后 原本以为离职休假能够把草稿箱里的文章清理一下,没想到积累的草稿更多了。 --EOF