📘

[Docker] ASP.NET Core Runtime のイメージ差異に気をつけたい

2023/12/19に公開

ASP.NET Core Runtime のイメージの種類

Docker Hub の ASP.NET Core Runtimeには、ASP.NET Core Runtimeのイメージが複数存在し、ざっと列挙してみると下記のイメージが存在します。
Ubuntu, Debian, Windows Server Core, Nano Server, Alpine, Ubuntu Chiseled, CBL-Mariner

Visual Studio 2022でASP.NET Core Web API (.NET 8)プロジェクトをDocker を有効にするで作成するとDebian 12のイメージが指定されています。

イメージの差異

Ubuntu,Debian,Windows Server Core,Nano Serverのイメージには、Unicodeとグローバリゼーションのサポートを提供するICUライブラリ、タイムゾーン情報を提供するライブラリ(Linuxの場合tzdata)が含まれていてフル機能を提供します。
しかし、Alpine,Ubuntu Chiseledのイメージは、イメージサイズに重点をおいているため、icutzdataが含まれておらず、Unicodeとグローバリゼーションのサポート、タイムゾーン情報を必要としないアプリでのみ動作します。

というようなことが下記に書いてあります。
https://github.com/dotnet/dotnet-docker/blob/main/documentation/image-variants.md#L1-L12

実際にDebianAlpineのDockerfileを確認して、icutzdataのライブラリのインストールの有無を確認してみます。
長くなるので気になる方は展開してご確認ください。

Debian 12のDockerfile
Alpine 3.18のDockerfile

Unicodeとグローバリゼーションのサポート機能とは icu

  • icuライブラリがない場合は、イメージ側でグローバリゼーションインバリアントモードが有効になっている。
  • .NET 6 以降では、グローバリゼーションインバリアントモードが有効状態でインバリアントカルチャ以外のカルチャを作成すると、例外がスローされる。

https://learn.microsoft.com/ja-jp/dotnet/core/compatibility/globalization/6.0/culture-creation-invariant-mode

グローバリゼーションインバリアントモードが有効な場合の影響については下記の資料が参考になります。
https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md

影響を受けるAPI

実際動作させたらどうなる?

下記のコードをグローバリゼーションインバリアントモードが有効になっているイメージで実行してみます。

CultureInfo.GetCultureInfo("ja-JP");

結果

指定したカルチャがサポートされていないというエラーが発生します。
グローバリゼーションインバリアントモードが有効になっているためですね。

System.Globalization.CultureNotFoundException: Only the invariant culture is supported in globalization-invariant mode. See https://aka.ms/GlobalizationInvariantMode for more information. (Parameter 'name')
ja-jp is an invalid culture identifier.
   at System.Globalization.CultureInfo.GetCultureInfo(String name)
   at ...

タイムゾーン情報とは tzdata

タイムゾーン情報のデータベースは、IANA(Internet Assigned Numbers Authority)が管理しています。

https://www.iana.org/time-zones

実際動作させたらどうなる?

下記のコードをtzdataが入っていないイメージで実行してみます。

TimeZoneInfo.FindSystemTimeZoneById("Asia/Tokyo");

結果

指定したタイムゾーンが見つからないというエラーが発生します。

System.TimeZoneNotFoundException: The time zone ID 'Asia/Tokyo' was not found on the local computer.
 ---> System.IO.DirectoryNotFoundException: Could not find a part of the path '/usr/share/zoneinfo/Asia/Tokyo'.
   at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
   at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.TimeZoneInfo.ReadAllBytesFromSeekableNonZeroSizeFile(String path, Int32 maxFileSize)
   at System.TimeZoneInfo.TryGetTimeZoneFromLocalMachineCore(String id, TimeZoneInfo& value, Exception& e)
   --- End of inner exception stack trace ---
   at System.TimeZoneInfo.FindSystemTimeZoneById(String id)
   at ....

おまけ Alpine 3.18icutzdataをインストールする

軽量なAlpine 3.18を利用したいが、Unicodeとグローバリゼーションのサポートとタイムゾーン情報をサポートしたい場合に、icutzdataをインストールしてみます。

Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0.0-alpine3.18

RUN apk add --upgrade --no-cache \
        # .NET dependencies
        icu-data-full \
        icu-libs \
        tzdata \

まとめ

基本的に、Visual Studio 2022でASP.NET Core Web APIプロジェクトをDocker を有効にするで作成した状態で利用していれば何も問題がありません!

軽量化を考えたい場合、Alpine 3.18を利用するのが良いと思いますが、icutzdataが含まれていない影響を考慮した上で選択する必要があります。

セキュリティの脆弱性という観点では、Debian 12よりは軽量なAlpine 3.18の方が脆弱性が少ないように見えます。
ただ、クリティカルなものは修正されていくので、最新版に追従出来ればそこまで気にする必要はないかなと思います。

ただ、実際問題として運用環境をそう簡単にホイホイ更新できるものでもないのが難しいところですね。

最後になりますが、イメージでのデプロイを行う場合、Visual Studio 2022でのデバッグは必ずDockerで行いましょう!
何を当たり前なことをと思われるかもしれませんが、デバッグ選択肢を間違えてiisで確認していて、デプロイしたらプラットフォーム差異で運用環境で爆発という事態になりかねませんので。。。

Discussion