I have an Azure App Service "Web App for docker containers" which needs to have Entity-Framework database migrations run before the Web App goes online. The MS Documentation (here too) says that the Web App should not instigate the migration. So I assume the migration must come from a run-time command in the docker image...the same docker image that contains the Web App. I say "run-time" because my Azure ARM deployment leverages github CI/CD "actions", which don't have a migration capability at deployment time. Anyway, the corresponding multi-stage dockerfile correctly generates the migration.sql
file that I need, but I'm not sure subsequently how to install and execute the necessary SqlCmd.exe
(at run-time) which runs that prior migration.sql
file as a parameter.
Below is my current dockerfile (targeting Windows Server, not Linux), which originally had been generated for me by Visual Studio 2022. The principle modification I made was the installation of the "dotnet EF" migration tool, and the command to build the migration script.
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
#Depending on the operating system of the host machines(s) that will build or run the containers, the image specified in the FROM statement may need to be changed.
#For more information, please see https://aka.ms/containercompat
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0-windowsservercore-ltsc2022 AS build
RUN dotnet tool install --global dotnet-ef
#ENV PATH="$PATH:/root/.dotnet/tools"
WORKDIR /src
COPY ["Alereem.WebAPI/Alereem.WebAPI.csproj", "Alereem.WebAPI/"]
COPY ["Alereem.Data/Alereem.Data.csproj", "Alereem.Data/"]
RUN dotnet restore "Alereem.WebAPI/Alereem.WebAPI.csproj"
COPY . .
WORKDIR "/src/Alereem.WebAPI"
RUN dotnet build "Alereem.WebAPI.csproj" -c Release -o /app/build
RUN dotnet ef migrations script -p ../Alereem.Data/Alereem.Data.csproj -s ./Alereem.WebAPI.csproj -o /app/publish/migrations.sql
FROM build AS publish
RUN dotnet publish "Alereem.WebAPI.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
# HOW DO I ADD AN INSTALLATION OF 'SQLCMD.EXE'?
# AND HOW DO I ADD THE INVOCATION OF SQLCMD, ALLOWING
# FOR THE DB CONNECTION STRING TO BE PASSED AT RUN-TIME
# AS AN ENVIRONMENT VARIABLE?
# ...<RUN SQLCMD.EXE MIGRATION HERE>...
# THEN RUN MAIN APPLICATION...
ENTRYPOINT ["dotnet", "Alereem.WebAPI.dll"]
The dockerfile comments I've added at the end represent the problem I have. I've found documentation online suggesting a canned base image I can use that already has sqlcmd
installed, but I assume unfortunately I must keep the base images above that Visual Studio created for my Azure App Service app. Also, according to this SO post, I've learned that running two run-time executables isn't "normal" in a dockerfile.
At this point, I need to do one of the following:
Regarding that last point: Again, I am using github "actions" for my CI/CD. I don't know a way for the github build agent to connect to the target database within my Azure tenant. And even if there were a way for that to happen, I have a requirement to have a complete deployment from simply executing my Azure ARM template. This means I don't have the option of hand-editing the github "actions" file to support the deployment. This is why I'm seemingly left only with the option of having the docker image be responsible for causing the migration...once it is launched at run-time.
Guidance would be appreciated.
My question hovered around an assumption that executing the Entity Framework DB migration needed to occur in the docker container entry point.
However, what I'm ultimately attempting to produce...is an Azure Marketplace "Managed App" deployment bundle. That bundle somehow needs to perform the EF migration. In that context, I now have learned that you can have a deployScript
in an ARM template perform the migration. Here is an example that was designed as an Azure Marketplace deployment. That example assumes that you've pre-generated an EF migration script.sql
that is kept in an artifacts
folder of the marketplace app deployment "bundle". The deployScript
then simply runs an Invoke-Sqlcmd
to run the script.sql
file.
While the above approach works, it has the limitation that the version of my Managed App marketplace offering is not kept current with my code base. So I have adjusted my strategy again, so that I use the ARM deployScript
to call a MigrateDB
endpoint on the Azure App Service which the ARM template is also responsible for deploying. The Azure App Service has a Docker container image that has the script.sql
within it. Using this approach, any customer who deploys my Azure Marketplace Managed App always has my latest code, because the ARM template (in regard to the Azure App Service defined within) is defined as pulling my latest docker image from the Azure Container Registry (ACR).
Now my only downside is that I need a way to keep the Azure App Service offline (including if it is one instance among several running in parallel in a server farm) until the MigrateDB
endpoint is called. I still haven't figured that one out yet, but this still represents a step forward.