Skip to main content

.NETアプリケーションをコンテナ化する際のベストプラクティス

著者

Marcelo Oliveira

hero container aps

2022年8月31日

0 分で読めます

Dockerによるコンテナ化は、Webアプリケーション開発における大きなトレンドとなり、多くの.NET開発者が取り入れています。.NET Framework 4.xのような古いバージョンを使っている場合でも、.NETアプリケーションをコンテナ化することには、開発者やDevOpsエンジニアにとって多くのメリットがあります。ただし、コンテナを適切に使う方法を知らなければ、そのメリットをほとんど得られません。

この記事では、4.xバージョンのフレームワークを含む.NETアプリケーションをコンテナ化する際のベストプラクティスをご紹介します。セキュリティリスクを減らし、コンテナから不要なコンポーネントを取り除くための、軽量なイメージの利用とイメージスキャンについても解説します。

必要なもの

始める前に、次の準備が必要です。

.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を起動します。

「docker desktop」のWindows検索結果。最も一致するアプリとしてDocker Desktopが表示されています。

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

「新しいプロジェクトの作成」オプションが赤く強調表示された、Visual Studioのスタート画面。

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

「Web Forms」のVisual Studio検索結果。C#、Windows、Cloud、Webのタグが付いたASP.NET Web Applicationプロジェクトテンプレートが表示されている

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

「WebFormsApp」という名前の.NET Framework 4.8用ASP.NET Web Applicationプロジェクトを新規作成するためのVisual Studioダイアログ

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

「新しい ASP.NET Web アプリケーション」画面。Empty と Web Forms のプロジェクトテンプレートの選択肢と説明が表示されている

Web FormsとDocker supportが選択されていることを確認し、Createをクリックします。

フォルダーとコア参照のオプション、詳細設定、無効化されたテストプロジェクト欄、[戻る]ボタンと[作成]ボタンが表示されたプロジェクト作成ダイアログ。

Visual Studioによるプロジェクトの作成が完了するまで待ちます。Visual Studioで表示されるプロジェクト構造は次のとおりです。

ASP.NETのファイル、フォルダー、構成ファイルを含むWebFormsAppプロジェクトの構造を表示したVisual Studioのソリューションエクスプローラー。

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

Docker DesktopのContainersビューに、ポート61469で実行中のWebFormsAppコンテナが表示されています

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

ディスク上のDocker Desktopイメージ画面。webformsapp:devを含む2つのローカルイメージの合計サイズは8.64 GB。

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

ナビゲーション、紹介文、利用開始、ライブラリ、Webホスティングの各セクションを表示した、ASP.NETアプリケーションのホームページのブラウザーウィンドウ。

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

Dockerfileがハイライト表示された、WebFormsAppプロジェクトのVisual Studioソリューション エクスプローラー。

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

ASP.NETアプリケーション用のDockerfileを表示するVisual Studioエディター。.NET Frameworkのベースイメージ、ソース引数、作業ディレクトリ、公開設定を含む。

FROM命令は新しいビルドステージを初期化し、以降の命令で使用するベースイメージを設定します。この例ではaspnet:4.8-windowsservercore-ltsc2019がイメージとして指定されており、DockerがMicrosoftのイメージリポジトリから取得します。

もちろん、Web FormsプロジェクトはDockerサポートなしで作成されていることのほうが多いでしょう。この状況を再現するため、今度はDockerサポートを有効にせず、新しいASP.NET Web Formsプロジェクトを作成します。

WebFormsAppソリューションのWebFormsAppNoDockerプロジェクトで、ASPXページや設定ファイルなどのファイルが表示されたVisual Studioのソリューション エクスプローラー。

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

Webプロジェクトで「Docker Support」が選択された「Add」メニューを表示しているVisual Studioのソリューション エクスプローラー

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

Dockerfileが選択されたWebFormsAppNoDockerプロジェクトを表示するVisual Studioのソリューション エクスプローラー

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

ASP.NET Frameworkのベースイメージ、WORKDIR /inetpub/wwwroot、ビルド出力をコピーするCOPYコマンドを含む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を選択します。

Connected Services、Dependencies、Properties、wwwroot、Pages、appsettings.json、Dockerfile、C#を含むWebAppプロジェクトを表示したVisual Studioのソリューションエクスプローラー

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

ASP.NET Core Web アプリのプロジェクト名、場所、ソリューション名、ディレクトリのオプションが表示された、Visual Studio の「新しいプロジェクトの構成」画面。

Nextをクリックし、次のオプションを選択します。

  • .NET 6.0 Framework

  • 認証の種類:なし

  • HTTPSを構成する:チェックを入れる

  • Dockerを有効にする:チェックを入れる

  • Docker OS:Linux

ASP.NET Core Webアプリの追加情報設定。.NET 6.0、認証なし、HTTPSとDockerが有効で、Linuxが選択されています。

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

C#、すべてのプラットフォーム、Webのフィルターが設定された、ASP.NET Core Web Appテンプレートを表示するテンプレート検索ウィンドウ。

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

「Welcome」の見出し、ASP.NET CoreでのWebアプリ構築に関するリンク、「Home」と「Privacy」のナビゲーションリンクが表示されたWebアプリのホームページ。

次に、docker imagesコマンドを実行して、システム上のDockerイメージ一覧を表示します。

> docker images

