Dokploy 项目的容器之间无法互访的解决办法

详细讲解在 Dokploy 中部署的容器服务之间无法互相访问的原因,以及如何通过配置 Docker Compose 网络来解决这一常见问题。

问题描述

在使用 Dokploy 部署应用时,你可能会遇到项目中的服务之间无法互相访问的问题。

例如,在一个 Dokploy 项目中:

  • 使用 Dokploy 的预置数据库功能创建了一个 MySQL 数据库
  • 使用 Docker Compose 部署了一个 Ghost 博客程序

此时,Ghost 应用的日志中会报告无法解析 MySQL 的主机名,导致数据库连接失败。

Error: getaddrinfo ENOTFOUND xxx-mysql-7eegrt
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:66:26)

问题原因

这个故障的根本原因是 容器网络隔离

在 Dokploy 中:

  • 通过预置数据库部署的 MySQL 容器会自动接入 dokploy-network 网络
  • 使用 Docker Compose 部署的应用默认会创建一个独立的专用网络,网络名称通常为 <项目名>_default

由于两个容器分别位于不同的 Docker 网络中,它们之间无法直接通过容器名或服务名进行通信。这就像两个人在不同的局域网中,无法直接访问对方一样。

解决方案

解决这个问题的关键是 让 Docker Compose 部署的应用加入到 dokploy-network 网络

配置步骤

在你的 Docker Compose 配置文件中,需要做两个修改:

  1. 在服务定义中添加网络配置:在 services 部分的应用配置中,添加 networks 字段,指定使用 dokploy-network
  2. 声明外部网络:在配置文件的顶层添加 networks 部分,声明 dokploy-network 为外部网络

完整配置示例

以 Ghost 博客为例,完整的 Docker Compose 配置如下:

services:
  ghost:
    image: ghost:5.129.0-alpine
    ports:
      - 2368
    environment:
      NODE_ENV: production
      url: https://xxx.com
      database__client: mysql
      database__connection__host: xxx-mysql-7eegrt
      database__connection__user: ghost
      database__connection__password: xxx
      database__connection__database: ghost
    volumes:
      - /root/xxx/data:/var/lib/ghost/content
    networks:
      - dokploy-network

networks:
  dokploy-network:
    external: true

配置说明

服务网络配置

services:
  ghost:
    # ... 其他配置
    networks:
      - dokploy-network

在服务定义中添加 networks 字段,指定容器要加入的网络。这里指定为 dokploy-network,这样 Ghost 容器启动后就会连接到这个网络。

外部网络声明

networks:
  dokploy-network:
    external: true

在顶层的 networks 部分声明网络配置:

  • external: true 表示这是一个外部网络,即该网络不是由当前 Docker Compose 创建的,而是已经存在的网络
  • Docker Compose 在启动时会检查 dokploy-network 是否存在,如果不存在则会报错

验证网络连接

配置完成后,你可以通过以下方式验证容器是否成功加入网络:

1. 查看容器网络

docker inspect <容器名或ID> | grep -A 10 Networks

输出应该包含 dokploy-network:

"Networks": {
    "dokploy-network": {
        "IPAMConfig": null
        "Links": null
        "Aliases": [
            "ghost"
            "xxx"
        ]
        ...
    }
}

2. 测试网络连通性

进入 Ghost 容器测试是否能够解析 MySQL 主机名:

# 进入容器
docker exec -it <ghost容器名> sh

# 测试 DNS 解析
ping xxx-mysql-7eegrt

# 测试 MySQL 端口连通性
nc -zv xxx-mysql-7eegrt 3306

如果能够正常解析和连接,说明网络配置成功。

其他注意事项

1. 数据库主机名

在 Dokploy 中创建的数据库,其主机名通常是 <项目名>-<服务名>-<随机字符> 的格式。你可以在 Dokploy 控制面板中查看具体的主机名。

2. 端口配置

当容器在同一个 Docker 网络中时:

  • 内部通信使用容器的内部端口(如 MySQL 的 3306)
  • 外部访问需要通过映射的主机端口

在上面的配置中,ports: - 2368 表示将容器的 2368 端口映射到主机的随机端口,Dokploy 会自动处理外部访问的路由。

3. 多网络配置

如果你的应用需要连接多个网络,可以这样配置:

services:
  myapp:
    networks:
      - dokploy-network
      - custom-network

networks:
  dokploy-network:
    external: true
  custom-network:
    driver: bridge

4. 网络隔离最佳实践

虽然将所有服务放在同一个网络中可以解决互访问题,但从安全角度考虑:

  • 生产环境建议根据服务职责划分不同的网络
  • 只有需要通信的服务才放在同一个网络中
  • 敏感服务(如数据库)应该尽量限制网络访问范围

总结

Dokploy 中容器无法互访的问题本质上是 Docker 网络隔离机制导致的。通过在 Docker Compose 配置中:

  1. 在服务定义中添加 networks: - dokploy-network
  2. 声明 dokploy-network 为外部网络

就可以让不同方式部署的容器加入同一个网络,实现相互访问。这是在 Dokploy 中进行容器编排时需要特别注意的配置细节。