[Docker] ASP.NET Core Runtime のイメージ差異に気をつけたい
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
のイメージは、イメージサイズに重点をおいているため、icu
とtzdata
が含まれておらず、Unicodeとグローバリゼーションのサポート、タイムゾーン情報を必要としないアプリでのみ動作します。
というようなことが下記に書いてあります。
実際にDebian
とAlpine
のDockerfileを確認して、icu
とtzdata
のライブラリのインストールの有無を確認してみます。
長くなるので気になる方は展開してご確認ください。
Debian 12のDockerfile
-
mcr.microsoft.com/dotnet/aspnet:8.0
-
mcr.microsoft.com/dotnet/runtime:8.0.0-bookworm-slim-amd64
-
mcr.microsoft.com/dotnet/runtime-deps:8.0.0-bookworm-slim-amd64
RUN apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates \ \ # .NET dependencies libc6 \ libgcc-s1 \ libicu72 \ libssl3 \ libstdc++6 \ tzdata \ zlib1g \ && rm -rf /var/lib/apt/lists/*
icu
ライブラリとtzdata
がインストールされている
-
-
mcr.microsoft.com/dotnet/runtime:8.0.0-bookworm-slim-amd64
Alpine 3.18のDockerfile
-
mcr.microsoft.com/dotnet/aspnet:8.0.0-alpine3.18
-
mcr.microsoft.com/dotnet/runtime:8.0.0-alpine3.18-amd64
-
mcr.microsoft.com/dotnet/runtime-deps:8.0.0-alpine3.18-amd64
ENV \ # Set the invariant mode since ICU package isn't included (see https://github.com/dotnet/announcements/issues/20) DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true RUN apk add --upgrade --no-cache \ ca-certificates-bundle \ \ # .NET dependencies libgcc \ libssl3 \ libstdc++ \ zlib
icu
ライブラリとtzdata
がインストールされていない
また、icu
がインストールされないため、グローバリゼーションインバリアントモードを有効にされている。
-
-
mcr.microsoft.com/dotnet/runtime:8.0.0-alpine3.18-amd64
icu
Unicodeとグローバリゼーションのサポート機能とは -
icu
ライブラリがない場合は、イメージ側でグローバリゼーションインバリアントモード
が有効になっている。 - .NET 6 以降では、グローバリゼーションインバリアントモードが有効状態でインバリアントカルチャ以外のカルチャを作成すると、例外がスローされる。
グローバリゼーションインバリアントモード
が有効な場合の影響については下記の資料が参考になります。
影響を受けるAPI
- CultureInfo
- System.Globalization.CultureInfo.CreateSpecificCulture(String)
- System.Globalization.CultureInfo.GetCultureInfo
- RegionInfo
- 文字列の大文字と小文字の使い分け、比較、または検索を実行する 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)が管理しています。
実際動作させたらどうなる?
下記のコードを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.18
にicu
とtzdata
をインストールする
おまけ 軽量なAlpine 3.18
を利用したいが、Unicodeとグローバリゼーションのサポートとタイムゾーン情報をサポートしたい場合に、icu
とtzdata
をインストールしてみます。
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
を利用するのが良いと思いますが、icu
とtzdata
が含まれていない影響を考慮した上で選択する必要があります。
セキュリティの脆弱性という観点では、Debian 12
よりは軽量なAlpine 3.18
の方が脆弱性が少ないように見えます。
ただ、クリティカルなものは修正されていくので、最新版に追従出来ればそこまで気にする必要はないかなと思います。
ただ、実際問題として運用環境をそう簡単にホイホイ更新できるものでもないのが難しいところですね。
最後になりますが、イメージでのデプロイを行う場合、Visual Studio 2022でのデバッグは必ずDocker
で行いましょう!
何を当たり前なことをと思われるかもしれませんが、デバッグ選択肢を間違えてiis
で確認していて、デプロイしたらプラットフォーム差異で運用環境で爆発という事態になりかねませんので。。。
Discussion