.NETアプリケーションをコンテナ化する際のベストプラクティス
Marcelo Oliveira
2022年8月31日
0 分で読めますDockerによるコンテナ化は、Webアプリケーション開発における大きなトレンドとなり、多くの.NET開発者が取り入れています。.NET Framework 4.xのような古いバージョンを使っている場合でも、.NETアプリケーションをコンテナ化することには、開発者やDevOpsエンジニアにとって多くのメリットがあります。ただし、コンテナを適切に使う方法を知らなければ、そのメリットをほとんど得られません。
この記事では、4.xバージョンのフレームワークを含む.NETアプリケーションをコンテナ化する際のベストプラクティスをご紹介します。セキュリティリスクを減らし、コンテナから不要なコンポーネントを取り除くための、軽量なイメージの利用とイメージスキャンについても解説します。
必要なもの
始める前に、次の準備が必要です。
Visual Studio 2022をダウンロードしてインストールします。
ローカルでコンテナを実行するためのDockerクライアントが必要です。Docker Desktopを利用できます。Windows 10以降が必要です。Windows版を選択してください。
Snyk Command Line Interface(CLI)をダウンロードしてインストールします。
Snykの無料アカウントに登録します。
.NETアプリをコンテナ化する(.NET Framework 4.xも対象)
.NET Core 1.0以降、Webアプリはクロスプラットフォーム対応となり、移植性が高く、オープンソースになりました。これにより、開発者はアプリをDockerに移行し、コンテナ化のメリットを最大限に活用できるようになりました。
Linux上で動作する新しい.NETバージョンが注目を集める一方、Windowsコンテナは、数多くのエンタープライズアプリケーションが依存する、古いWindows専用の.NETバージョンをサポートしています。.NET FrameworkのWebアプリを保守しているすべての組織が、新しいバージョンへの移行をすぐにできるわけではありません。そのため、.NET Framework 4.xアプリケーションのコンテナ化には意味があります。
以下では、Visual Studio 2022でASP.NET Web Formsアプリケーションをコンテナ化して実行する手順を説明します。
まず、開発マシンでDocker Desktopを起動します。

Visual StudioのGet startedウィンドウで、Create a new projectを選択します。

Search for templatesのテキストボックスに「Web Forms」と入力し、ASP.NET Web Application (.NET Framework)を選択します。

新しいアプリケーションの名前(例:WebFormsApp)を入力し、ディスク上の場所を指定して、.NET Framework 4.8を選択し、Createをクリックします。

次に、種類としてWeb Formsを選択します。

