Docker容器网络互通配置指南：从连接拒绝到定位真凶

凌晨三点，我对着屏幕上那行 Connection refused 发呆。两个Docker容器，明明都在同一台机器上，却像失联了一样无法通信。我打开第六罐红牛，心想这事儿不应该这么复杂。事实证明，它确实不复杂，只是藏了很多坑等着你往里跳。🌃

问题的起点：两个世界的容器

看起来很简单的需求

我要做的事情听起来直白：让 LangBot 和 WeChatPadPro 两个服务互相通信。一个负责AI对话，一个对接微信消息，逻辑上它们应该是天然的搭档。

但现实给了我一巴掌。这两个服务分别跑在不同的 docker-compose 项目里，它们之间的距离，比我想象的要远。

第一次尝试的错误是这样的：

HTTPConnectionPool(host='127.0.0.1', port=1238): Max retries exceeded
Connection refused

我检查了端口占用，看了防火墙规则，确认服务在运行。一切看起来都正常，但就是连不上。就像你明明看见对方在线，消息就是发不出去，对方也收不到。

Docker重新定义了"本地"

在没有容器的时代，127.0.0.1 就是本机，同一台机器上的服务通过端口就能互相访问。Docker改变了这个规则。

每个容器都是一个独立的运行环境。当你在容器内部访问 127.0.0.1 时，你访问的是容器自己，不是宿主机，更不是其他容器。这就像你站在自己房间里喊"有人吗"，隔壁邻居是听不见的。

更麻烦的是，不同的 docker-compose 项目会创建各自的网络：

# WeChatPadPro 项目创建的网络
deploy_wechatpadpro-network

# LangBot 项目创建的网络
docker_langbot-network

这两个网络就像两条平行线，永远不会相交。除非你做点什么。🔌

配置过程：一场细节的战争

第一步：创建一座桥梁

解决方案的核心思路是：创建一个外部网络，让两个项目的容器都加入进来。

docker network create langbot-network

这个命令创建了一个独立于任何项目的网络。它不属于 WeChatPadPro，也不属于 LangBot，它是中立的公共区域。

如果执行时提示网络已存在，说明之前创建过，直接用就行：

Error response from daemon: network with name langbot-network already exists

这不是错误，反而是好消息——网络已经在那里了。

第二步：修改 WeChatPadPro 配置

打开 docker-compose.yml，找到网络配置部分。这里是最容易出错的地方。

错误的写法：

networks:
langbot-network:
driver: bridge # ❌ 这会创建新网络，不是使用外部网络

正确的写法：

networks:
wechatpadpro-network:
driver: bridge
langbot-network:
external: true # ✅ 标记为外部网络

然后在服务配置里指定网络：

services:
wechatpadpro:
networks:
- wechatpadpro-network # 内部网络，访问数据库
- langbot-network # 外部网络，对外通信

mysql:
networks:
- wechatpadpro-network # 只在内部网络

redis:
networks:
- wechatpadpro-network # 只在内部网络

注意这个设计：MySQL 和 Redis 只在内部网络，外部容器无法直接访问它们。这是有意为之的安全设计。

第三步：修改 LangBot 配置

同样的道理，修改 LangBot 的配置：

services:
langbot_plugin_runtime:
networks:
- langbot-network

langbot:
networks:
- langbot-network

networks:
langbot-network:
external: true # 不能少这行

关键点：网络名必须完全一致。langbot-network 和 langbot_network 是两个不同的网络，连字符和下划线的差异会让你的配置彻底失效。

第四步：重建容器

配置改完要生效，必须重建容器：

# WeChatPadPro 目录
docker-compose down
docker-compose up -d

# LangBot 目录
docker-compose down
docker-compose up -d

启动时注意观察日志。正确的日志应该是：

Network langbot-network External ✓

如果看到这样的日志：

Network deploy_langbot-network Created ✗

说明配置还是错的，Docker 又创建了一个新网络，而不是使用外部网络。

第五步：验证网络

检查网络中的容器：

docker network inspect langbot-network

应该看到输出里包含三个容器：

wechatpadpro

langbot

langbot_plugin_runtime

然后测试连通性：

docker exec -it wechatpadpro ping langbot

能 ping 通就说明网络配置成功了。如果报错 ping: executable file not found，不用担心，这只是镜像里没装 ping 工具，不代表网络不通。换个方式：

docker exec -it langbot curl http://wechatpadpro:8080

那些让人抓狂的细节

127.0.0.1 的惯性思维

LangBot 的配置文件里最初写的是：

wechatpad_url: http://127.0.0.1:1238

在容器里，这个地址指向的是容器自己，不是 wechatpadpro。必须改成容器名：

wechatpad_url: http://wechatpadpro:1238

Docker 的内置 DNS 会自动解析容器名到对应的 IP。这是容器间通信的标准做法。

external: true 的必要性

如果配置文件里只写：

networks:
langbot-network:
driver: bridge

Docker 会认为这是一个项目内的网络，会创建一个带项目前缀的新网络，比如 deploy_langbot-network。

