无法将 Docker 中的 Asp.net 核心 WebApi 与 EFCore Mysql 提供程序连接到主机服务器上的非 Docker Mysql
Cannot connect Asp.net Core WebApi in Docker with EFCore Mysql provider to non Docker Mysql on host server
我有一个 Asp.Net Core 3.1.3 WebApi,EfCore 3.1.3 和 Pomelo.EntityFrameworkCore.MySql 作为提供者
此 WebApi 在 Docker.
中构建和部署
主机服务器是Debian 10,配置了UFW作为防火墙。
我在主机服务器上安装了 Mysql 服务器。
我将 Mysql
的绑定地址设置为 0.0.0.0
/etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
log-error = /var/log/mysql/error.log
bind-address = 0.0.0.0
我在 UFW 中创建了一条规则,只允许本地主机和 docker0
网桥 ip 地址
在我的 docker-compose 配置中,我添加了主机服务器的 IP 地址,但是与 MySql 的连接失败了
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 3.1.3 initialized 'ApplicationContext' using provider 'Pomelo.EntityFrameworkCore.MySql' with options: using lazy-loading proxies ServerVersion 8.0.19 MySql
fail: Microsoft.EntityFrameworkCore.Database.Connection[20004]
An error occurred using the connection to database '<db_name>' on server '<host_ip_address>'.
info: Microsoft.EntityFrameworkCore.Infrastructure[10404]
A transient exception has been encountered during execution and the operation will be retried after 0ms.
MySql.Data.MySqlClient.MySqlException (0x80004005): Connect Timeout expired.
---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
在 Startup.cs 中,这是 EfCore 的配置:
services.AddDbContext<ApplicationContext>(opts =>
{
opts
.UseLazyLoadingProxies()
.UseMySql(connectionString, mySqlOptions =>
mySqlOptions
.ServerVersion(new Version(dbOptions.Version), ServerType.MySql)
.CharSet(CharSet.Utf8Mb4)
.EnableRetryOnFailure(3))
.EnableDetailedErrors();
});
为了构建连接字符串,我使用 MySql.Data.MySqlClient.MySqlConnectionStringBuilder:
var builder = new MySql.Data.MySqlClient.MySqlConnectionStringBuilder
{
Server = dbOptions.Server,
Database = dbOptions.Name,
UserID = dbOptions.User,
Password = dbOptions.Password,
PersistSecurityInfo = true
};
return builder.ToString();
我生成迁移脚本并将其部署到服务器上,因为 Pomelo 在调用 dbContext.Database.Migrate();
时将数据库名称设置为空字符串
在 docker 文件中,我公开了端口 80 和 443。
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
...
我在 docker-compose 文件中将数据库参数作为环境变量发送。
我做了一些数据播种以从 Identity 添加用户和角色。
var roleManager = provider.GetRequiredService<RoleManager<RoleModel>>();
roleManager.CreateAsync(new RoleModel(roleName)).GetAwaiter().GetResult();
...
我错过了什么?
除了在我的 docker-compose 中使用主机网络模式部署我的 docker 容器外,我没有找到任何其他解决方案。
docker-compose.yml
services:
<service_name>:
image: <image_name>
network_mode: "host" #important here
ports:
- "5000:5000"
- "5001:5001"
environment:
ASPNETCORE_Kestrel__Certificates__Default__Password: "${ASPNETCORE_KESTREL_CERTIFICATE_PASSWORD}"
ASPNETCORE_Kestrel__Certificates__Default__Path: "${ASPNETCORE_KESTREL_CERTIFICATE_PATH}"
ASPNETCORE_ENVIRONMENT: Production
"Database:Server": "${Database_Server}"
"Database:Version": "${Database_Version}"
"Database:Name": "${Database_Name}"
"Database:User": "${Database_User}"
"Database:Password": "${Database_Password}"
build:
context: ./Src
dockerfile: Dockerfile-build
volumes:
- ${CERTIFICATE_PATH}:/https
- ${LOGS_PATH}:/app/logs
在那种情况下,我只需要使用主机服务器的 IP 地址连接到 MySql(所有 Ufw,MySql 配置随附)。
我有一个 Asp.Net Core 3.1.3 WebApi,EfCore 3.1.3 和 Pomelo.EntityFrameworkCore.MySql 作为提供者 此 WebApi 在 Docker.
中构建和部署主机服务器是Debian 10,配置了UFW作为防火墙。
我在主机服务器上安装了 Mysql 服务器。
我将 Mysql
的绑定地址设置为 0.0.0.0/etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
log-error = /var/log/mysql/error.log
bind-address = 0.0.0.0
我在 UFW 中创建了一条规则,只允许本地主机和 docker0
网桥 ip 地址
在我的 docker-compose 配置中,我添加了主机服务器的 IP 地址,但是与 MySql 的连接失败了
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 3.1.3 initialized 'ApplicationContext' using provider 'Pomelo.EntityFrameworkCore.MySql' with options: using lazy-loading proxies ServerVersion 8.0.19 MySql
fail: Microsoft.EntityFrameworkCore.Database.Connection[20004]
An error occurred using the connection to database '<db_name>' on server '<host_ip_address>'.
info: Microsoft.EntityFrameworkCore.Infrastructure[10404]
A transient exception has been encountered during execution and the operation will be retried after 0ms.
MySql.Data.MySqlClient.MySqlException (0x80004005): Connect Timeout expired.
---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
在 Startup.cs 中,这是 EfCore 的配置:
services.AddDbContext<ApplicationContext>(opts =>
{
opts
.UseLazyLoadingProxies()
.UseMySql(connectionString, mySqlOptions =>
mySqlOptions
.ServerVersion(new Version(dbOptions.Version), ServerType.MySql)
.CharSet(CharSet.Utf8Mb4)
.EnableRetryOnFailure(3))
.EnableDetailedErrors();
});
为了构建连接字符串,我使用 MySql.Data.MySqlClient.MySqlConnectionStringBuilder:
var builder = new MySql.Data.MySqlClient.MySqlConnectionStringBuilder
{
Server = dbOptions.Server,
Database = dbOptions.Name,
UserID = dbOptions.User,
Password = dbOptions.Password,
PersistSecurityInfo = true
};
return builder.ToString();
我生成迁移脚本并将其部署到服务器上,因为 Pomelo 在调用 dbContext.Database.Migrate();
时将数据库名称设置为空字符串在 docker 文件中,我公开了端口 80 和 443。
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
...
我在 docker-compose 文件中将数据库参数作为环境变量发送。
我做了一些数据播种以从 Identity 添加用户和角色。
var roleManager = provider.GetRequiredService<RoleManager<RoleModel>>();
roleManager.CreateAsync(new RoleModel(roleName)).GetAwaiter().GetResult();
...
我错过了什么?
除了在我的 docker-compose 中使用主机网络模式部署我的 docker 容器外,我没有找到任何其他解决方案。
docker-compose.yml
services:
<service_name>:
image: <image_name>
network_mode: "host" #important here
ports:
- "5000:5000"
- "5001:5001"
environment:
ASPNETCORE_Kestrel__Certificates__Default__Password: "${ASPNETCORE_KESTREL_CERTIFICATE_PASSWORD}"
ASPNETCORE_Kestrel__Certificates__Default__Path: "${ASPNETCORE_KESTREL_CERTIFICATE_PATH}"
ASPNETCORE_ENVIRONMENT: Production
"Database:Server": "${Database_Server}"
"Database:Version": "${Database_Version}"
"Database:Name": "${Database_Name}"
"Database:User": "${Database_User}"
"Database:Password": "${Database_Password}"
build:
context: ./Src
dockerfile: Dockerfile-build
volumes:
- ${CERTIFICATE_PATH}:/https
- ${LOGS_PATH}:/app/logs
在那种情况下,我只需要使用主机服务器的 IP 地址连接到 MySql(所有 Ufw,MySql 配置随附)。