Adding optional font packages to Windows containers

Published Jun 29 2022 03:00 AM 1,616 Views

Customer feedback is the main driver for the Windows container team when planning new features and improvements to the platform. Since we launched containers in Windows Server 2016, customers have told us how a slim container image impacts the overall performance. With that in mind, we removed as much of the base container images as we could, including components such as fonts – which in most cases is not relevant.

Since then, we also heard your feedback about scenarios that do need these fonts back for applications to properly work. Today we’ll cover how you can add fonts back to Windows containers on the Server Core base container image in a way that is supported for both Windows Server 2019 and 2022.

 

Building the Container

When we removed the fonts from the Server Core base container image, we also removed the feature that installs new fonts. As you build your container image, you’ll have to incorporate the steps below to add the necessary feature back to Windows containers.

First, you’ll need an up-to-date Windows Server 2019 or 2022 host or VM as a container host. Putting removed features back requires up-to-date media. There are a few ways to acquire up-to-date install media, but the simplest is just to take a Windows Server 2019 or 2022 VM and let Windows Update bring it up to date.

Next, you need to prepare your container host.  You can use the instructions in our documentation page. You’ll also need to share the %windir%\WinSxS directory. For this example, we created a local user with a randomly-generated password (represented as <password>):

 

For Command Prompt:

 

net user ShareUser <password> /ADD
net share WinSxS=%windir%\WinSxS /grant:ShareUser,READ

 

For PowerShell:

 

net user ShareUser ‘<password>’ /ADD
net share WinSxS=${env:windir}\WinSxS /grant:ShareUser,READ

 

 

Next, create a file called InstallFonts.cmd and add the following content to it:

 

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%
if errorlevel 1 goto :eof
 
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-MinConsoleFonts /Source:O:\ /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-Support /Source:O:\ /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-BitmapFonts /Source:O:\ /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-TrueType /Source:O:\ /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-UAPFonts /Source:O:\ /LimitAccess

 

 

Now you can add the context to your dockerfile. Here’s an example:

 

FROM mcr.microsoft.com/windows/servercore:ltsc2022
ARG SHARE_PW=
WORKDIR /install
COPY InstallFonts.cmd .
RUN InstallFonts.cmd

 

 

With a dockerfile in place, you can build and tag your container image using:

 

docker build -t <newname:tag> --build-arg SHARE_PW=<password> .

 

 

Yes, you will end up with the SHARE_PW in the build trace, but if you set it up as a randomly-generated string for each build, you’re not leaking a real secret. Furthermore, once the build is complete you can clean up the share and user with:

 

net share WinSxS /delete
net user ShareUser /delete

 

 

Running the workload

Due to a limitation in how Server Core containers handle fonts, you do need to specifically tell Windows about the newly available fonts in the container.  A simple PowerShell script will do the job.  This must be run after the container is started and prior to running your workload.  We suggest calling this 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 hopes to remove this limitation in a future version of Windows, but the script is required for current releases of Windows Server 2019 and 2022. Once you have built the container as described above and run this script inside the container, all of the fonts usually present on Windows Server Core will be available to your containerized workload.

 

We cannot overstate how valuable your feedback is to us. Please continue sending your suggestions via our GitHub page!

2 Comments
Version history
Last update:
‎Jun 28 2022 10:21 AM
Updated by: