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

Docker部署ASP.NET Core API时无法自动初始化SQL Server数据库种子数据

问题:Docker Compose启动ASP.NET Core与SQL Server时数据库初始化失败

尝试通过Docker Compose同时启动ASP.NET Core Web API和SQL Server实例,要求启动时自动完成数据库Schema创建、EF迁移执行及种子数据插入(种子数据通过重写EF Core的OnModelCreating方法配置)。但当前配置运行时后端容器无法连接到SQL Server,只能先单独启动数据库容器,再手动执行迁移脚本才能正常运行,需要实现全自动化初始化。


当前配置文件

.NET后端Dockerfile

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 7132
EXPOSE 5194

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["Services/MyApp/MyApp.API/MyApp.API.csproj", "Services/MyApp/MyApp.API/"]
RUN dotnet restore "Services/MyApp/MyApp.API/MyApp.API.csproj"
COPY . .

WORKDIR "/src/Services/MyApp/"

RUN dotnet tool install --global dotnet-ef --version 6.0.25
RUN /root/.dotnet/tools/dotnet-ef migrations add InitialCreate --verbose --startup-project "MyApp.API" --project "MyApp.Infrastructure"
RUN /root/.dotnet/tools/dotnet-ef database update --verbose --startup-project "MyApp.API" --project "MyApp.Infrastructure"

RUN dotnet build "MyApp.API/MyApp.API.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MyApp.API/MyApp.API.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app

COPY --from=publish /app/publish .

ENTRYPOINT ["dotnet", "MyApp.API.dll"]

Docker Compose配置

version: '3.8'

services:
  myapp-db:
    image: mcr.microsoft.com/mssql/server:2019-latest
    container_name: myapp-db
    environment:
      ACCEPT_EULA: Y
      SA_PASSWORD: mypassword
    ports:
      - "14330:1433"
    restart: always
    networks:
      - myapp-network
    volumes:
      - myapp-db-volume:/var/opt/mssql

  myapp-backend:
    build:
        context: ../myapp-backend/src
        dockerfile: Dockerfile
    container_name: myapp-backend
    environment:
      ASPNETCORE_HTTP_PORT: "https://+:7132"
      ASPNETCORE_URLS: "http://+:7132"
    ports:
      - "7132:7132"
      - "5194:5194"
    restart: always
    depends_on:
      - myapp-db
    networks:
      - myapp-network

networks:
  myapp-network:

volumes:
  myapp-db-volume:

数据库连接字符串

Server=myapp-db;Database=myappdb;User Id=SA;Password=mypassword;trusted_connection=false;encrypt=false

问题根源与解决步骤

核心问题

  1. 镜像构建阶段执行迁移错误:当前Dockerfile在build阶段就执行了dotnet ef database update,此时构建环境中不存在SQL Server容器,必然连接失败。迁移操作应放在容器启动阶段执行,而非镜像构建阶段。
  2. depends_on仅保证启动顺序:即使后端容器在数据库容器之后启动,SQL Server仍需要一段时间完成初始化,此时后端尝试连接会失败,需要等待数据库完全就绪后再执行后续操作。

修正方案

1. 修改Dockerfile,移除构建阶段的迁移命令

将迁移相关操作移到容器启动时执行,同时安装dotnet-ef工具并添加启动脚本:

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 7132
EXPOSE 5194
# 安装sqlcmd工具用于检测SQL Server状态
RUN apt-get update && apt-get install -y mssql-tools unixodbc-dev
ENV PATH="$PATH:/opt/mssql-tools/bin"

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["Services/MyApp/MyApp.API/MyApp.API.csproj", "Services/MyApp/MyApp.API/"]
RUN dotnet restore "Services/MyApp/MyApp.API/MyApp.API.csproj"
COPY . .
WORKDIR "/src/Services/MyApp/MyApp.API"
RUN dotnet build "MyApp.API.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MyApp.API.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
# 安装dotnet-ef工具
RUN dotnet tool install --global dotnet-ef --version 6.0.25
ENV PATH="$PATH:/root/.dotnet/tools"
# 复制启动脚本
COPY start.sh .
RUN chmod +x start.sh
# 使用自定义启动脚本
ENTRYPOINT ["./start.sh"]

2. 创建启动脚本start.sh

在API项目根目录创建该脚本,实现等待SQL Server就绪、执行迁移、启动API的流程:

#!/bin/bash
# 等待SQL Server可连接
until sqlcmd -S myapp-db -U SA -P mypassword -Q "SELECT 1" > /dev/null 2>&1; do
    echo "等待SQL Server启动中..."
    sleep 5
done

echo "SQL Server已就绪,执行数据库迁移..."
dotnet ef database update --startup-project MyApp.API --project ../MyApp.Infrastructure/MyApp.Infrastructure.csproj

echo "迁移完成,启动API服务..."
dotnet MyApp.API.dll

3. 优化Docker Compose配置,添加健康检查

为SQL Server服务添加健康检查,让后端容器等待数据库完全就绪后再启动:

version: '3.8'

services:
  myapp-db:
    image: mcr.microsoft.com/mssql/server:2019-latest
    container_name: myapp-db
    environment:
      ACCEPT_EULA: Y
      SA_PASSWORD: mypassword
    ports:
      - "14330:1433"
    restart: always
    networks:
      - myapp-network
    volumes:
      - myapp-db-volume:/var/opt/mssql
    # 健康检查:验证SQL Server是否可正常连接
    healthcheck:
      test: ["CMD-SHELL", "sqlcmd -S localhost -U SA -P mypassword -Q 'SELECT 1' || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 5

  myapp-backend:
    build:
        context: ../myapp-backend/src
        dockerfile: Dockerfile
    container_name: myapp-backend
    environment:
      ASPNETCORE_HTTP_PORT: "https://+:7132"
      ASPNETCORE_URLS: "http://+:7132"
      # 环境变量传入连接字符串(也可通过配置文件挂载)
      ConnectionStrings__DefaultConnection: "Server=myapp-db;Database=myappdb;User Id=SA;Password=mypassword;trusted_connection=false;encrypt=false"
    ports:
      - "7132:7132"
      - "5194:5194"
    restart: always
    depends_on:
      myapp-db:
        condition: service_healthy  # 等待数据库健康检查通过
    networks:
      - myapp-network

networks:
  myapp-network:

volumes:
  myapp-db-volume:

4. 验证种子数据

通过modelBuilder.Entity<T>().HasData(...)配置的种子数据,会在dotnet ef database update执行时自动插入到数据库中,无需额外操作。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 08:47:33