只有明确标记 external: true，Docker 才会去寻找已存在的外部网络：

networks:
langbot-network:
external: true

这一行，不能省。

网络名称的字符陷阱

Docker 网络名区分大小写，也区分连字符和下划线：

网络名 | 是否相同
langbot-network | 基准
Langbot-Network | ❌ 不同（大小写）
langbot_network | ❌ 不同（下划线）
langbot-network | ✅ 相同

我就在这个细节上卡了半小时。两个配置文件，一个用连字符，一个用下划线，看起来差不多，但 Docker 认为它们是两个完全不同的网络。

容器重启的必要性

修改 docker-compose.yml 后，必须重建容器才能生效。简单的 docker-compose restart 是不够的，因为网络配置在容器创建时就确定了。

必须用：

docker-compose down # 删除容器
docker-compose up -d # 重新创建

从网络问题到应用问题

错误信息的进化

配置完网络后，我以为一切搞定了。但 LangBot 还是报错：

500 Server Error: Internal Server Error for url:
http://wechatpadpro:1238/login/GetLoginStatus

但这次的错误性质变了：

之前是 Connection refused —— 网络不通

现在是 500 Server Error —— 网络通了，但接口报错

这说明网络层面已经没问题了，问题转移到了应用层。

WeChatPadPro 的真正问题

查看 wechatpadpro 的日志：

docker logs wechatpadpro --tail=50

发现了真相：

GET Connection locfree Failed by e36bdea0-f39a-4252-8fdc-913cf026e535
❌ 登录过程中发生panic
❌ 用户登录失败
登录初始化完成: 0/1 用户成功登录

原来问题不在网络，而在微信登录失败。WeChatPadPro 服务本身启动了，但微信账号没有成功登录，所以接口返回 500 错误。

分层排查的重要性

这个过程给我的启示是：问题要分层看。

层级 | 问题表现 | 排查方法
网络层 | Connection refused | 检查网络配置、容器连通性
应用层 | 500/404 等HTTP错误 | 查看应用日志、检查服务状态
业务层 | 逻辑错误、数据异常 | 检查配置、验证业务流程

我的问题经历了这样的演进：

网络层：Connection refused → 配置外部网络解决

应用层：500 Server Error → 需要先完成微信登录

网络通了不代表服务能用，这是两个层面的问题。

未解决的部分

当前的状态

截至现在：

✅ Docker 网络配置正确

✅ 容器间可以互相访问

✅ LangBot 能够请求 WeChatPadPro 的接口

❌ WeChatPadPro 的微信登录失败

❌ 整个服务链路还没跑通

问题从"网络不通"变成了"服务未就绪"。这是进步，但还没到终点。

下一步要做的事

根据 WeChatPadPro 的文档，需要：

访问 Swagger UI：http://localhost:8080

填入 adminKey：从日志中获取

获取 token：调用 /admin/GanAuthKey 接口

扫码登录微信：调用 /login/GetLoginQrCodeNew 接口

在 LangBot 中配置：填入正确的 token 和 wxid

这些步骤都是业务层面的操作，和 Docker 网络无关了。但如果网络不通，连这些步骤都无法开始。

真实的技术工作

技术工作就是这样。你解决了一个问题，往往会发现另一个问题。问题不会消失，只会转移。

网络配置花了我两个小时，定位到微信登录问题又花了一个小时。但至少现在我知道：

网络没问题

Docker 配置没问题

问题在 WeChatPadPro 的业务层

这就够了。定位问题比解决问题更重要，因为只有知道问题在哪儿，才能知道该往哪儿使劲。💪

配置检查清单

如果你遇到类似的 Docker 网络问题，按这个清单检查：

网络配置

[ ] 创建了外部网络 docker network create xxx

[ ] 两个 docker-compose.yml 的网络名完全一致

[ ] 网络配置都标记了 external: true

[ ] 服务配置中引用了正确的网络名

容器状态

[ ] 执行了 docker-compose down 和 up -d

[ ] 启动日志显示 External 而不是 Created

[ ] 用 docker ps 确认所有容器都在运行

[ ] 用 docker network inspect 确认容器在同一网络

应用配置

[ ] 配置文件里用容器名替换了 127.0.0.1

[ ] 端口号正确（容器内部端口，不是映射的宿主机端口）

[ ] 相关的 token、密钥等配置正确

验证方法

[ ] docker exec 能在容器间通信

[ ] 接口返回的是业务错误而非连接错误

[ ] 查看了双方容器的日志

当网络层通了但服务还不工作时，停止折腾网络配置，去看应用日志。别在已经解决的问题上继续浪费时间。

天快亮了，外面传来早班公交车的声音。问题还没完全解决，但至少知道了问题在哪儿。有时候技术工作就是这样，你花大半夜时间，可能只是排除了一个方向，定位到了真正的问题。

但这就是进步。从漫无目的的摸索，到明确知道下一步要做什么，这就是价值。🌅

网络通了，剩下的就是业务问题了。那是另一个故事，也是明天的工作。现在，我需要睡觉。