You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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连接数据库代码处崩溃

疑问

  1. 是否需要为MySQL容器单独创建Dockerfile?若需要,应放置在何处(解决方案中无MySQL项目)?
  2. 连接失败是否源于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的连通性:

  1. 启动Compose服务:docker-compose up -d
  2. 进入WebAPI容器:docker exec -it expensetrackerapi sh
  3. 安装ping工具(若容器未预装):apt-get update && apt-get install iputils-ping
  4. 测试网络连通:ping mysql-et,能通则网络正常
  5. 测试数据库连接:mysql -h mysql-et -u zzzz -pxxxxxx ExpenseTracker,能连接则数据库服务正常

内容的提问来源于stack exchange,提问作者Babu Mannavalappil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 11:55:06