无法使用 docker 容器连接到 MySQL 数据库
Posted
技术标签:
【中文标题】无法使用 docker 容器连接到 MySQL 数据库【英文标题】:Cannot connect to MySQL db using docker container 【发布时间】:2020-10-25 15:15:08 【问题描述】:我在Typescript
中编写了一个应用程序,它使用Typeorm
与mysql
数据库进行交互。当我使用npm run dev
(package.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
中启动,默认情况下它们可以通过主机名相互访问,例如app
和 db
。要尝试这一点,请将它们提出来,docker attach/exec
到 app
,然后尝试 ping db
。
见https://***.com/a/30173220/1148483
这意味着在您的应用中,您可以使用db
作为数据库主机配置。
【讨论】:
感谢您的回答,无论如何,如果我使用db
作为主机,我会得到getaddrinfo ENOTFOUND
两者都在同一个docker-compose
文件中运行?
不,lamp
和 myapp
有两个不同的docker-compose
文件,它们是两个不同的容器
是的,我的意思是你并不局限于一个容器或一个 dockerfile 中的基础镜像,而拥有多个实际上是它的目的。
是的,但我无法从 myapp 容器访问 Lamp Network (mysql)以上是关于无法使用 docker 容器连接到 MySQL 数据库的主要内容,如果未能解决你的问题,请参考以下文章
后端容器 ip 无法使用 docker 连接到数据库 mysql
无法从 docker 容器连接到 Localhost Mysql
Spring boot JDBC无法连接到docker容器中的mysql