docker nodejs 容器无法连接 mysql 容器

docker nodejs container cant connect mysql container

我在 Digital Ocean 运行宁 Docker 服务器。我有两个容器 Nodejs 和 Mysql。 Mysql 容器打开了 3306 端口。

当尝试通过 Docker 服务器 ip + 端口通过 nodejs 访问 mysql 时。我收到错误:连接 ETIMEDOUT。

当我在本地计算机上 运行 相同的 nodejs docker 设置时,它工作正常。有什么我想念的吗?

这里是nodejs docker-composer.yml:

version: '2'
services:
    test-web-install:
        image: example-nodejs:latest
        working_dir: /home/app
        volumes:
        - ./:/home/app
        command: sh -c 'nodemon'
        environment:
        - NODE_ENV=development
        - DB_HOST=192.168.11.207 #or public ip in internet
        - DB_PORT=3036
        - DB_PASSWORD=root
        - DB_USER=root
        - DB_DATABASE=root
        ports:
        - "3000:3000"

这里是 docker-composer.yml for mysql

mysql:
    container_name: flask_mysql
    restart: always
    image: mysql:5.6
    environment:
        MYSQL_ROOT_PASSWORD: 'root' # TODO: Change this
        MYSQL_USER: 'root'
        MYSQL_PASS: 'root'
        MYSQL_DATABASE: 'root'
    volumes:
    - ./data:/var/lib/mysql
    ports:
    - "3036:3306"
    restart: always

我会在前进时修改答案 - 根据您的意见,虽然我无法访问您的环境,但让我们尝试逐步解决这个问题:

  1. 让我们让数据库对 node.js 服务器可见
  2. 看看它是如何工作的,然后可能会深入研究 env 网络配置。

有 2 种方法可以解决第一个问题,也可能是第二个问题,正如我所看到的,但无法触及您的环境:

第一种方法将确保服务器可以看到数据库,但如果您无法从外部连接到数据库,则似乎存在 firewall/droplet 网络配置问题,您可以尝试第二种方法(不太可能改变,但最好尝试一下)。这假设您使用相同的 docker 组合和相同的桥接自定义网络:

version: '2'
services:
    test-web-install:
        image: example-nodejs:latest
        working_dir: /home/app
        volumes:
        - ./:/home/app
        command: sh -c 'nodemon'
        environment:
        - NODE_ENV=development
        - DB_HOST= mysql 
        - DB_PORT=3036
        - DB_PASSWORD=root
        - DB_USER=root
        - DB_DATABASE=root
        ports:
        - "3000:3000"
    networks:
      inner:
        alias: server
  mysql:
    container_name: flask_mysql
    restart: always
    image: mysql:5.6
    environment:
        MYSQL_ROOT_PASSWORD: 'root' # TODO: Change this
        MYSQL_USER: 'root'
        MYSQL_PASS: 'root'
        MYSQL_DATABASE: 'root'
    volumes:
    - ./data:/var/lib/mysql
    ports:
    - "<externalEnvIp>:3036:3306"
    restart: always
    networks:
      inner:
        alias: mysql
networks:
  inner:
      driver: bridge
      driver_opts:
        com.docker.network.enable_ipv6: "true"
        com.docker.network.bridge.enable_ip_masquerade: "true"
      ipam:
        driver: default
        config:
        - subnet: 172.16.100.0/24
          gateway: 172.16.100.1

选项 2:

version: '2'
services:
    test-web-install:
        image: example-nodejs:latest
        working_dir: /home/app
        volumes:
        - ./:/home/app
        command: sh -c 'nodemon'
        environment:
        - NODE_ENV=development
        - DB_HOST= mysql 
        - DB_PORT=3036
        - DB_PASSWORD=root
        - DB_USER=root
        - DB_DATABASE=root
        ports:
        - "3000:3000"
        network_mode: "host"
  mysql:
    container_name: flask_mysql
    restart: always
    image: mysql:5.6
    environment:
        MYSQL_ROOT_PASSWORD: 'root' # TODO: Change this
        MYSQL_USER: 'root'
        MYSQL_PASS: 'root'
        MYSQL_DATABASE: 'root'
    volumes:
    - ./data:/var/lib/mysql
    ports:
    - "3036:3306"
    restart: always
    network_mode: "host"

更精确的解决方案(找到问题的根源)将涉及深入挖掘您的 env 网络配置、docker 网络设置等,但这些解决方案现在可能有助于解决您的问题。

请尝试后输出结果。

docker 网络不允许您从容器内部返回到主机 IP 以连接到另一个容器公开的端口。我还没有深入研究这个问题,看看这是由于 iptables 规则还是 docker-proxy 内部的原因。无论哪种方式,都不值得研究,因为容器到容器网络是 docker.

的内置功能

要使用 docker 的网络,容器需要在同一个 docker 网络上,并且您可以通过 DNS 中的容器名称引用它们。使用 docker-compose,通常您可以使用服务名称代替容器名称(例如示例中的 test-web-install 和 mysql),因为 compose 为这些创建了别名。但是,由于您已覆盖 mysql 的容器名称,请改用 flask_mysql 容器名称。

在您的场景中,由于您已将启动与两个单独的 docker-compose.yml 文件分开,因此您将位于由 compose 创建的单独网络上。您有两种选择来解决此问题:

  1. 将两者合并为一个 docker-compose.yml ().
  2. 使用您预先创建的外部定义网络。

要执行后者,请先创建您的网络:

docker network create dbnet

然后更新您的 docker-compose.yml 以使应用看起来像:

version: '2'
networks:
    dbnet:
        external: true

services:
    test-web-install:
        image: example-nodejs:latest
        working_dir: /home/app
        volumes:
        - ./:/home/app
        command: sh -c 'nodemon'
        environment:
        - NODE_ENV=development
        - DB_HOST=flask_mysql
        - DB_PORT=3036
        - DB_PASSWORD=root
        - DB_USER=root
        - DB_DATABASE=root
        ports:
        - "3000:3000"
        networks:
        - dbnet

docker-compose.yml mysql:

version: '2'

networks:
  dbnet:
    external: true

services:

  mysql:
    container_name: flask_mysql
    restart: always
    image: mysql:5.6
    environment:
        MYSQL_ROOT_PASSWORD: 'root' # TODO: Change this
        MYSQL_USER: 'root'
        MYSQL_PASS: 'root'
        MYSQL_DATABASE: 'root'
    volumes:
    - ./data:/var/lib/mysql
    ports:
    - "3036:3306"
    restart: always
    networks:
    - dbnet