c# - 如何在Docker中运行.NET Core 3.1.3 x86 App

标签 c# docker .net-core x86 dockerfile

我有一个构建为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平台构建的,生成的图像看起来不错。

我根据应用程序镜像和CMD创建了一个容器,并确认所有文件都在预期的位置,甚至从命令行运行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运行的问题吗?

最佳答案

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

  • 基于mcr.microsoft.com/windows/servercore:ltsc2019构建自定义镜像,该镜像添加了C++ Redistributable 2015 x86;
  • 基于1.创建的另一个图像,其中添加了.NET Core x86 SDK,以及;
  • 基于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"]
    

    关于c# - 如何在Docker中运行.NET Core 3.1.3 x86 App,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61491430/

    相关文章:

    Mysql2::Error:排序内存不足,考虑使用 docker-compose.yml 增加服务器排序缓冲区大小

    mysql - 如何在 docker compose 上修复 'The server requested authentication method unknown to the client [caching_sha2_password]'?

    c# - 提取视频的第 5 帧并使用 ffmpeg C# 合并到视频中

    C# 创建一个由多个类使用的枚举的最佳方法是什么?

    c# - C# 中的 Terras 猜想

    docker-engine 到 docker-compose 到 docker compose 文件关系

    linux - Ubuntu 上的 Microsoft.AspNetCore.Identity.UI 3.1 的 ASP.NET Core 3.1 问题

    c# - 简单注入(inject)器 - 在运行时根据指定的泛型类型注入(inject)服务

    c# - 将一个 XML 文档转换为另一个 XML 文档

    c# - 装饰器装饰基本命令