Docker Compose部署.NET API+MySQL+EF时插入数据失败求助
问题排查:Docker Compose部署.NET API + MySQL时EF插入失败
问题描述
我用Docker Compose部署基于.NET的API服务,搭配MySQL数据库,通过API端触发Entity Framework(EF)的数据库迁移操作。API和MySQL容器看起来都正常启动了,但发起请求时,Docker控制台报出EF执行插入命令失败的错误:
mysql-1 | 2024-10-30T03:02:44.680273Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.40' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL. api-1 | fail: Microsoft.EntityFrameworkCore.Database.Command[20102] api-1 | Failed executing DbCommand (44ms) [Parameters=[@p0='?' (DbType = Int32), @p1='?' (Size = 4000), @p2='?' (Size = 4000), @p3='?' (Size = 4000)], CommandType='Text', CommandTimeout='30'] api-1 | SET AUTOCOMMIT = 1; api-1 | INSERT INTO `User` (`Id`, `Email`, `Name`, `Password`) api-1 | VALUES (@p0, @p1, @p2, @p3);
相关配置文件
Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base USER app WORKDIR /app EXPOSE 8080 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["ApiNetEFMySQL.csproj", "."] RUN dotnet restore "./ApiNetEFMySQL.csproj" COPY . . WORKDIR "/src/." RUN dotnet build "./ApiNetEFMySQL.csproj" -c $BUILD_CONFIGURATION -o /app/build FROM build AS publish ARG BUILD_CONFIGURATION=Release RUN dotnet publish "./ApiNetEFMySQL.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "ApiNetEFMySQL.dll"]
docker-compose.yml(含EF命令配置)
services: api: build: context: . dockerfile: Dockerfile ports: - "8080:8080" environment: - ASPNETCORE_ENVIRONMENT=Production - ConnectionStrings__LocalConnection=Server=mysql;Port=3306;Database=testapi;User ID=root;Password=2870FJlw; depends_on: - mysql command: > sh -c "until nc -z mysql 3306; do echo 'Waiting for MySQL...'; sleep 2; done; dotnet ef database update; dotnet ApiNetEFMySQL.dll" networks: - my_network mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: 2870FJlw MYSQL_DATABASE: testapi ports: - "3307:3306" volumes: - mysql_data:/var/lib/mysql networks: - my_network volumes: mysql_data: networks: my_network:
连接字符串配置
"ConnectionStrings": { "LocalConnection": "Server=mysql;Port=3307;Database=testapi;User ID=root;Password=<mypassword>;" } }
Program.cs数据库配置
var connection = builder.Configuration.GetConnectionString("LocalConnection") ?? throw new InvalidOperationException("String de conexion no encontrada."); builder.Services.AddDbContext<UserContext>(options => options.UseMySql( connection, ServerVersion.AutoDetect(connection)));
排查与解决方案
1. 修复连接字符串端口错误
容器内部通过Docker网络访问MySQL时,必须使用容器内部端口3306,而非宿主机映射的3307端口。当前本地配置文件中的连接字符串端口写反了,导致API无法正确连接数据库。
修正后的连接字符串:
"ConnectionStrings": { "LocalConnection": "Server=mysql;Port=3306;Database=testapi;User ID=root;Password=2870FJlw;" }
2. 解决EF迁移无法执行的问题
当前Dockerfile最终使用的是aspnet:8.0运行时镜像,该镜像不包含.NET SDK和EF工具,因此docker-compose中配置的dotnet ef database update命令会执行失败,导致数据库表未创建,插入操作自然报错。
推荐两种解决方式:
方案A:程序启动时自动执行迁移(推荐)
在Program.cs中添加自动迁移逻辑,替代容器启动时的EF命令:
var app = builder.Build(); // 自动执行数据库迁移(生产环境需谨慎使用,建议提前手动执行) using (var scope = app.Services.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService<UserContext>(); dbContext.Database.Migrate(); } // 后续中间件配置... app.Run();
同时删除docker-compose.yml中command字段里的dotnet ef database update;部分,保留等待MySQL的逻辑即可:
command: > sh -c "until nc -z mysql 3306; do echo 'Waiting for MySQL...'; sleep 2; done; dotnet ApiNetEFMySQL.dll"
方案B:给容器安装EF工具(不推荐,镜像体积增大)
修改Dockerfile的final阶段,安装EF工具:
FROM base AS final WORKDIR /app COPY --from=publish /app/publish . # 安装EF全局工具 RUN dotnet tool install --global dotnet-ef ENV PATH="$PATH:/home/app/.dotnet/tools" ENTRYPOINT ["dotnet", "ApiNetEFMySQL.dll"]
3. 验证数据库表是否存在
进入MySQL容器,检查testapi数据库中是否存在User表:
# 进入MySQL容器 docker exec -it mysql-1 mysql -uroot -p2870FJlw # 切换到testapi数据库 use testapi; # 查看所有表 show tables;
如果没有User表,说明迁移未执行成功,回到步骤2排查。
4. 确认MySQL用户权限
检查root用户是否允许从Docker网络连接:
在MySQL命令行中执行:
SELECT user, host FROM mysql.user WHERE user='root';
若host字段为%,则表示允许所有主机连接,权限正常;若不是,需修改权限:
ALTER USER 'root'@'%' IDENTIFIED BY '2870FJlw'; FLUSH PRIVILEGES;
内容的提问来源于stack exchange,提问作者Fede Woodward
相关产品推荐
相关产品推荐

