【问题标题】:How to run a .NET Core 3.1.3 x86 App in Docker如何在 Docker 中运行 .NET Core 3.1.3 x86 应用程序
【发布时间】:2020-04-28 23:03:37
【问题描述】:

我有一个构建为 x86 的 .NET Core 3.1.3 Web API 项目。它必须是 x86,因为它通过 dllimport 使用 x86 C++ DLL。在 Docker 之外,应用程序按预期运行。但是,一旦我添加了 Windows Docker 支持,它就会立即失败。我从 SO 研究中相信它失败了,因为 Microsoft 没有为 .NET Core 提供任何 x86 基础映像。默认的 Windows Docker 基础镜像当前是 mcr.microsoft.com/dotnet/core/aspnet:3.1-nanoserver-1903。

我尝试使用 mcr.microsoft.com/windows/servercore:1909 作为基础映像,但随后收到错误消息“无法启动程序:'C:\Program Files\dotnet\dotnet.exe。 '" 我认为这是因为此 exe 在所使用的基础映像中不存在。而且,对于 x86,大概需要“C:\Program Files (x86)\dotnet\dotnet.exe”。

我当前的 Dockerfile 是:

FROM mcr.microsoft.com/windows/servercore:1909 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/windows/servercore:1909 AS build
WORKDIR /src
COPY ["WAPTCoreWebService/WAPTCoreWebService.csproj", "WAPTCoreWebService/"]
RUN dotnet restore "WAPTCoreWebService/WAPTCoreWebService.csproj"
COPY . .
WORKDIR "/src/WAPTCoreWebService"
RUN dotnet build "WAPTCoreWebService.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "WAPTCoreWebService.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WAPTCoreWebService.dll"]

我是否正确解释了这个错误。如果不是,那是什么意思?如果是这样,如何添加支持以在此映像中构建我的 .NET Core 应用的 x86 版本?我需要以某种方式下载并运行 dotnet-runtime-3.1.3-win-x86.exe 吗?如果有,怎么做?

更新 2020 年 4 月 29 日

根据 Matt Thalman 的回答,我构建了一个自定义映像以包含 x86 版本的 .NET Core SDK。 Docker文件是:

# escape=`

# Installer image
FROM mcr.microsoft.com/windows/servercore:1909 AS installer

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

