.netwindowsdockerfiledocker-for-windowsvcredist

How to install Visual C++ Redistributable in ASP.NET Core Runtime Docker images


I have a project which requires the Visual C++ Redistributable packages installed on-top of the standard ASP.NET Core and .NET runtimes and libraries in the Microsoft ASP.NET Core Runtime Docker image.

I've tried doing this by expanding the example Dockerfile supplied in the Microsoft Lean .NET Containerize a .NET app tutorial to additionally install the Visual C++ Redistributables with VcRedist.

The resultant Dockerfile looks like the following:

FROM mcr.microsoft.com/dotnet/sdk:8.0-nanoserver-1809 AS build-env
WORKDIR /App

# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
# Build and publish a release
RUN dotnet publish -c Release -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0-windowsservercore-ltsc2022
WORKDIR /App
COPY --from=build-env /App/out .
COPY --from=build-env /App/InstallVCPPRedist.ps1 .
SHELL ["powershell", "command" ]
RUN .\InstallVCPPRedist.ps1
CMD [ "ASPApp.exe" ]

Where the installation of the Visual C++ Redistrutable packages via VcRedist is carried out in a PowerShell script copied to the instance during the build process, InstallVCPPRedist.ps1, as follows:

try { 
    Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
    Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted
    Install-Module -Name VcRedist
    Import-Module -Name VcRedist
    mkdir C:\Temp
    mkdir C:\Temp\VcRedist
    $VcRedists = Save-VcRedist -VcList (Get-VcList) -Path "C:\Temp\VcRedist"
    Install-VcRedist  -VcList $VcRedists
} catch {
    Write-Error "An error occurred: $_"
    exit 1
}
exit 0

When I run docker build it looks like the build process completes without issue, as below:

docker build -t docker-asp-vcpp-redist-image .
Sending build context to Docker daemon  38.69MB
Step 1/12 : FROM mcr.microsoft.com/dotnet/sdk:8.0-nanoserver-1809 AS build-env
 ---> 86c24fcbbcf6
Step 2/12 : WORKDIR /App
 ---> Using cache
 ---> fd9b6023d30a
Step 3/12 : COPY . ./
 ---> d90f3407e7b1
Step 4/12 : RUN dotnet restore
 ---> Running in 035fb5e7392a
  Determining projects to restore...
  Restored C:\App\Project.csproj (in 8.38 sec).
 ---> Removed intermediate container 035fb5e7392a
 ---> 5e17e340c728
Step 5/12 : RUN dotnet publish -c Release -o out
 ---> Running in a92c3d301887
MSBuild version 17.9.8+b34f75857 for .NET
  Determining projects to restore...
  All projects are up-to-date for restore.
C:\App\Program.cs(17,1): warning CS4014: Because this call is not awaited, execution of     the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. [C:\App\Project.csproj]
  Project-> C:\App\bin\Release\net6.0\Project.dll
  Project -> C:\App\out\
 ---> Removed intermediate container a92c3d301887
 ---> e5c314cf35d2
Step 6/12 : FROM mcr.microsoft.com/dotnet/aspnet:6.0-windowsservercore-ltsc2022
 ---> 2ff1b8e8da5c
Step 7/12 : WORKDIR /App
 ---> Using cache
 ---> 417102a4468a
Step 8/12 : COPY --from=build-env /App/out .
 ---> Using cache
 ---> 034f52b6ffd6
Step 9/12 : COPY --from=build-env /App/InstallVCPPRedist.ps1 .
 ---> Using cache
 ---> 0b3bc1cbbf71
Step 10/12 : SHELL [ "powershell", "command" ]
 ---> Using cache
 ---> 646e586e2160
Step 11/12 : RUN .\InstallVCPPRedist.ps1
 ---> Running in bd8ae54f6d8d
 ---> Removed intermediate container bd8ae54f6d8d
 ---> 1c56dcb78841
Step 12/12 : CMD [ "Project.exe" ]
 ---> Running in fca2ef892d35
 ---> Removed intermediate container fca2ef892d35
 ---> 0c8694e5d0ba
Successfully built 0c8694e5d0ba
Successfully tagged docker-asp-vcpp-redist-image:latest

But for some reason the Visual C++ Redistributes still don't seem to be present on the machine.

What am I missing here?

For context, I've tried manually running .\InstallVCPPRedist.ps1 in a docker container launched from my built image and it seems to complete without issue and result in the VC++ Redistributable being installed correctly, so I'm not sure what's causing it not to work when running from the Dockerfile during the build.


Solution

  • It would seem that the issue was caused by the way that PowerShell executes scripts by default.

    As far as I understand, without explicitly telling it otherwise, PowerShell doesn't wait for the whole script to return before continuing.

    Within the Dockerfile, this meant that docker was happy to continue with the remainder of the steps after:

    RUN .\InstallVCPPRedist.ps1
    

    Before all the steps in the PowerShell script have actually finished executing.

    As outlined in the following Stack Overflow answer: https://stackoverflow.com/a/48804143/7647013, telling PowerShell to execute with the $ProgressPreference='SilentlyContinue' and $ErrorActionPreference = 'Stop' options set forces PowerShell to only return that it's done running the .\InstallVCPPRedist.ps1 script when it's progressed through the whole script or failed.

    Changing the:

    SHELL ["powershell", "command" ]

    Line to

    SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

    In my Dockerfile allowed docker build to successfully create a version of the ASP.NET Core Runtime image for my project with the Visual C++ Redistributeables present.