通过容器编排处理EF Core迁移

时间:2019-05-08 13:45:38

标签: docker asp.net-core docker-compose entity-framework-core dockerfile

我正在使用ASP.Net Core,Entity Framework Core和PostgreSQL构建一个香草的Web应用程序,我想使用它在Docker(无论是Docker Swarm还是Kubernetes)之上的容器协调器进行部署。

我想知道如何在部署过程中集成数据库迁移。

我当前的Dockerfile(我正在使用多阶段构建)是:

FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine as builder
COPY . /app
WORKDIR /app
RUN dotnet publish -c Release -o publish

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2
COPY --from=builder /app/publish /app/
WORKDIR /app
CMD dotnet MyApp.dll

我的docker-compose.yml(我想通过docker stack命令使用,因此它不包括build选项的使用)

version: '3'

services:
    app:
        image: edouardberthe/myapp
        ports:
            - 80:80
        depends_on:
            - db
    db:
        image: postgres:latest
        ports:
            - 5432:5432
        volumes:
            - data:/var/lib/postgresql/data
        environment:
            POSTGRES_USER: myapp_user
            POSTGRES_PASSWORD: myapp_pass
            POSTGRES_DB: myapp_db
volumes:
    data:

现在,我想在每个部署上启动迁移(由Entity Framework核心通过dotnet ef migrations add生成)。

在开发过程中,我使用dotnet ef database update。 但是,我不能这样做,因为这意味着我在运行时需要.Net Core SDK(此外,从SO帖子和Microsoft文档中,我已经发现这是一种不良做法)。

我从this discussion on github看到,最好使用dotnet ef migrations script --idempotent,它会在构建时生成纯SQL迁移文件,然后在运行时运行此脚本。但是(如文章中所述)“唯一的问题是,在运行时映像上,我还需要一个命令行客户端来使用数据库。”

如果我按照此过程进行操作,我的Dockerfile将会变得(更大,更复杂),例如:

FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine as builder
COPY . /app
WORKDIR /app
RUN dotnet publish -c Release -o publish \
    && dotnet ef migrations script --output publish/migrate.sql --idempotent 

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2
COPY --from=builder /app/publish /app/
WORKDIR /app
RUN apt-get update \
    && mkdir -p /usr/share/man/man1 \
    && mkdir -p /usr/share/man/man7 \
    && apt-get install --no-install-recommends -y postgresql-client \
    && rm -rf /var/lib/apt/lists/* \
    && apt-get clean
CMD psql -f migrate.sql && dotnet MyApp.dll

(这两行mkdir来自this postthis fix) 除了增加了复杂性之外,最后一个CMD行也不起作用,因为我无权访问数据库! 我确实知道数据库名称,用户名和密码将是什么(即使我不认为将其放入Dockerfile中也是一个好主意),但是我还不知道host将是什么是。

在这样的设置中,没有更好的方法来处理迁移吗?

谢谢

1 个答案:

答案 0 :(得分:0)

我不确定这是否是最佳实践,但是您可以从C#代码触发模式升级。您必须在Startup.cs的Configure方法中添加以下代码:

using (var serviceScope = app.ApplicationServices
    .GetRequiredService<IServiceScopeFactory>()
    .CreateScope())
{
    using (var context = serviceScope.ServiceProvider.GetService<EasyAdminContext>())
    {
        context.Database.Migrate();
    }
}

这样,在应用程序启动时将更新数据库