无法使用 docker 容器连接到 MySQL 数据库

Posted

技术标签:

【中文标题】无法使用 docker 容器连接到 MySQL 数据库【英文标题】:Cannot connect to MySQL db using docker container 【发布时间】: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 自动为您执行的设置,以及默认情况下可以访问的主机名。 【参考方案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://***.com/a/30173220/1148483

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

【讨论】:

感谢您的回答,无论如何,如果我使用db 作为主机,我会得到getaddrinfo ENOTFOUND 两者都在同一个docker-compose文件中运行? 不,lampmyapp 有两个不同的docker-compose 文件,它们是两个不同的容器 是的,我的意思是你并不局限于一个容器或一个 dockerfile 中的基础镜像,而拥有多个实际上是它的目的。 是的,但我无法从 myapp 容器访问 Lamp Network (mysql)

以上是关于无法使用 docker 容器连接到 MySQL 数据库的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 docker 容器连接到 MySQL 数据库

后端容器 ip 无法使用 docker 连接到数据库 mysql

无法从 docker 容器连接到 Localhost Mysql

Spring boot JDBC无法连接到docker容器中的mysql

Python Flask SQLAlchemy 容器无法连接到 MySQL 容器

Mariadb docker容器无法使用Python连接到主机上的MySQL服务器(111连接被拒绝)