.NET 8 WebAPI容器通过Docker Compose无法连接MySQL容器排查
.NET 8 WebAPI + Docker Compose 连接MySQL容器失败问题排查与解决
问题背景
在Windows 11环境下,通过Visual Studio搭建.NET 8解决方案,包含WebAPI后端项目及对应Dockerfile,使用Docker Compose进行容器编排。将原本独立运行的MySQL容器整合进Compose配置,使其与WebAPI容器处于同一Docker网络,MySQL数据存储在Docker卷中。
问题现象
- 容器外手动运行WebAPI项目+手动启动MySQL容器:可通过Swagger UI正常连接数据库并测试接口
- 通过Docker Compose启动所有服务:MySQL容器正常启动,但WebAPI容器报错
Unable to connect to any of the specified MySQL hosts,Debug模式下会在Program.cs连接数据库代码处崩溃
疑问
- 是否需要为MySQL容器单独创建Dockerfile?若需要,应放置在何处(解决方案中无MySQL项目)?
- 连接失败是否源于Docker网络问题?
当前配置文件
WebAPI Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base USER app WORKDIR /app EXPOSE 8080 EXPOSE 8081 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["ExpenseTracker.API/ExpenseTracker.API.csproj", "ExpenseTracker.API/"] COPY ["ExpenseTracker.Data/ExpenseTracker.Data.csproj", "ExpenseTracker.Data/"] COPY ["ExpenseTracher.CommonTools/ExpenseTracker.CommonTools.csproj", "ExpenseTracher.CommonTools/"] COPY ["ExpenseTracker.Services/ExpenseTracker.Services.csproj", "ExpenseTracker.Services/"] COPY ["ExpenseTracker.UserObjects/ExpenseTracker.UserObjects.csproj", "ExpenseTracker.UserObjects/"] RUN dotnet restore "./ExpenseTracker.API/ExpenseTracker.API.csproj" COPY . . WORKDIR "/src/ExpenseTracker.API" RUN dotnet build "./ExpenseTracker.API.csproj" -c $BUILD_CONFIGURATION -o /app/build FROM build AS publish ARG BUILD_CONFIGURATION=Release RUN dotnet publish "./ExpenseTracker.API.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false FROM base AS final WORKDIR /app COPY --from=publish /app/publish .
docker-compose.yml
services: expensetracker.api: image: ${DOCKER_REGISTRY-}expensetrackerapi container_name: expensetrackerapi build: context: . dockerfile: ExpenseTracker.API/Dockerfile depends_on: - mysql-et mysql-et: image: mysql:9.0.0 container_name: mysql-et ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: Valappil@1 MYSQL_DATABASE: ExpenseTracker volumes: - mysql-et-db:/var/lib/mysql volumes: mysql-et-db:
appsettings连接字符串
"ConnectionStrings": { // 已隐去用户和密码 "ExpTrkDBConn": "Server=mysql-et; port=3306; database=ExpenseTracker; user=zzzz; password=xxxxxxxxx;" }
Program.cs相关代码
string? connectionString = builder.Configuration.GetConnectionString("ExpTrkDBConn"); //builder.Services.AddDbContext<ExpenseTrackerDbContext>(options => options.UseMySQL(connectionString)); var serverVersion = new MySqlServerVersion(ServerVersion.AutoDetect(connectionString)); //builder.Services.AddDbContext<ExpenseTrackerDbContext>(options => // options.UseMySql(connectionString, // new MySqlServerVersion(ServerVersion.AutoDetect(connectionString)))); builder.Services.AddDbContext<ExpenseTrackerDbContext>(options => options.UseMySql(connectionString, new MySqlServerVersion(serverVersion)));
问题解答与修复方案
1. 是否需要为MySQL容器单独创建Dockerfile?
不需要。直接使用官方MySQL镜像(mysql:9.0.0)即可,官方镜像已封装完整的MySQL运行环境与初始化逻辑。若后续需自定义配置(如修改my.cnf),可通过挂载本地配置文件到容器的方式实现,无需编写独立Dockerfile。
2. 连接失败的核心原因
并非Docker网络问题,而是启动时序不匹配+MySQL初始化延迟导致:
depends_on仅保证MySQL容器先启动,但不保证MySQL服务完成初始化并可接受连接- WebAPI容器启动后立即尝试连接数据库,此时MySQL可能仍在执行初始化操作(如创建数据库、配置权限),导致连接失败
- 额外注意:连接字符串中使用的自定义用户
zzzz,当前Compose配置未创建该用户,若未使用root用户连接,会触发鉴权失败
具体修复步骤
步骤1:补全MySQL用户配置
若使用自定义用户zzzz连接数据库,需在Compose的MySQL服务中添加环境变量创建该用户并授权:
mysql-et: image: mysql:9.0.0 container_name: mysql-et ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: Valappil@1 MYSQL_DATABASE: ExpenseTracker MYSQL_USER: zzzz # 添加自定义用户名 MYSQL_PASSWORD: xxxxxx # 与连接字符串中的密码保持一致 volumes: - mysql-et-db:/var/lib/mysql
步骤2:添加启动等待逻辑(二选一)
方案A:Docker Compose健康检查(推荐)
修改docker-compose.yml,为MySQL服务添加健康检查,让WebAPI等待MySQL服务完全就绪后再启动:
services: expensetracker.api: image: ${DOCKER_REGISTRY-}expensetrackerapi container_name: expensetrackerapi build: context: . dockerfile: ExpenseTracker.API/Dockerfile depends_on: mysql-et: condition: service_healthy # 等待MySQL健康检查通过 mysql-et: image: mysql:9.0.0 container_name: mysql-et ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: Valappil@1 MYSQL_DATABASE: ExpenseTracker MYSQL_USER: zzzz MYSQL_PASSWORD: xxxxxx volumes: - mysql-et-db:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "zzzz", "-pxxxxxx"] interval: 5s timeout: 5s retries: 10
方案B:WebAPI代码添加重试逻辑
在Program.cs中配置DbContext时,添加数据库连接重试策略:
builder.Services.AddDbContext<ExpenseTrackerDbContext>(options => options.UseMySql(connectionString, serverVersion) .EnableRetryOnFailure( maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(10), errorNumbersToAdd: null));
步骤3:验证网络连通性(可选)
若修复后仍有问题,可进入WebAPI容器测试与MySQL的连通性:
- 启动Compose服务:
docker-compose up -d - 进入WebAPI容器:
docker exec -it expensetrackerapi sh - 安装ping工具(若容器未预装):
apt-get update && apt-get install iputils-ping - 测试网络连通:
ping mysql-et,能通则网络正常 - 测试数据库连接:
mysql -h mysql-et -u zzzz -pxxxxxx ExpenseTracker,能连接则数据库服务正常
内容的提问来源于stack exchange,提问作者Babu Mannavalappil
相关产品推荐
相关产品推荐