# Retrieve .NET Core SDK
RUN $dotnet_sdk_version = '3.1.201'; `
    Invoke-WebRequest -OutFile dotnet.zip https://dotnetcli.azureedge.net/dotnet/Sdk/$dotnet_sdk_version/dotnet-sdk-$dotnet_sdk_version-win-x86.zip; `
    $dotnet_sha512 = '48aa1afaf7a52effb367bbb14a66e2c3bf8da468025795daf0fa0d18e3b9650ba3bd23800c9965a4d4ec1d891afecbce51b2487730f1b0d6040ee7cb73a15ec6'; `
    if ((Get-FileHash dotnet.zip -Algorithm sha512).Hash -ne $dotnet_sha512) { `
        Write-Host 'CHECKSUM VERIFICATION FAILED!'; `
        exit 1; `
    }; `
    `
    Expand-Archive dotnet.zip -DestinationPath dotnet; `
    Remove-Item -Force dotnet.zip

# Install PowerShell global tool
RUN $powershell_version = '7.0.0'; `
    Invoke-WebRequest -OutFile PowerShell.Windows.x64.$powershell_version.nupkg https://pwshtool.blob.core.windows.net/tool/$powershell_version/PowerShell.Windows.x64.$powershell_version.nupkg; `
    $powershell_sha512 = '1980da63a4f6017235e7af810bfda66be8fa53d0475d147a8219a36c76a903af99adb6cd5309e3dadc610389ae3525bca1ca2d30e7a991640e924334fd4e4638'; `
    if ((Get-FileHash PowerShell.Windows.x64.$powershell_version.nupkg -Algorithm sha512).Hash -ne $powershell_sha512) { `
        Write-Host 'CHECKSUM VERIFICATION FAILED!'; `
        exit 1; `
    }; `
    `
    \dotnet\dotnet tool install --add-source . --tool-path \powershell --version $powershell_version PowerShell.Windows.x64; `
    \dotnet\dotnet nuget locals all --clear; `
    Remove-Item -Force PowerShell.Windows.x64.$powershell_version.nupkg; `
    Remove-Item -Path \powershell\.store\powershell.windows.x64\$powershell_version\powershell.windows.x64\$powershell_version\powershell.windows.x64.$powershell_version.nupkg -Force

# SDK image
FROM mcr.microsoft.com/windows/servercore:1909

ENV `
    # Enable detection of running in a container
    DOTNET_RUNNING_IN_CONTAINER=true `
    # Enable correct mode for dotnet watch (only mode supported in a container)
    DOTNET_USE_POLLING_FILE_WATCHER=true `
    # Skip extraction of XML docs - generally not useful within an image/container - helps performance
    NUGET_XMLDOC_MODE=skip `
    # PowerShell telemetry for docker image usage
    POWERSHELL_DISTRIBUTION_CHANNEL=PSDocker-DotnetCoreSDK-NanoServer-1909

# In order to set system PATH, ContainerAdministrator must be used
USER ContainerAdministrator
RUN setx /M PATH "%PATH%;C:\Program Files (x86)\dotnet;C:\Program Files\powershell"
USER ContainerUser

COPY --from=installer ["/dotnet", "/Program Files (x86)/dotnet"]

COPY --from=installer ["/powershell", "/Program Files/powershell"]

# Trigger first run experience by running arbitrary cmd
RUN dotnet help

这构建得很好,最后的dotnet help 命令正确执行。

我更改了我的应用程序 Dockerfile 以使用此自定义映像作为基础映像,并且构建也很好。当我从 Visual Studio 2019 运行此程序时,我得到与上面相同的错误(“无法启动程序:'C:\Program Files\dotnet\dotnet.exe.'”)。为什么VS仍在尝试使用x64入口点。该项目是针对 x86 平台构建的,生成的图像看起来不错。

我基于应用程序映像创建了一个容器,并将CMDed 到其中并确认所有文件都在预期的位置,甚至从命令行运行dotnet applicationName.dll 并且应用程序启动正常。

当我尝试从 Visual Studio 运行时,它会尝试通过以下方式运行图像:

docker run -dt -v "C:\Users\Valued Customer\onecoremsvsmon\16.5.0102.0:C:\remote_debugger:ro" -v "C:\Users\Valued Customer\AppData\Roaming\Microsoft\UserSecrets:C:\Users\ContainerUser\AppData\Roaming\Microsoft\UserSecrets:ro" -v "C:\Users\Valued Customer\AppData\Roaming\ASP.NET\Https:C:\Users\ContainerUser\AppData\Roaming\ASP.NET\Https:ro" -e "ASPNETCORE_URLS=https://+:443;http://+:80" -e "ASPNETCORE_ENVIRONMENT=Development" -e "ASPNETCORE_LOGGING__CONSOLE__DISABLECOLORS=true" -P --name WAPTCoreWebService_1 --entrypoint C:\remote_debugger\x64\msvsmon.exe waptcorewebservice /noauth /anyuser /silent /nostatus /noclrwarn /nosecuritywarn /nofirewallwarn /nowowwarn /fallbackloadremotemanagedpdbs /timeout:2147483646 /LogDebuggeeOutputToStdOut

入口点指向 x64 应用程序 (msvsmon.exe)。这可能是从 VS 运行的问题吗?

【问题讨论】:

  • 我根本无法使用此图像运行 Invoke-WebRequest (mcr.microsoft.com/windows/servercore:1909)。它总是以“无法解析远程名称”而失败。然而,这个图像(mcr.microsoft.com/dotnet/framework/runtime:4.8)更好,但我无法在那里设置任何 ENV 变量。我是否错过了上述解决方案的任何更新?

标签: c# docker .net-core x86 dockerfile


【解决方案1】:

这是一个不完美的答案,但我确实设法获得了一个 x86 .NET Core Web API,它依赖于一个 VC++ x86 DLL,并在 Azure Kubernetes 服务上运行。基本上我分为三个阶段:

  1. 基于 mcr.microsoft.com/windows/servercore:ltsc2019 构建自定义映像,添加 C++ Redistributable 2015 x86;
  2. 另一个镜像是基于 1. 创建的,添加了 .NET Core x86 SDK,并且;
  3. 最终图像是基于 2. 创建的,它添加了我的应用程序代码。

下面包含三个 Dockerfile。接下来,我将把它整合到一个 Dockerfile 中。

添加 C++ Redist x86:waptx86custom

请注意,我从自己的 Azure 帐户中提取了 redist exe 的副本,但您也可以将其包含在与 Dockerfile 相同的文件夹中,然后从那里添加。

FROM mcr.microsoft.com/windows/servercore:ltsc2019 AS base

# Installing Microsoft Visual C++ 2015 x86 Redistributable.
ADD https://lqsts.blob.core.windows.net/temp/vc_redist_2015_3.x86.exe C:/vc_redist.x86.exe
RUN C:\vc_redist.x86.exe /install /norestart /quiet /log vc_log.txt

添加 .NET Core SDK x86:waptx86corecustom

# escape=`

# Installer image
FROM acswebwapt.azurecr.io/waptx86custom AS installer

# Apply latest patch
RUN curl -fSLo patch.msu http://download.windowsupdate.com/c/msdownload/update/software/updt/2020/01/windows10.0-kb4534119-x64_a2dce2c83c58ea57145e9069f403d4a5d4f98713.msu `
    && mkdir patch `
    && expand patch.msu patch -F:* `
    && del /F /Q patch.msu `
    && DISM /Online /Quiet /Add-Package /PackagePath:C:\patch\windows10.0-kb4534119-x64.cab `
    && rmdir /S /Q patch

ENV COMPLUS_NGenProtectedProcess_FeatureEnabled 0