このコマンドを実行すると、次のような結果が表示されます。

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
webapp       dev       e3b51b1eef08   4 hours ago   208MB

アプリはLinuxコンテナで実行されており、上記のwebappイメージのサイズは208 MBです。

次に、Webアプリのコンテナイメージを小さくしてみましょう。

Visual Studioでアプリを停止し、Dockerfileを開きます。次の部分では、Dockerにdotnet/aspnet:6.0とdotnet/sdk:6.0のイメージをMicrosoft Container Registry(MCR)から取得し、アプリコンテナのベースイメージとして使うよう指示しています。

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
WORKDIR /src
COPY ["WebApp/WebApp.csproj", "WebApp/"]
RUN dotnet restore "WebApp/WebApp.csproj"
COPY . .
WORKDIR "/src/WebApp"
RUN dotnet build "WebApp.csproj" -c Release -o /app/build

次にF5を押してアプリケーションを再実行します。Webアプリが起動したら、docker imagesコマンドを実行してシステム上のDockerイメージ一覧を表示します。

> docker images

イメージ一覧は次のように表示されます。

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
webapp       dev       778bcd52f366   4 hours ago   100MB
<none>       <none>    e3b51b1eef08   4 hours ago   208MB

webappイメージが再ビルドされ、サイズが100 MBになっていることがわかります(元のイメージより108 MB小さくなっています)。

イメージをスキャンして脆弱性を検出する

コードベースを頻繁に更新すること自体がベストプラクティスです。新機能やバグ修正、より優れたユーザーインターフェイス、パフォーマンス向上といったメリットは明らかです。しかし、セキュリティアップデートも同じくらい重要です。

ベースイメージのOSやライブラリに未修正の脆弱性が含まれている可能性があります。また、ベースイメージに追加したスクリプト、コード、アプリにも、気付かないまま本番環境に持ち込んでしまう脆弱性が含まれている可能性があります。

コンテナの脆弱性をスキャンすることは、潜在的なセキュリティリスクを評価し、適切な対策を講じるうえで欠かせません。ここでは、古い.NETイメージmcr.microsoft.com/dotnet/core/aspnet:2.2を使ってみましょう。

dotnet new webapp -n "AspNet2.2" -f "netcoreapp2.2"

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

次にDockerfileを開き、内容を以下のコードに置き換えます。

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:2.2.105 AS build
WORKDIR /src
COPY ["AspNet2.2.csproj", "."]
RUN dotnet restore "./AspNet2.2.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "AspNet2.2.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "AspNet2.2.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "AspNet2.2.dll"]

次に、イメージスキャンを適用してコンテナにどの程度の脆弱性があるかを調べます。まずdocker images CLIコマンドを実行し、現在のローカルイメージを一覧表示します。

docker images

REPOSITORY       TAG       IMAGE ID       CREATED              SIZE
aspnet22         latest    223b485f4516   About a minute ago   265MB

次にsnyk authコマンドを実行して、Snyk CLIの認証を行います。

> snyk auth

アカウントの認証が完了したら、Snyk CLIを使う準備ができました。snyk container test <repository>:<tag>コマンドを実行して、ローカルでビルドし、ローカルのDockerデーモンで利用できるようにしたイメージをテストしましょう。

> snyk container test aspnet22:latest
zlib、systemd、shadow/passwdパッケージの重大度の高い脆弱性を一覧表示するPowerShellターミナル

snyk container testコマンドは、イメージにインストールされているコンポーネントの一覧を生成してSnykサービスに送信し、イメージ内の脆弱性一覧を返します。

スキャンの結果、イメージ内に193件の脆弱性が見つかりました。

docker-image|aspnet22のターミナルレポート。Microsoft .NETベースイメージに193件の脆弱性があり、そのうち10件はクリティカルと表示されています。

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

> snyk container monitor aspnet22:latest
aspnet22:latest DockerイメージのSnykによるモニタリング結果と、プロジェクト履歴を表示するリンクが示されたターミナル出力。

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

「ベースイメージのアップグレードに関する推奨事項」というタイトルの表。脆弱性と深刻度ごとに、現在の.NETベースイメージと代替イメージを比較しています。

コンテナ化の3つのヒント

.NETアプリケーションのコンテナ化には、開発者やDevOpsエンジニアにとって魅力的なメリットが数多くあります。しかし、コンテナはあらゆる問題を解決する魔法のようなものではありません。コンテナを正しく理解し、そのメリットを最大限に引き出す方法を知るために、ベストプラクティスを実践する必要があります。

コンテナは.NET Coreアプリ専用という誤解が根強くありますが、.NET Framework 4.xアプリケーションにもメリットがあることを見てきました。

コンテナイメージは、小さければ小さいほど優れています。アプリの実行に必要なものだけを含む小さなベースイメージを使えば、コンテナの攻撃対象領域を縮小できることがわかりました。

最後に、コンテナイメージをスキャンして最新の状態に保つことで、セキュリティリスクを軽減する方法を見てきました。Snyk container testとSnyk container monitorコマンドは、.NETコンテナの脆弱性をスキャンし、継続的に監視するための非常に役立つツールです。適切に使えば、コンテナ化によってアプリの古さを問わず、セキュリティと柔軟性をさらに高められます。

開発者ファーストのコンテナセキュリティ

Snykは、コンテナイメージとKubernetesワークロードの脆弱性を検出し、自動的に修正します。