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

如何在Docker Compose中等待EF迁移完成后再启动ApiServer容器?

解决Docker Compose中ASP.NET + EF迁移 + SQL Server的启动顺序问题

我正在构建docker-compose.yml,用于本地运行ASP.NET + Entity Framework迁移 + SQL Server,目标是用一条docker compose up --build一键启动。但depends_on只会等容器启动就继续执行后续流程,我需要等entity-framework-migrations和populate_data_sqlserver容器完成任务后,再启动ApiServer。启动顺序必须严格遵循:SQL Server启动就绪 → 执行EF迁移 → 填充初始化数据 → 最后启动Api服务器。当前的compose配置如下:

version: '3.9'

services:
    sql_server:
        image: mcr.microsoft.com/azure-sql-edge
        environment:
            - "ACCEPT_EULA=Y"
            - "SA_PASSWORD=Pa$$W0rd"
        restart: always
        ports:
            - "1433:1433"
        volumes:
            - ./sql_server:/var/lib/sql_server

    entity-framework-migrations:
        build:
            context: ../
            dockerfile: Dockerfile
        depends_on:
            - sql_server
        environment:
            - ConnectionStrings__SQL=Server=sql_server,1433;Persist Security Info=False;User ID=sa;Password=Pa$$W0rd;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False;;
        command: migrate

    populate_data_sqlserver:
        image: mcr.microsoft.com/mssql-tools:latest
        depends_on:
            - sql_server
            - entity-framework-migrations
            - wait_migrations
        command: /bin/bash -c '/opt/mssql-tools/bin/sqlcmd -S sql_server -U SA -P "Pa$$W0rd" -i /var/lib/sql_server/setup_db.sql -I'
        volumes:
            - ./sql_server:/var/lib/sql_server

    ApiServer:
        image: api-server-product:latest
        build:
            context: ../
            dockerfile: Dockerfile
        environment:
            - ASPNETCORE_URLS=http://+:5000
            - ConnectionStrings__SQL=Server=sql_server,1433;Persist Security Info=False;User ID=sa;Password=Pa$$W0rd;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False;;
        ports:
            - "5000:5000"
        depends_on:
            - sql_server
            - entity-framework-migrations
            - populate_data_sqlserver

解决方案:用共享标记+Healthcheck实现严格顺序

步骤1:给SQL Server添加Healthcheck,确保真正就绪

depends_on只检查容器是否启动,不关心数据库是否可用。给SQL Server加Healthcheck,确保它能正常接受连接:

sql_server:
    image: mcr.microsoft.com/azure-sql-edge
    environment:
        - "ACCEPT_EULA=Y"
        - "SA_PASSWORD=Pa$$W0rd"
    restart: always
    ports:
        - "1433:1433"
    volumes:
        - ./sql_server:/var/lib/sql_server
    healthcheck:
        test: ["CMD-SHELL", "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'Pa$$W0rd' -Q 'SELECT 1' || exit 1"]
        interval: 10s  # 每10秒检查一次
        timeout: 5s    # 超时时间5秒
        retries: 5     # 最多重试5次

步骤2:添加共享卷存储任务完成标记

在compose顶部定义一个共享卷,用来记录迁移和数据填充是否完成:

version: '3.9'

# 新增共享卷,用于传递任务完成信号
volumes:
    task-status: {}

services:
    # ... 其他服务

步骤3:修改EF迁移容器,完成后写入标记

让迁移容器在完成任务后,在共享卷里创建一个标记文件,同时依赖SQL Server的健康状态:

entity-framework-migrations:
    build:
        context: ../
        dockerfile: Dockerfile
    depends_on:
        sql_server:
            condition: service_healthy  # 等SQL Server真正就绪才启动
    environment:
        - ConnectionStrings__SQL=Server=sql_server,1433;Persist Security Info=False;User ID=sa;Password=Pa$$W0rd;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False;;
    command: /bin/bash -c "migrate && touch /task-status/migrations_done"  # 完成后创建标记
    volumes:
        - task-status:/task-status  # 挂载共享卷

步骤4:修改数据填充容器,等待迁移完成再执行

让数据填充容器先等待迁移标记出现,完成后也写入自己的标记:

populate_data_sqlserver:
    image: mcr.microsoft.com/mssql-tools:latest
    depends_on:
        sql_server:
            condition: service_healthy
    command: /bin/bash -c "
        # 等待迁移完成标记
        until [ -f /task-status/migrations_done ]; do sleep 2; done;
        # 执行数据填充脚本
        /opt/mssql-tools/bin/sqlcmd -S sql_server -U SA -P 'Pa$$W0rd' -i /var/lib/sql_server/setup_db.sql -I;
        # 写入数据填充完成标记
        touch /task-status/data_populated
    "
    volumes:
        - ./sql_server:/var/lib/sql_server
        - task-status:/task-status

步骤5:修改ApiServer,等待数据填充完成再启动

让ApiServer启动前检查数据填充的标记,确保前面的任务都完成:

ApiServer:
    image: api-server-product:latest
    build:
        context: ../
        dockerfile: Dockerfile
    environment:
        - ASPNETCORE_URLS=http://+:5000
        - ConnectionStrings__SQL=Server=sql_server,1433;Persist Security Info=False;User ID=sa;Password=Pa$$W0rd;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False;;
    ports:
        - "5000:5000"
    depends_on:
        sql_server:
            condition: service_healthy
    command: /bin/bash -c "
        # 等待数据填充完成标记
        until [ -f /task-status/data_populated ]; do sleep 2; done;
        # 启动Api服务(替换成你的实际启动命令)
        dotnet YourApiAssembly.dll
    "
    volumes:
        - task-status:/task-status

替代方案:将迁移和填充整合到ApiServer启动流程

如果不想用单独的迁移和填充容器,可以把逻辑直接放到ApiServer的启动脚本里:

  1. 在ApiServer的Dockerfile中安装mssql-tools和EF工具;
  2. 创建启动脚本start.sh:
#!/bin/bash
set -e

# 等待SQL Server就绪
echo "Waiting for SQL Server..."
until /opt/mssql-tools/bin/sqlcmd -S sql_server -U sa -P 'Pa$$W0rd' -Q 'SELECT 1' > /dev/null 2>&1; do
    sleep 2
done

# 执行EF迁移
echo "Running EF migrations..."
dotnet ef database update --project YourMigrationProject --startup-project YourApiProject

# 填充初始化数据
echo "Populating initial data..."
/opt/mssql-tools/bin/sqlcmd -S sql_server -U SA -P 'Pa$$W0rd' -i /var/lib/sql_server/setup_db.sql -I

# 启动Api服务
echo "Starting API server..."
dotnet YourApiAssembly.dll
  1. 在compose中挂载脚本并设置为启动命令:
ApiServer:
    # ... 其他配置
    command: /bin/bash /app/start.sh
    volumes:
        - ./sql_server:/var/lib/sql_server
        - ./start.sh:/app/start.sh

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 03:35:02