【问题标题】:Cannot connect to MySQL db using docker container无法使用 docker 容器连接到 MySQL 数据库
【发布时间】:2020-10-25 15:15:08
【问题描述】:

我在Typescript 中编写了一个应用程序,它使用TypeormMySQL 数据库进行交互。当我使用npm run devpackage.json 脚本)运行应用程序时,使用这些凭据可以正常连接:

"type": "mysql",
"host": "127.0.0.1",
"port": 3306,
"username": "root",
"password": "root",
"database": "mydb",

但是当我启动我的 Docker 容器时,我得到:

> Error: connect ECONNREFUSED 127.0.0.1:3306
> errno: -111,
> code: 'ECONNREFUSED',
> syscall: 'connect',
> address: '127.0.0.1',
> port: 3306,
> fatal: true

我无法解决这个问题,我也尝试将127.0.0.1 更改为localhost,但同样的问题。这很奇怪,因为我使用Dbeaver 连接我的LAMP,这也是一个Docker 容器容器,我可以建立连接。

似乎只与容器连接有关的问题,也许应用程序的容器不知道网络127.0.0.1

这是我的图片文件:

FROM node:stretch-slim

WORKDIR /myapp

COPY package.json ./
COPY ./dist ./dist

RUN npm install

EXPOSE 4000
ENV NODE_ENV development
ENV PORT 4000
ENV URL http://localhost:4000
ENV JWT_SECRET secret

CMD ["npm", "run", "start", "dev"]

这是我的docker-compose.yml

version: '3'
services:
  app:
    container_name: myapp
    restart: always
    build: .
    ports:
      - '4000:4000'

为了编译我的容器,我做了:docker-compose up --build

怎么了?从我的lamp 容器中可以看出,每个端口都正确暴露:

【问题讨论】:

  • lamp_db_1 是数据库主机名,使用它代替 localhost 或 127.0.0.1
  • @abestrad 如果我这样做,我会得到:getaddrinfo ENOTFOUND lamp_db_1
  • 假设它们在同一个 docker-compose.yml 文件中(这些容器名称表明它们是),Compose 服务块名称 db 也将用作主机名。 Docker 中的localhost 几乎总是“这个容器”,而不是另一个容器或主机。
  • 您如何在 compose 中声明您的网络?默认情况下,它会为您的应用程序设置一个网络。每个服务都应该加入默认网络,并且该网络上的其他服务都可以访问。和 可发现 使用主机名(容器名称)
  • Networking in Compose 是有用的背景资料;它描述了 Compose 自动为您执行的设置,以及默认情况下可以访问的主机名。

标签: mysql node.js docker docker-compose docker-networking


【解决方案1】:

这里的问题是每个容器都使用自己的网络,即使我在端口3306 上暴露了mysql 容器,我也无法从myapp 容器访问mysql,因为myapp 容器使用另一个网络。

所以执行以下命令:docker network ls 我能够列出所有可用的网络,然后我做到了:

docker network inspect bridge

它返回了以下gateway: 172.17.0.1

解决方案是将localhost 替换为172.17.0.1。但是我不太喜欢下面的解决方案,所以我重建了myapp图像,之前在docker-compose.yml中添加了network_mode,所以现在我有了:

version: '3'
services:
  app:
    container_name: myapp
    restart: always
    build: .
    ports:
      - '4000:4000'
    network_mode: 'host'

如文档所述:

如果您对容器使用主机网络模式,则该容器的网络堆栈不会与 Docker 主机隔离(容器共享主机的网络命名空间),并且容器不会获得自己的 IP 地址分配。例如,如果您运行一个绑定到端口 80 的容器并使用主机网络,则容器的应用程序可在主机 IP 地址的端口 80 上使用。

我不知道是否有更好的解决方案,到目前为止我是Docker 菜鸟,所以也许这方面的专家可以提出更好的解决方案来共享容器网络,例如mysql ,然后从其他容器访问该共享网络。

另一种解决方案是"host": "host.docker.internal"

【讨论】:

    【解决方案2】:

    docker-compose

    docker-compose 不仅限于一项服务,您还可以拥有整个系统,在您的情况下,这意味着数据库服务器、您的应用程序以及所有其他东西。

    您可以将您的 docker-compose.yml 文件更改为如下所示(从 https://hub.docker.com/_/mysql 复制的 MySQL 位)

    version: '3'
    services:
    
      db:
        image: mysql
        command: --default-authentication-plugin=mysql_native_password
        restart: always
        environment:
          MYSQL_ROOT_PASSWORD: example
    
      app:
        container_name: myapp
        restart: always
        build: .
        ports:
          - '4000:4000'
    

    网络

    因为您的容器在同一个docker-compose 中启动,默认情况下它们可以通过主机名相互访问,例如appdb。要尝试这一点,请将它们提出来,docker attach/execapp,然后尝试 ping db

    https://stackoverflow.com/a/30173220/1148483

    这意味着在您的应用中,您可以使用db 作为数据库主机配置。

    【讨论】:

    • 感谢您的回答,无论如何,如果我使用db 作为主机,我会得到getaddrinfo ENOTFOUND
    • 两者都在同一个docker-compose文件中运行?
    • 不,lampmyapp 有两个不同的docker-compose 文件,它们是两个不同的容器
    • 是的,我的意思是你并不局限于一个容器或一个 dockerfile 中的基础镜像,而拥有多个实际上是它的目的。
    • 是的,但我无法从 myapp 容器访问 Lamp Network (mysql)
    猜你喜欢
    • 2020-03-12
    • 2022-01-20
    • 2020-09-05
    • 2016-04-17
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    相关资源
    最近更新 更多