Solving the Missing Font Files Issue in .NET Docker Containers
Previously, my DevOps colleagues mentioned that I needed to strengthen my CI/CD and environment-related skills. I thought about it, and realized my talent is limited, so there isn't much room for improvement in continuing to research .NET. As it turns out, I've been researching WSL lately, but I got stuck due to permission issues and haven't managed to write a single note in almost a month. Instead, I ended up writing a few .NET notes in my spare time. But after some thought, I remembered I had handled a Docker issue before, so I could barely scrape together a note to prove that I am actually doing some research XD.
Font Issues in Docker Containers
In Linux systems, font files are usually located under the /usr/share/fonts path. As shown in the image below, you can see a truetype folder inside, which stores the font files.

In a Linux container created using a Dockerfile, you might find that the fonts folder is missing under the /usr/share/ path. For example, the Dockerfile generated by creating a project in Visual Studio:
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["TestFont6/TestFont6.csproj", "TestFont6/"]
RUN dotnet restore "./TestFont6/TestFont6.csproj"
COPY . .
WORKDIR "/src/TestFont6"
RUN dotnet build "./TestFont6.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./TestFont6.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TestFont6.dll"]When the container is running, you can see that the fonts folder is missing.

This is likely because mcr.microsoft.com/dotnet/aspnet:6.0 uses a more lightweight Linux base image (such as Debian, Alpine, etc.). These images usually contain only the most basic system packages and do not pre-install many common font packages to reduce size.
To solve this problem, you can make the following adjustments to the Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
RUN sed -i'.bak' 's/$/ contrib/' /etc/apt/sources.list
# Update package list and install ttf-mscorefonts-installer and fontconfig packages
RUN apt-get update; apt-get install -y ttf-mscorefonts-installer fontconfig
# Use the fc-cache command to refresh the font cache and optimize font loading speed
# -f Force refresh of the cache
# -v Display detailed information
RUN fc-cache -f -v
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["TestFont6/TestFont6.csproj", "TestFont6/"]
RUN dotnet restore "./TestFont6/TestFont6.csproj"
COPY . .
WORKDIR "/src/TestFont6"
RUN dotnet build "./TestFont6.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./TestFont6.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TestFont6.dll"]This way, the truetype folder will appear under the /usr/share/fonts path.
Handling .NET 8 Dockerfile Issues
When using a .NET 8 Dockerfile, the method above will encounter the following error:
#5 ERROR: process "/bin/sh -c sed -i'.bak' 's/$/ contrib/' /etc/apt/sources.list" did not complete successfully: exit code: 21Checking the /etc/apt/ path based on the error message, I found that only the sources.list.d folder exists, and the sources.list file is missing.
According to the article "Sources.list file is missing in debian12", the mcr.microsoft.com/dotnet/sdk:6.0 image uses Debian 11, while mcr.microsoft.com/dotnet/sdk:8.0 has switched to Debian 12. In Debian 12, package management has been changed to use the /etc/apt/sources.list.d/debian.sources file.
Here is the adjustment for the .NET 8 Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
# Find the line matching Components: main in the /etc/apt/sources.list.d/debian.sources file and append contrib to the end of that line.
RUN sed -i 's/^Components: main$/& contrib/' /etc/apt/sources.list.d/debian.sources
# Update package list and install ttf-mscorefonts-installer and fontconfig packages
RUN apt-get update; apt-get install -y ttf-mscorefonts-installer fontconfig
# Use the fc-cache command to refresh the font cache and optimize font loading speed
# -f Force refresh of the cache
# -v Display detailed information
RUN fc-cache -f -v
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["TestFont/TestFont.csproj", "TestFont/"]
RUN dotnet restore "./TestFont/TestFont.csproj"
COPY . .
WORKDIR "/src/TestFont"
RUN dotnet build "./TestFont.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./TestFont.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "TestFont.dll"]This way, you can also see the truetype folder under the /usr/share/fonts path.
WARNING
The comments in the Dockerfile were generated by ChatGPT. Although I verified them via Google, I am not very familiar with environment commands, so I cannot guarantee they are 100% correct.
Change Log
- 2024-08-09 Initial version created.