Web FormsとDocker supportが選択されていることを確認し、Createをクリックします。
![フォルダーとコア参照のオプション、詳細設定、無効化されたテストプロジェクト欄、[戻る]ボタンと[作成]ボタンが表示されたプロジェクト作成ダイアログ。](https://res.cloudinary.com/snyk/image/upload/f_auto,w_580,q_auto/v1663085447/wordpress-sync/blog-net-add-folder-ref.jpg)
Visual Studioによるプロジェクトの作成が完了するまで待ちます。Visual Studioで表示されるプロジェクト構造は次のとおりです。

次に、Docker Desktopを開きます。WebFormsAppコンテナがポート61469で実行されていることを確認できます。

Imagesタブを開くと、WebFormsAppコンテナの実行元であるWebFormsAppイメージが表示されます。

最後に、Ctrl+F5を押してDockerイメージをビルドし、ローカルで実行します。コンテナイメージのビルドとDockerコンテナでの実行が完了すると、Visual Studioによって既定のブラウザーでWebアプリが起動します。

次に、Visual Studioに戻り、Dockerfileファイルをクリックします。

コンテナ内でプロジェクトを実行するための設定が記述されたDockerfileが開きます。

FROM命令は新しいビルドステージを初期化し、以降の命令で使用するベースイメージを設定します。この例ではaspnet:4.8-windowsservercore-ltsc2019がイメージとして指定されており、DockerがMicrosoftのイメージリポジトリから取得します。
もちろん、Web FormsプロジェクトはDockerサポートなしで作成されていることのほうが多いでしょう。この状況を再現するため、今度はDockerサポートを有効にせず、新しいASP.NET Web Formsプロジェクトを作成します。

次に、新しいプロジェクトにDockerfileを追加します。プロジェクト名を右クリックし、AddメニューからDocker Supportサブメニューを選択します。

これでVisual StudioがプロジェクトのDockerfileを自動的に作成します。

コンテナの生成元となるイメージとソースコードのパスは、すでにVisual Studioによって選択されています。

これでプロジェクトにDockerによるコンテナ化のサポートが追加され、移植性、俊敏性、迅速なデリバリー、セキュリティの向上、管理の簡素化などのメリットを得られます。
コンテナイメージをできるだけ小さくする
LinuxとWindowsのどちらのコンテナにも、アプリケーションの実行に必要なアプリとサービスだけを含む軽量なベースイメージがあります。依存関係を最小限に抑えた小さなイメージを使えば、依存関係を通じて持ち込まれる脆弱性を減らし、攻撃対象領域を縮小できます。
.NET開発者が小さなコンテナに使えるベースイメージをいくつか見てみましょう。まず、LinuxではサポートされていないASP.NET Framework 4.xを引き続き使用している場合、選択肢はWindowsコンテナのみです。Microsoftが推奨する軽量なベースイメージは、Windows Server CoreとNano Serverです。
Windows Server Coreは、標準のWindowsグラフィカルユーザーインターフェイスを必要としないWindows Serverの役割の実行やアプリケーションの稼働に使う、コマンドラインベースの最小構成OSです。Nano Serverは、プライベートクラウドやデータセンター向けに最適化されたオペレーティングシステムです。Nano Serverにはローカルログオン機能がなく、サイズがより小さく、Server Coreよりもはるかに高速に再起動します。
.NET Coreおよび.NET 5以降では、SDKイメージはビルドのみに使用し、マルチステージビルドの一部として本番環境にデプロイする場合はランタイムイメージを使用します。軽量なベースイメージの候補として、Debian bullseye-slim-amd64やAlpine Linuxのイメージがあります。
.NETランタイムの依存関係用イメージを使い、.NETアプリケーションを自己完結型モードでビルドすると、ベースイメージをさらに小さくできます。これにより、アプリに必要な依存関係だけを取得し、それ以外は含めずに済みます。
それでは、軽量イメージを使って.NET 6のWebアプリケーションをビルドしてみましょう。Visual Studio 2022を開き、Create New Projectをクリックして、種類としてASP.NET Core Web Appを選択します。

WebAppなどのプロジェクト名を入力します。

Nextをクリックし、次のオプションを選択します。
.NET 6.0 Framework
認証の種類:なし
HTTPSを構成する:チェックを入れる
Dockerを有効にする:チェックを入れる
Docker OS:Linux

Createボタンをクリックし、Visual Studioに新しいプロジェクトが表示されることを確認します。

F5を押して、ローカルのDockerコンテナでホストされているWebアプリを実行します。

次に、docker imagesコマンドを実行して、システム上のDockerイメージ一覧を表示します。
このコマンドを実行すると、次のような結果が表示されます。
アプリはLinuxコンテナで実行されており、上記のwebappイメージのサイズは208 MBです。
次に、Webアプリのコンテナイメージを小さくしてみましょう。
Visual Studioでアプリを停止し、Dockerfileを開きます。次の部分では、Dockerにdotnet/aspnet:6.0とdotnet/sdk:6.0のイメージをMicrosoft Container Registry(MCR)から取得し、アプリコンテナのベースイメージとして使うよう指示しています。
次にF5を押してアプリケーションを再実行します。Webアプリが起動したら、docker imagesコマンドを実行してシステム上のDockerイメージ一覧を表示します。
イメージ一覧は次のように表示されます。
webappイメージが再ビルドされ、サイズが100 MBになっていることがわかります(元のイメージより108 MB小さくなっています)。
イメージをスキャンして脆弱性を検出する
コードベースを頻繁に更新すること自体がベストプラクティスです。新機能やバグ修正、より優れたユーザーインターフェイス、パフォーマンス向上といったメリットは明らかです。しかし、セキュリティアップデートも同じくらい重要です。
ベースイメージのOSやライブラリに未修正の脆弱性が含まれている可能性があります。また、ベースイメージに追加したスクリプト、コード、アプリにも、気付かないまま本番環境に持ち込んでしまう脆弱性が含まれている可能性があります。
コンテナの脆弱性をスキャンすることは、潜在的なセキュリティリスクを評価し、適切な対策を講じるうえで欠かせません。ここでは、古い.NETイメージmcr.microsoft.com/dotnet/core/aspnet:2.2を使ってみましょう。
Visual Studioでプロジェクトを開き、新しいプロジェクトにDockerfileを追加します。プロジェクト名を右クリックし、AddメニューからDocker Supportサブメニューをクリックします。
次にDockerfileを開き、内容を以下のコードに置き換えます。
次に、イメージスキャンを適用してコンテナにどの程度の脆弱性があるかを調べます。まずdocker images CLIコマンドを実行し、現在のローカルイメージを一覧表示します。
次にsnyk authコマンドを実行して、Snyk CLIの認証を行います。
アカウントの認証が完了したら、Snyk CLIを使う準備ができました。snyk container test <repository>:<tag>コマンドを実行して、ローカルでビルドし、ローカルのDockerデーモンで利用できるようにしたイメージをテストしましょう。

snyk container testコマンドは、イメージにインストールされているコンポーネントの一覧を生成してSnykサービスに送信し、イメージ内の脆弱性一覧を返します。
スキャンの結果、イメージ内に193件の脆弱性が見つかりました。

イメージを監視するには、snyk container monitor <repository>:<tag>コマンドを実行します。

snyk container monitorコマンドは、イメージにインストールされているコンポーネントの一覧を生成してSnykサービスに送信し、http://app.snyk.io/org/{YOUR-ACCOUNT}/にあるSnykサービスへのリンクを返します。リンク先で結果を確認できます。

コンテナ化の3つのヒント
.NETアプリケーションのコンテナ化には、開発者やDevOpsエンジニアにとって魅力的なメリットが数多くあります。しかし、コンテナはあらゆる問題を解決する魔法のようなものではありません。コンテナを正しく理解し、そのメリットを最大限に引き出す方法を知るために、ベストプラクティスを実践する必要があります。
コンテナは.NET Coreアプリ専用という誤解が根強くありますが、.NET Framework 4.xアプリケーションにもメリットがあることを見てきました。
コンテナイメージは、小さければ小さいほど優れています。アプリの実行に必要なものだけを含む小さなベースイメージを使えば、コンテナの攻撃対象領域を縮小できることがわかりました。
最後に、コンテナイメージをスキャンして最新の状態に保つことで、セキュリティリスクを軽減する方法を見てきました。Snyk container testとSnyk container monitorコマンドは、.NETコンテナの脆弱性をスキャンし、継続的に監視するための非常に役立つツールです。適切に使えば、コンテナ化によってアプリの古さを問わず、セキュリティと柔軟性をさらに高められます。
開発者ファーストのコンテナセキュリティ
Snykは、コンテナイメージとKubernetesワークロードの脆弱性を検出し、自動的に修正します。
