How to run EF Core migrations from Docker
July 24, 2024 by Anuraj
Docker dotnet EFCore
In this blog post, we’ll learn how to run EF Core migrations from Docker. One of the project I am working we had to deploy database changes to MySql Server using Docker. In this post we will explore various approaches to deploy database schema changes using Docker. In this project, all our model classes and dbcontext class is in a class library - not as part of the web API application.
Here is the first version of Docker file.
FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS predeploy
ARG CONNECTION_STRING
ENV ConnectionStrings__HelloWorldDbConnection=$CONNECTION_STRING
WORKDIR /src
COPY src/HelloWorld.Data/ src/HelloWorld.Data/
COPY src/HelloWorld.Api/ src/HelloWorld.Api/
RUN dotnet tool install -g dotnet-ef
ENV PATH="${PATH}:/root/.dotnet/tools"
RUN dotnet build src/HelloWorld.Api/HelloWorld.Api.csproj -c Release
CMD ["/usr/bin/dotnet", "ef", "database", "update","--project", "src/HelloWorld.Data/",
"--startup-project", "src/HelloWorld.Api/","--context", "HelloWorldDbContext"]
And we can build the container image using the following command docker build --build-arg CONNECTION_STRING="Server=host.docker.internal;Port=3306;database=helloworld;Uid=root;Pwd=Password@12345" -t anuraj/helloworld:v1 .
- In this command, I am passing the connection string - CONNECTION_STRING
as an build argument and setting the HelloWorldDbConnection
environment variable, so that EF Core CLI tool can connect to MySql Server and deploy the changes. In the Docker file, I am building the projects, then installing the dotnet ef
dotnet tool and building the project using dotnet build
command. We need to modify the PATH
environment variable, so that we can execute dotnet ef
command And when running the docker container using docker run
command, it will deploy the database changes using dotnet ef database update
command.
We will be able to deploy the changes using this container image, but the size of the image will be big because it is using SDK base image which we don’t for deploying database changes. We can optimize using the runtime image or any other small base image. Here is the modified version, it is a multistage build. And in this instead of deploying the database changes using dotnet tool, I am using the dotnet ef migration bundle
feature.
FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build
ARG CONNECTION_STRING
ENV ConnectionStrings__HelloWorldsDbConnection=$CONNECTION_STRING
WORKDIR /src
COPY src/HelloWorld.Data/ src/HelloWorld.Data/
COPY src/HelloWorld.Api/ src/HelloWorld.Api/
RUN dotnet tool install -g dotnet-ef
ENV PATH="${PATH}:/root/.dotnet/tools"
RUN dotnet ef migrations bundle --self-contained -r linux-musl-x64
--project src/HelloWorld.Data/ --startup-project src/HelloWorld.Api/ -o /migrations/efbundle
FROM alpine:3.14 AS runtime
ARG CONNECTION_STRING
ENV ConnectionStrings__HelloWorldsDbConnection=$CONNECTION_STRING
RUN apk upgrade --no-cache && \
apk add --no-cache libgcc libstdc++ libintl icu-libs
COPY --from=build /migrations .
CMD exec ./efbundle --connection $ConnectionStrings__HelloWorldsDbConnection
In this file, I am building the EF Bundle using linux-musl-x64
specific runtime targeting Alpine Linux version. Also it is without framework dependency (–self-contained parameter). And then I am using Alpine as runtime image and installing few tools and libraries to run the efbundle executable. And finally running the executable with the connection string parameter.
Now we can run the docker build --build-arg CONNECTION_STRING="Server=host.docker.internal;Port=3306;database=helloworld;Uid=root;Pwd=Password@12345" -t anuraj/helloworld:v1 .
command and run the container and deploy the changes to database.
Here is the screenshot the Docker container running to my local developer machine. For logging I enabled --verbose
flag in the CMD command instruction, like this - CMD exec ./efbundle --connection $ConnectionStrings__HelloWorldsDbConnection --verbose
This way we can deploy database changes using EF Core migrations and Docker.
Happy Programming
Copyright © 2024 Anuraj. Blog content licensed under the Creative Commons CC BY 2.5 | Unless otherwise stated or granted, code samples licensed under the MIT license. This is a personal blog. The opinions expressed here represent my own and not those of my employer. Powered by Jekyll. Hosted with ❤ by GitHub