.NET includes various globalization capabilities, including support for processing natural language text, calendars, currency, and time zones. The .NET implementations for these capabilities comes primarily from operating system libraries, such as International Components for Unicode (ICU) and tzdata. In some cases, these libraries and their accompanying databases are always available and in other cases it is desired that they be absent because they may be considered prohibitively large.
The .NET team has various policies for making these libraries available in containers and for configuring the .NET product to use them (or not).
The globalapp samples demonstrates using globalization capabilities in containers.
In many scenarios, globalization support with ICU is required, for example, to correctly sort a list of strings (particularly characters outside the ASCII range). Other applications may not be oriented around natural language or other global concepts, and would prefer to optimize for container size. .NET container images have been curated to offer options for both of these scenarios.
.NET container images that include ICU:
- Alpine
sdk
images - Debian images
- Ubuntu images
- All
extra
variant images
.NET container images that do not include ICU:
- Alpine
aspnet
,monitor
,runtime
,runtime-deps
images - Ubuntu chiseled images
Images that do not include ICU enable Globalization Invariant Mode, which provides more basic globalization behaviors in absence of using ICU.
Some users want to add ICU to one of the image types that doesn't include it. It is counter-productive to remove ICU from an image that already includes it; it doesn't actually reduce the size of the image since it's stored in an earlier layer which cannot be changed.
When using Microsoft.Data.SqlClient
or Entity Framework Core without ICU installed, the following exception may be thrown when attempting to connect to a database:
System.Globalization.CultureNotFoundException: Only the invariant culture is supported in globalization-invariant mode. See https://aka.ms/GlobalizationInvariantMode for more information. (Parameter 'name')
en-us is an invalid culture identifier.
This is by design. Microsoft.Data.SqlClient
requires ICU to be installed. See this Sql Client issue for more information.
ICU can be added to a .NET Alpine image by adding the following instructions to the final stage within a Dockerfile
, as demonstrated in Dockerfile.alpine-icu. This Dockerfile fragment adds and configures ICU and disables Globalization invariant mode.
ENV \
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false \
LC_ALL=en_US.UTF-8 \
LANG=en_US.UTF-8
RUN apk add --no-cache \
icu-data-full \
icu-libs
ICU can be added to an Ubuntu chiseled image, as demonstrated in this chisel issue.
Tzdata provides data for applications that rely on timezone information. Applications that solely use DateTime.UtcNow
for recording time don't need this library.
The following code uses tzdata
:
DateTime nowUtc = DateTime.UtcNow;
DateTime now = DateTime.Now;
var homeZone = TimeZoneInfo.Local;
string home = "America/Los_Angeles";
var tz = TimeZoneInfo.FindSystemTimeZoneById(home);
With tzdata
installed and the timezone configured (via the TZ
environment variable or writing a value to /etc/timezone
), DateTime.UtcNow
and DateTime.Now
will return the correct values (which will be same if the timezone is Etc/UTC
), TimeZoneInfo.Local
will return the value set in /etc/timezone
, and the call to TimeZoneInfo.FindSystemTimeZoneById
will succeed.
Without tzdata
installed, DateTime.UtcNow
and DateTime.Now
will return the same value, TimeZoneInfo.Local
will return a value for UTC, and the call to TimeZoneInfo.FindSystemTimeZoneById
will fail resulting in an exception.
.NET container images do not install tzdata
, however, Debian images contain it (at the time of writing). If you rely on this library, you need to install it by adding the following instructions to the final stage within a Dockerfile
, depending on the distro you use.
tzdata
can be added to a .NET Alpine image with the following Dockerfile
fragment.
RUN apk add --no-cache tzdata
tzdata
can be added to a .NET Ubuntu image with the following Dockerfile
fragment.
apt update && DEBIAN_FRONTEND=noninteractive apt install -y tzdata && rm -rf /var/lib/apt/lists/*
The best practice is to pass timezone information into a container via environment variable.
docker run --rm -it -e TZ="Etc/UTC" app
Alternatively, the host timezone can be used:
$ cat /etc/timezone
America/Los_Angeles
$ docker run --rm -it -e TZ=$(cat /etc/timezone) app
This approach enables a container image to be launched with a specific timezone (at launch), as opposed to setting the timezone in the image as part of docker build
.