Nginx宿主机反向代理动态Docker容器的域名访问异常问题
老哥,我来帮你捋捋这个问题的根源和解决办法:
你现在遇到的502坏网关本质是宿主机的Nginx找不到你的Docker容器——原因很简单:你手动创建的Docker桥接网络有自己独立的内部DNS服务,而你的Nginx跑在宿主机上,不在这个桥接网络里,所以它根本没法解析容器的hostname(比如abcde),最后超时就返回了坏网关。
下面给你几个实用的解决方案,优先推荐第一种,完全符合你不想动态改Nginx配置的需求:
方案一:让Nginx用Docker桥接网络的DNS解析容器名
这是最适合你的方案,不用动Nginx的部署方式,只改两行配置:
先找到你自定义桥接网络的网关IP
运行这条命令查看你的网络详情:docker network inspect 你的桥接网络名称在输出里找
Gateway字段,比如会得到类似172.18.0.1的IP,这就是桥接网络内部的DNS地址。修改Nginx配置
把原来的resolver行替换成这个网关IP,同时给proxy_pass加上容器内部的监听端口3000(因为桥接网络里可以直接通过容器hostname+内部端口访问,不用管宿主机的随机映射端口):resolver 172.18.0.1 valid=10s; # 替换成你实际查到的网关IP server { listen 80; server_name ~^(?<container>\w+)\.apps\.example\.com$; location / { proxy_pass http://$container:3000; # 加上容器内部的3000端口 } }重启Nginx生效
执行宿主机的Nginx重启命令:sudo systemctl restart nginx
这样改完之后,Nginx就会通过Docker桥接网络的DNS去解析容器hostname,直接在桥接网络内部和容器通信,既高效又不用管那些随机的宿主机映射端口,完美匹配你动态创建容器的场景。
方案二:把Nginx容器化并加入同一桥接网络(备选)
如果你不介意把宿主机的Nginx改成Docker容器,那直接把Nginx容器加入到你的自定义桥接网络里,这样Nginx容器就能用Docker内置的127.0.0.11 DNS解析容器hostname了,配置里的resolver用127.0.0.11就行,proxy_pass同样用http://$container:3000。不过你明确说Nginx在宿主机上,这个方案仅供参考。
方案三:动态修改宿主机hosts(不推荐)
这个方法是每次创建容器后,把容器的IP和hostname加到宿主机的/etc/hosts里,比如172.18.0.2 abcde,但这需要动态修改hosts文件,违背了你不想动态改配置的初衷,所以不推荐使用。
最后验证一下:创建一个hostname为abcde的容器并加入目标桥接网络,访问http://abcde.apps.example.com,应该就能正常代理到容器的3000端口了。
备注:内容来源于stack exchange,提问作者tommyd456