RUN \Windows\Microsoft.NET\Framework64\v4.0.30319\ngen uninstall "Microsoft.Tpm.Commands, Version=10.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=amd64" `
    && \Windows\Microsoft.NET\Framework64\v4.0.30319\ngen update `
    && \Windows\Microsoft.NET\Framework\v4.0.30319\ngen update

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

# Retrieve .NET Core SDK
RUN $dotnet_sdk_version = '3.1.201'; `
    Invoke-WebRequest -OutFile dotnet.zip https://dotnetcli.azureedge.net/dotnet/Sdk/$dotnet_sdk_version/dotnet-sdk-$dotnet_sdk_version-win-x86.zip; `
    $dotnet_sha512 = '48aa1afaf7a52effb367bbb14a66e2c3bf8da468025795daf0fa0d18e3b9650ba3bd23800c9965a4d4ec1d891afecbce51b2487730f1b0d6040ee7cb73a15ec6'; `
    if ((Get-FileHash dotnet.zip -Algorithm sha512).Hash -ne $dotnet_sha512) { `
        Write-Host 'CHECKSUM VERIFICATION FAILED!'; `
        exit 1; `
    }; `
    `
    Expand-Archive dotnet.zip -DestinationPath dotnet; `
    Remove-Item -Force dotnet.zip

# Install PowerShell global tool
RUN $powershell_version = '7.0.0'; `
    Invoke-WebRequest -OutFile PowerShell.Windows.x64.$powershell_version.nupkg https://pwshtool.blob.core.windows.net/tool/$powershell_version/PowerShell.Windows.x64.$powershell_version.nupkg; `
    $powershell_sha512 = '1980da63a4f6017235e7af810bfda66be8fa53d0475d147a8219a36c76a903af99adb6cd5309e3dadc610389ae3525bca1ca2d30e7a991640e924334fd4e4638'; `
    if ((Get-FileHash PowerShell.Windows.x64.$powershell_version.nupkg -Algorithm sha512).Hash -ne $powershell_sha512) { `
        Write-Host 'CHECKSUM VERIFICATION FAILED!'; `
        exit 1; `
    }; `
    `   
    \dotnet\dotnet tool install --add-source . --tool-path \powershell --version $powershell_version PowerShell.Windows.x64; `
    \dotnet\dotnet nuget locals all --clear; `
    Remove-Item -Force PowerShell.Windows.x64.$powershell_version.nupkg; `
    Remove-Item -Path \powershell\.store\powershell.windows.x64\$powershell_version\powershell.windows.x64\$powershell_version\powershell.windows.x64.$powershell_version.nupkg -Force


# SDK image
FROM acswebwapt.azurecr.io/waptx86custom

ENV `
    # Enable detection of running in a container
    DOTNET_RUNNING_IN_CONTAINER=true `
    ASPNETCORE_URLS=http://+:443;http://+:80 `
    # Enable correct mode for dotnet watch (only mode supported in a container)
    DOTNET_USE_POLLING_FILE_WATCHER=true `
    # Skip extraction of XML docs - generally not useful within an image/container - helps performance
    NUGET_XMLDOC_MODE=skip `
    # PowerShell telemetry for docker image usage
    POWERSHELL_DISTRIBUTION_CHANNEL=PSDocker-DotnetCoreSDK-NanoServer-1909

# In order to set system PATH, ContainerAdministrator must be used
USER ContainerAdministrator
RUN setx /M PATH "%PATH%;C:\Program Files (x86)\dotnet;C:\Program Files\powershell"
USER ContainerUser

COPY --from=installer ["/dotnet", "/Program Files (x86)/dotnet"]

COPY --from=installer ["/powershell", "/Program Files/powershell"]

# Trigger first run experience by running arbitrary cmd
RUN dotnet help

添加应用程序

FROM acswebwapt.azurecr.io/waptx86corecustom AS base

WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM acswebwapt.azurecr.io/waptx86corecustom AS build

WORKDIR /src
COPY ["WAPTCoreWebService/WAPTCoreWebService.csproj", "WAPTCoreWebService/"]
RUN dotnet restore "WAPTCoreWebService/WAPTCoreWebService.csproj"
COPY . .
WORKDIR "/src/WAPTCoreWebService"
RUN dotnet build "WAPTCoreWebService.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "WAPTCoreWebService.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WAPTCoreWebService.dll"]

【讨论】:

    【解决方案2】:

    是的,您的解释是正确的。 Windows 基础映像未安装 .NET Core。这里有关于如何在 Docker 映像中安装 .NET Core 的文档:https://github.com/dotnet/dotnet-docker/blob/master/samples/snippets/installing-dotnet.md

    【讨论】:

    • 谢谢马特。根据链接,我创建了一个似乎可以正常工作的自定义基础映像(请参阅原始问题中的更新),但我仍然收到“无法启动程序:'C:\Program Files\dotnet\dotnet.exe”。从 VS 运行时。有什么想法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 2020-03-29
    • 2019-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多