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

3

我使用 Typescript 写了一个应用程序,它使用 TypeormMySQL 数据库交互。当我使用 npm run dev 运行该应用程序时,连接使用以下凭据工作正常:

"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容器中可以看到,每个端口都被正确地暴露出来: enter image description here

lamp_db_1 是数据库主机名,请使用它代替 localhost 或 127.0.0.1。 - undefined
假设它们在同一个 docker-compose.yml 文件中(这些容器名称表明它们是),Compose 服务块的名称 db 也可以作为主机名使用。在 Docker 中,localhost 几乎总是指向“此容器”,而不是其他容器或主机。 - undefined
@abestrad 如果我指定为 host: 172.17.0.1,它是可以工作的,但是是否可能共享mysql容器的网络? - undefined
1
你在compose中如何声明你的网络?默认情况下,它为你的应用程序设置了一个单一的网络。每个服务都应该加入默认网络,并且可以通过该网络上的其他服务进行访问,并且可以使用主机名(容器名称)进行发现。 - undefined
1
Compose 中的网络 是有用的背景资料;它描述了 Compose 为您自动设置的内容以及默认情况下可达到的主机名。 - undefined
显示剩余3条评论
3个回答

3

不要使用 localhost,而是用 host.docker.internal 替换它。这样可以让你连接本地数据库。


1
这救了我的一天!谢谢,非常感激! - undefined
1
太感谢了!你真是救了我一天!这个需要标记为正确答案。 - undefined

3

这里的问题是每个容器使用它们自己的网络,即使我将 mysql 容器暴露在 3306 端口,我也不能从 myapp 容器访问 mysql,因为 myapp 容器使用另一个网络。

所以执行以下命令:docker network ls,我可以列出所有可用的网络,然后执行如下操作:

docker network inspect bridge

运行命令返回以下网关:172.17.0.1。

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

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"


0

docker-compose

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

你可以将你的docker-compose.yml文件更改为以下内容(MySQL部分从https://hub.docker.com/_/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/exec命令进入app容器,并尝试执行ping db命令。

请参考https://dev59.com/oF0a5IYBdhLWcg3wk5dw#30173220

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


谢谢你的回答。不管怎样,如果我使用db作为主机,我会得到getaddrinfo ENOTFOUND的错误。 - undefined
两者都在同一个docker-compose文件中运行吗? - undefined
不对,lampmyapp有两个不同的docker-compose文件,它们是两个不同的容器。 - undefined
是的,我的意思是在一个Dockerfile中你不仅限于一个容器或基础镜像,而且拥有多个容器或基础镜像实际上就是它的目的。 - undefined
sfarzoso和@Andrei Mustață..问题解决了吗?我遇到了类似的问题,不确定该如何解决...任何线索都会有帮助。谢谢! - undefined
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接