为了提高 Windows 容器的整体性能,我们删除了 Windows 基本容器映像中的许多组件(包括字体等组件),这些组件在大多数情况下都是无关紧要的。 不过,在某些情况下,应用程序可能需要使用这些字体才能正常工作。
准备环境
当我们从 Server Core 基本容器映像中删除字体时,我们也删除了安装新字体的功能。 在生成容器映像时,必须结合以下步骤将必要的功能添加回 Windows 容器。 首先,需要一台最新的 Windows Server 2019 或 2022 主机或 VM 作为容器主机。 还原已删除的功能需要使用最新的媒体。
注意
有一些方法可以获取最新的安装媒体,但最简单的方法是使用 Windows Server 2019 或 2022 VM,让 Windows 更新将其更新为最新版本。 还需要原始 Windows Server 2019 或 2022 RTM 媒体的 ISO。 该映像可通过 Visual Studio 订阅或批量许可证服务中心获取。
要准备好环境,你需要一台经过正确配置的 Windows 容器主机,并共享 %windir%\WinSxS 目录。 还必须共享 %windir%\WinSxS 目录。 在本例中,我们创建了一个本地用户,密码是随机生成的:
对于命令提示符:
net user ShareUser <password> /ADD
net share WinSxS=%windir%\WinSxS /grant:ShareUser,READ
对于 PowerShell:
net user ShareUser ‘<password>’ /ADD
net share WinSxS=${env:windir}\WinSxS /grant:ShareUser,READ
接下来,装载 RTM 媒体。
对于命令提示符:
set imagePath=<path to RTM ISO>
powershell Mount-DiskImage -ImagePath %imagePath%
set driveLetter=<drive letter of the mounted ISO>
set repairMountDir=%SystemDrive%\repair
mkdir repairMountDir
dism /mount-image /imagefile:"%driveLetter%\sources\install.wim" /index:1 /mountdir:%repairMountDir%
net share RTM=%repairMountDir% /grant:ShareUser,READ
对于 PowerShell:
$imagePath = <path to RTM ISO>
Mount-DiskImage -ImagePath $imagePath
# Find the drive letter of the mounted ISO
$driveLetter = <drive letter of mounted ISO>
$repairMountDir = "${env:systemdrive}\repair"
mkdir $repairMountDir
dism /mount-image /imagefile:"$driveLetter\sources\install.wim" /index:1 /mountdir:$repairMountDir
net share RTM=$repairMountDir /grant:ShareUser,READ
注意
确保在装载 RTM 媒体时指定映像索引 1。
接下来,创建一个名为 InstallFonts.cmd 的文件,并向其添加以下内容:
REM Connect to the WinSxS share on the container host
for /f "tokens=3 delims=: " %%g in ('netsh interface ip show address ^| findstr /c:"Default Gateway"') do set GATEWAY=%%g
net use o: \\%GATEWAY%\WinSxS /user:ShareUser %SHARE_PW%
net use r: \\%GATEWAY%\RTM /user:ShareUser %SHARE_PW%if errorlevel 1 goto :eof
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-MinConsoleFonts /Source:O:\ /Source:R:\ /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-Support /Source:O:\ /Source:R:\ /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-BitmapFonts /Source:O:\ /Source:R:\ /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-TrueType /Source:O:\ /Source:R:\ /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-UAPFonts /Source:O:\ /Source:R:\ /LimitAccess
现在可以将上下文添加到 dockerfile。 下面是一个示例:
FROM mcr.microsoft.com/windows/servercore:ltsc2022
ARG SHARE_PW=
WORKDIR /install
COPY InstallFonts.cmd .
RUN InstallFonts.cmd
有了 dockerfile,可以使用以下命令生成并标记容器映像:
docker build -t <newname:tag> --build-arg SHARE_PW=<password> .
可以在生成跟踪中获得 SHARE_PW,但如果针对每次生成设置为随机生成的字符串,则不会泄露真实机密。 此外,生成完成后,可以使用以下命令清理共享和用户:
net share WinSxS /delete
net user ShareUser /delete
运行工作负载
由于 Server Core 容器在处理字体方面存在限制,你确实需要特别告知 Windows 容器中新的可用字体。 必须在容器启动后、运行工作负载之前运行 PowerShell 脚本。 建议调用此 LoadFonts.ps1:
$fontCSharpCode = @'
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
namespace FontResource
{
public class AddRemoveFonts
{
[DllImport("gdi32.dll")]
static extern int AddFontResource(string lpFilename);
public static int AddFont(string fontFilePath) {
try
{
return AddFontResource(fontFilePath);
}
catch
{
return 0;
}
}
}
}
'@
Add-Type $fontCSharpCode
foreach($font in $(gci C:\Windows\Fonts))
{
Write-Output "Loading $($font.FullName)"
[FontResource.AddRemoveFonts]::AddFont($font.FullName) | Out-Null
}
Microsoft 希望在未来的 Windows 版本中取消这一限制,但当前的 Windows Server 2019 和 2022 版本需要使用该脚本。 按照此处所述生成容器并在容器内运行此脚本后,Windows Server Core 上的所有字体都可用于容器化工作负载。
添加字体时出现的问题
如果在 Server Core 容器映像上启用字体时遇到问题,请在 GitHub 存储库的“问题”部分告知我们。