C# 和 Docker - 无法从容器化 .NET Core 3.1 Web API 连接到容器化 MySQL 服务器
Posted
技术标签:
【中文标题】C# 和 Docker - 无法从容器化 .NET Core 3.1 Web API 连接到容器化 MySQL 服务器【英文标题】:C# and Docker - Can't connect to containerized MySQL server from containerized .NET Core 3.1 Web API 【发布时间】:2020-12-11 04:21:42 【问题描述】:作为参考,我尝试了以下链接中的想法无济于事:
Docker-Compose Unable to connect to any of the specified mysql hosts Connect to MySQL container from Web Api .Net Core Container? How to get Ip Address?
我有三个容器化应用程序:mysql@8.0“暴露”——因为没有更好的术语——在端口 9999 后面; .NET Core 3.1 WebAPI;和一个容器化的 Angular 应用程序。 Angular 应用程序可以成功地调用 5001 端口后面的 WebAPI。问题似乎是 Web API 与 MySQL 容器建立了连接。
所有应用程序都作为容器部署在我的本地开发工作站上。 Web API 和 MySQL 数据库正在使用一个 docker-compose.yml
进行部署,我在下面分享了它。我为前端应用构建了一个简单的镜像,并从 Docker 命令行进行部署。
这是我的docker-compose.yml
API 和 DB:
version: "3.3"
services: # list of services composing your application
db: # the service hosting your MySQL instance
image: mysql:8.0 # the image and tag docker will pull from docker hub
volumes: # this section allows you to configure persistence within multiple restarts
- db_data:/var/lib/mysql
restart: always # if the db crash somehow, restart it
ports:
- "9999:3306"
environment: # env variables, you usually set this to override existing ones
MYSQL_ROOT_PASSWORD: *****
networks:
- soar-network
soar-api: # you application service
build: ./ # this tells docker-compose to not pull from docker hub, but to build from the Dockerfile it will find in ./
restart: always
ports:
- "5001:80"
networks:
- soar-network
# set a dependency between your service and the database:
# this means that your application will not run if the db service is not running,
# but it doesn't assure you that the dabase will be ready to accept incoming connection
# (so your application could crash untill the db initializes itself)
depends_on:
- db
volumes:
db_data: # this tells docker-compose to save your data in a generic docker volume. You can see existing volumes typing 'docker volume ls'
networks:
soar-network:
driver: bridge
Web API 代码对我在代码中使用的DbContext
使用以下连接字符串:
"ConnectionStrings":
"DefaultConnection": "server=localhost;port=9999;uid=root;pwd=*****;database=SoarDb"
请注意,连接字符串中的port
与我在docker-compose
中映射的内容相匹配。我已经尝试过使用3306
和33060
,也无济于事。
我也尝试过使用127.0.0.1
作为server
值,但没有成功。
Web API 容器中记录的错误如下:
soar-api_1 | fail: Microsoft.EntityFrameworkCore.Database.Connection[20004]
soar-api_1 | An error occurred using the connection to database 'SoarDb' on server 'localhost'.
soar-api_1 | fail: Microsoft.EntityFrameworkCore.Query[10100]
soar-api_1 | An exception occurred while iterating over the results of a query for context type 'DataAccess.SoarDataContext'.
soar-api_1 | MySql.Data.MySqlClient.MySqlException (0x80004005): Unable to connect to any of the specified MySQL hosts.
soar-api_1 | at MySqlConnector.Core.ServerSession.ConnectAsync(ConnectionSettings cs, ILoadBalancer loadBalancer, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ServerSession.cs:line 442
另一个奇怪的事情是:我可以添加迁移并使用dotnet-ef add migration
和dotnet-ef database update
将数据库更新到这个特定的容器化数据库。
非常感谢任何见解。我尝试了许多不同的设置排列和调整,但没有运气,不知道我在误解什么。
【问题讨论】:
【参考方案1】:您的错误是,从soar-api
容器的角度来看,localhost
只是指回容器(soar-api
正在其中运行)...而不是 docker 正在运行的服务器(即下一层)。
相反,您应该能够将连接字符串设置为 server=db;port=3306;...
这是因为 docker 提供了一个 DNS 代理,允许您按名称访问同一网络上的容器(看起来您已经正确设置了 @987654326 @)
实际上容器db
获得一个IP(例如:A),而容器soar-api
获得另一个IP(B)。您来自 B 的连接需要指定 IP 地址 A,除非您将 docker-compose 配置为指定(您可以do this too,但正如您一样)已经写好了,docker会帮你处理的)
我想您是在主服务器外部运行迁移,而不是在任何一个容器内。
如果没有其他服务需要直接访问它(这是为了让外部计算机连接到 docker-server 并访问该服务),您可能不需要在 9999
上的 9999
上公开 MySQL。
注意127.0.0.1
(实际上是127.0.0.0/8
空间中的任何地址)是localhost
的同义词。还有::1/128
(IPv6,如果已启用)
【讨论】:
感谢您的回复。我在帖子中确实提到有 3 个容器化应用程序:其中 2 个可以在docker-compose
中找到,还有 1 个(此处未共享)具有在 Dockerfile 中定义并从 docker run
CLI 部署的图像.感谢您的想法;我一定会试一试的!
所以我发现在 conn 字符串中使用服务名称(在这种情况下为db
)是必要的;谢谢。但是,连接字符串似乎还需要包含 3306 作为端口号——not 9999。你能解释一下为什么会这样吗?连接字符串现在是"DefaultConnection": "server=db;port=3306;uid=root;pwd=****;database=SoarDb"
哦,是的,所以 port:port 映射是将服务器(迄今为止未知的 IP)端口路由到 docker 容器端口。在 docker 网络中,任何容器(在该网络上)上的任何公开端口都可以直接访问。您通常不需要对外公开端口(如果 docker 之外没有任何东西需要访问 MySQL,则不需要公开 9999)。
啊哈!明白了;再次感谢。就我而言,我正在从我的 Docker 主机对容器运行迁移和查询,not 在任何容器内。但由于我的 Docker 主机上也有一个 MySQL 服务器实例——而不是在容器中——在默认端口 3306 后面,我需要在公开 MySQL 容器时选择不同的端口。现在一切都说得通了!以上是关于C# 和 Docker - 无法从容器化 .NET Core 3.1 Web API 连接到容器化 MySQL 服务器的主要内容,如果未能解决你的问题,请参考以下文章
CentOS7下使用Docker容器化.net Core 2.2
无法从 docker windows 容器中的 asp.net 核心应用程序连接到主机数据库