docker 容器跟随宿主机域名解析

前景需要

自从朋友家里网爆炸之后，你站的前端和 API 不得不搬到了同一个机子上
但是某一天在使用某人的神秘设备访问的时候，报错 "禁止访问或 API 服务出现问题"，我一想估计就是因为前端访问后端带的 User-Agent 是客户端的，或者是说前端访问后端的时候给 CDN 传递的 IP 出了问题，然后就完美的触发了我抽象的 WAF 被拦截了
这样前端访问后端是需要先到 CDN，然后 CDN 再回来到后端，既然在一台服务器上为什么要兜这么大一圈呢，于是就有了这篇文章

省流

把宿主机的 /etc/hosts 文件映射到 docker 容器中

问题分析

由于 Mix-Space 的前后端目前都是可以用 docker 运行的，图省事所以两个我都是用 docker 跑的
前端的 API 是由 .env 中的 NEXT_PUBLIC_API_URL 提供的，这也就是最主要的
在 docker 容器中，127.0.0.1 指的是当前这个容器自己，当然前端容器里面只跑了一个前端并没有后端，所以不能设置为 127.0.0.1
那设置为后端容器的 IP 不就行了？在前端页面的某些场景中需要明文用到这个 URL，所以不能直接设置在服务器上的内网地址然后给用户访问显然是不现实的，所以此方案行不通
有人说把两个容器放在同一个网络里，这样确实是访问更方便，但是回到上一个问题，所以行不通

IP 行不通只能走域名了，那么我们可以给域名固定到目标容器的 IP
但容器每次重启之后 IP 好像是会变的吧（？但是 docker bridge 网络的网关始终是指向宿主机的，所以我们可以把后端容器中 Web 服务的端口映射到宿主机，然后用 nginx 反代到 80 端口，然后域名在本机指向 bridge 的 IP，这样就能一举两得了（确信

解决过程

首先得获取 docker 的 bridge 网卡的网关是哪个
服务器终端输入 ifconfig，然后找一找有个叫 docker0 的网卡，这个就是了

然后 inet 对应的值（也就是 172.17.0.1 就是他的网关了
可以 curl 测试一下，我宿主机跑了一个 nginx，curl 的结果是 nginx 的默认页，也就是说这个地址确实是指向宿主机的（当然 curl 后端的 port 也是通的

然后我第一时间想到的是修改宿主机的 /etc/hosts 文件，给后端的域名指定到这个地址
然后去容器里测试一看，这玩意根本就不走宿主机的 hosts，，，

此时有两个解决方案

1. 通过本地搭建 DNS 强行解析 IP

其实用 ADGuard Home 中的自定义规则就可以
关于如何搭建可以详情这篇文章

由于我本地不走这玩意的 DNS 所以直接看第二个

2. 将宿主机 hosts 文件映射到 docker 容器中

给前端容器的 docker-compose.yml 文件里面加一句

Copy
volumes:
- /etc/hosts:/etc/hosts:ro

防止容器乱改所以挂载为只读
然后重启容器

再回到容器里试试

好已经完美解决了

后记

本文有点繁琐，意在记录遇到的抽象问题
如果你认为我的思路对你有用的话，欢迎点赞转发收藏最后再投喂一下，谢谢喵

此文由 Mix Space 同步更新至 xLog
原始链接为 https://blog.nekorua.com/posts/maintain/121.html