无法在 Docker 映像中安装 Windows 功能 NET-Framework-Features

无法在 Docker 映像中安装 Windows 功能 NET-Framework-Features

我正在尝试从使用 .NET 3.5 的本地构建环境中创建 docker 映像。我尝试启用该功能,但出现错误。

这是我为了重现问题而简化的 docker 文件:

FROM mcr.microsoft.com/dotnet/framework/sdk
RUN powershell "Install-WindowsFeature -Name NET-Framework-Features -Verbose"

这是输出:

Sending build context to Docker daemon  72.74MB
Step 1/2 : FROM mcr.microsoft.com/dotnet/framework/sdk
 ---> 88afad8be364
Step 2/2 : RUN powershell "Install-WindowsFeature -Name NET-Framework-Features -Verbose"
 ---> Running in 0a377584126e
VERBOSE: Installation started...
VERBOSE: Continue with installation?
VERBOSE: Prerequisite processing started...
VERBOSE: Prerequisite processing succeeded.
Install-WindowsFeature : The request to add or remove features on the
specified server failed.
Installation of one or more roles, role services, or features failed.
The service cannot be started, either because it is disabled or because it has
no enabled devices associated with it. Error: 0x80070422
At line:1 char:1
+ Install-WindowsFeature -Name NET-Framework-Features -Verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (@{Vhd=; Credent...Name=localh
   ost}:PSObject) [Install-WindowsFeature], Exception
    + FullyQualifiedErrorId : DISMAPI_Error__Failed_To_Enable_Updates,Microsof
   t.Windows.ServerManager.Commands.AddWindowsFeatureCommand

Success Restart Needed Exit Code      Feature Result
------- -------------- ---------      --------------
False   No             Failed         {}
VERBOSE: Installation succeeded.


The command 'powershell -Command $ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue'; powershell "Install-WindowsFeature -Name NET-Framework-Features -Verbose"' returned a non-zero code: 1

构建并运行裸映像而不尝试安装(步骤 2/2)并检查功能显示 3.5 是一种选择:

C:\>powershell "Get-WindowsFeature net*"

Display Name                                            Name                       Install State
------------                                            ----                       -------------
[ ] .NET Framework 3.5 Features                         NET-Framework-Features         Available
    [ ] .NET Framework 3.5 (includes .NET 2.0 and 3.0)  NET-Framework-Core               Removed
    [ ] HTTP Activation                                 NET-HTTP-Activation            Available
    [ ] Non-HTTP Activation                             NET-Non-HTTP-Activ             Available
[X] .NET Framework 4.8 Features                         NET-Framework-45-Fea...        Installed
    [X] .NET Framework 4.8                              NET-Framework-45-Core          Installed
    [ ] ASP.NET 4.8                                     NET-Framework-45-ASPNET        Available
    [X] WCF Services                                    NET-WCF-Services45             Installed
        [ ] HTTP Activation                             NET-WCF-HTTP-Activat...        Available
        [ ] Message Queuing (MSMQ) Activation           NET-WCF-MSMQ-Activat...        Available
        [ ] Named Pipe Activation                       NET-WCF-Pipe-Activat...        Available
        [ ] TCP Activation                              NET-WCF-TCP-Activati...        Available
        [X] TCP Port Sharing                            NET-WCF-TCP-PortShar...        Installed
[ ] Network Virtualization                              NetworkVirtualization            Removed

我尝试启用NET-Framework-45-ASPNET它并且看起来工作正常,但是它再次被列为AvailableNET-Framework-Core被列为Removed

进一步了解如何修复该Removed状态表明,操作系统安装 ISO 中带有 -files 的文件夹.cab应列为-Source。但 cmd 返回的操作系统名称sysinfo显示Microsoft没有相应 ISO 的纯文本。我尝试下载Windows Server 2019 ISO并将其source/sxs用作-Source,希望获得最佳效果,但却得到相同的错误结果和输出(新的 Dockerfile):

FROM mcr.microsoft.com/dotnet/framework/sdk
# Copy sources/sxs from Windows Server 2016 ISO
COPY sources\sxs2016 C:\sources\sxs
RUN powershell "Install-WindowsFeature NET-Framework-Features -Source C:\sources\sxs -Verbose"

有什么想法可以使它工作吗?

答案1

发生此错误的原因是它试图使用 Windows 更新服务,而该服务在基础容器中已被禁用。即使直接向安装程序提供带有源的本地路径,也会出现这种情况。

使原始 Dockerfile 正常工作的最简单的更改是在安装之前启用 Windows 更新服务:

FROM mcr.microsoft.com/dotnet/framework/sdk
RUN powershell "Set-Service -Name wuauserv -StartupType Manual; Install-WindowsFeature -Name NET-Framework-Features -Verbose"

相同的方法适用于已将 .NET Framework 3.5 源复制到本地的 Powershell 脚本:

Set-Service -Name wuauserv -StartupType "Manual"
write-output "Installing Windows Feature .net framework 35"
Install-WindowsFeature -Name NET-Framework-Features -Source C:\NET-Framework35-Features -Verbose

与微软在官方镜像中使用的相比,这可能仍然是更好的选择,因为它更简单、更易于维护。他们直接引用特定版本并根据需要进行更新。

答案2

我在 Dockerfile 中找到了解决方案mcr.microsoft.com/dotnet/framework/runtime:3.5

# escape=`

FROM mcr.microsoft.com/windows/servercore:1903

# Install .NET Fx 3.5
RUN curl -fSLo microsoft-windows-netfx3.zip https://dotnetbinaries.blob.core.windows.net/dockerassets/microsoft-windows-netfx3-1903.zip `
    && tar -zxf microsoft-windows-netfx3.zip `
    && del /F /Q microsoft-windows-netfx3.zip `
    && DISM /Online /Quiet /Add-Package /PackagePath:.\microsoft-windows-netfx3-ondemand-package~31bf3856ad364e35~amd64~~.cab `
    && del microsoft-windows-netfx3-ondemand-package~31bf3856ad364e35~amd64~~.cab `
    && powershell Remove-Item -Force -Recurse ${Env:TEMP}\*

# Apply latest patch
RUN curl -fSLo patch.msu http://download.windowsupdate.com/d/msdownload/update/software/updt/2019/09/windows10.0-kb4515871-x64_03a6aec54b0ca2fc40efcff09a810064f5d2ae60.msu `
    && mkdir patch `
    && expand patch.msu patch -F:* `
    && del /F /Q patch.msu `
    && DISM /Online /Quiet /Add-Package /PackagePath:C:\patch\Windows10.0-kb4515871-x64.cab `
    && rmdir /S /Q patch

# ngen .NET Fx
ENV COMPLUS_NGenProtectedProcess_FeatureEnabled 0
RUN \Windows\Microsoft.NET\Framework64\v2.0.50727\ngen uninstall "Microsoft.Tpm.Commands, Version=10.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=amd64" `
    && \Windows\Microsoft.NET\Framework64\v2.0.50727\ngen update `
    && \Windows\Microsoft.NET\Framework\v2.0.50727\ngen update

与我尝试过的不同之处似乎在于:

  • 从“microsoft docker assets”下载 netfx3-on-demand-package。
  • 使用 DISM 安装它并指出包路径而不是源路径。

Dockerfile 还应用了某种补丁并更新了 ngen。(不确定这是否相关,但老实说,我太害怕更改这个巫术配方了。)

相关内容