スキップしてメイン コンテンツに移動

【Day 16】ASP.NET Core Web APIのコンテナ化(初めてのDockerfile作成)

Day 16 アイキャッチ
▲ Day 16: ASP.NET Core Web APIのコンテナ化(初めてのDockerfile作成)
🐳
皆さん、こんにちは! Docker/コンテナ実践講座の専任講師です。
いよいよ本日より「第4部: C# / .NET アプリケーションのコンテナ化(Dockerfile)」が幕を開けます!
これまでは既存のnginxやhello-worldコンテナを起動・操作・デバッグする基礎を学んできましたが、今日からは私たちが普段開発している「本物のC# / ASP.NET Core Web APIアプリケーション」を自分自身の手でコンテナ化する本丸の領域へ突入します!
「IISの手順書構築しかやったことがない」という30年選手のベテランエンジニアの皆さんも、Dockerfileの基本命令(FROM, WORKDIR, COPY, RUN, ENTRYPOINT)を一度理解してしまえば、サーバー構築の常識が180度変わる快感を味わっていただけます!

① 導入・本日の達成目標

Dockerの本当の価値は、誰かが作ったイメージを動かすことではなく、「自分たちの業務アプリケーションを再現性100%のイメージとしてパッケージングする」ことにあります。
その中心となる設計図が Dockerfile です。

本日の講義を終える頃には、以下の3つの目標を完全にクリアできるようになります。

  • Dockerfileの基本構文である5大命令(FROM, WORKDIR, COPY, RUN, ENTRYPOINT)の役割と実行順序を論理的に理解できる。
  • IISの手動仮想ディレクトリ構築とDockerfileの違いを把握し、インフラをGitでコード管理するメリットを体感できる。
  • 実際に dotnet publish で出力したC# Web APIの成果物をDockerfileでイメージ化(docker build)し、ローカルでコンテナ起動(docker run)してAPIレスポンスを確認できる。

② VM / Windowsサーバー技術者のためのパラダイムシフト

長年Windows ServerとIIS(Internet Information Services)でWebシステムを運用してきたエンジニアにとって、Web APIの新規デプロイといえば以下のような骨の折れる作業でした。

IIS手動設定 vs Dockerfileコード化
▲ 【図解②】旧来のIIS手動構築 vs 現代のDockerfileコード化によるパラダイムシフト

Windows Serverにログインし、IISマネージャーを開き、アプリケーションプールを作成して.NET CLRバージョンを選択し、仮想ディレクトリを掘って物理パスを割り当て、アクセス権限(IIS_IUSRS等)を設定する……。
どれだけ分厚いExcel手順書を作っても、作業者の操作ミスやサーバーごとの環境差異によって「開発機では動いたのにステージングサーバーでHTTP 500エラー」というトラブルが日常茶飯事でした。

しかしDockerの世界では、これらすべてのサーバー構築手順が「リポジトリ直下のたった1枚のテキストファイル(Dockerfile)」に凝縮されます!
OSの環境準備、フォルダ作成、成果物の配置、ポート開放、起動プロセスの定義まで、すべてが数行のコードとして記述され、Gitで厳格にバージョン管理されるのです。

📊 旧来のIIS手動構築 と 現代のDockerfileコード化 の対比表

比較項目 旧来:IIS / Windows Server 手動構築 現代:Dockerfile によるインフラコード化
環境構築の手段 GUI(IISマネージャー)+Excel手順書 テキストファイル(Dockerfile)に宣言的記述
バージョン管理 ❌ 手順書の日付更新のみ(実機差分は追跡不能) ⭕ Gitコミット・PRレビューで完全追跡
再現性 人的ミスやサーバー固有設定によりブレやすい 100% 誰のPCでもクラウドでも寸分違わず同一動作
Webサーバー 重厚なIIS(OS固定) 高速・軽量なKestrel(.NET内蔵Webサーバー)
構築所要時間 数十分〜半日 ビルド実行から起動まで数秒〜数十秒

③ Dockerfileの基本構造と5大必須命令

Dockerfileは、上から下に向かって1行ずつ実行される「コンテナイメージの組み立て指示書」です。
まずはASP.NET Core Web APIを動かすための最小構成のDockerfileを見てみましょう。

Dockerfileの主要命令
▲ 【図解①】Dockerfileの基本構文(ベース準備から起動までの3大ステップ)
# 1. 土台となる公式.NETランタイムイメージを指定
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base

# 2. コンテナ内部の作業ディレクトリを設定
WORKDIR /app

# 3. ホストPCでビルド済みの成果物(publishフォルダ)をコンテナ内へコピー
COPY ./publish .

# 4. コンテナがリッスンするポート番号を明示(ドキュメント用途)
EXPOSE 8080

# 5. コンテナ起動時に実行するコマンドを指定
ENTRYPOINT ["dotnet", "MyWebApi.dll"]

各命令の役割とベテラン向け解説

  • FROM: すべてのDockerfileの1行目に記述する最重要命令です。Microsoftが公式配布しているASP.NET Coreランタイム(Linuxベース)を土台として指定します。SDKではなくランタイム(aspnet:8.0)を選ぶことで、イメージサイズを約200MB程度に抑えられます。
  • WORKDIR: Linuxコマンドの cd と mkdir を合体させた命令です。指定したディレクトリ(/app)が存在しなければ自動作成し、以降の COPY や ENTRYPOINT のカレントディレクトリとします。これを書かないとルート直下(/)にDLLが散乱してしまいます。
  • COPY: ホストPC側のファイルやフォルダをコンテナ内部へコピーします。上記の例では、ホストの ./publish フォルダ内にある全ファイルを、コンテナの WORKDIR(/app)へ流し込んでいます。
  • EXPOSE: コンテナが待ち受けるポート(.NET 8のデフォルトは8080)をDockerに宣言するメタデータです(実際のポートバインディングは docker run -p で行います)。
  • ENTRYPOINT: コンテナがインスタンス化(起動)された瞬間に実行するメインプロセスを指定します。

④ ENTRYPOINT と CMD の役割と決定的違い

Docker初心者が最も混乱しやすいのが「ENTRYPOINT と CMD の違い」です。
どちらも「コンテナ起動時に実行するコマンド」を指定できるように見えますが、その役割分担は明確に異なります。

ENTRYPOINTとCMDの役割
▲ 【図解③】ENTRYPOINT と CMD の役割分担とC#/.NETにおける設計ルール

🎯 結論:コンテナの「役割」と「引数」の分離

  • ENTRYPOINT(固定実行コマンド): コンテナの「主たる役割」を定義します。C# Web APIの場合、このコンテナは「dotnet コマンドを実行するサーバー」であるため、ENTRYPOINT ["dotnet", "MyWebApi.dll"] と固定するのがベストプラクティスです。docker run の引数で簡単に上書きされません。
  • CMD(可変引数・デフォルト値): ENTRYPOINT に渡す「引数の初期値」を提供します。docker run my-image --environment=Staging のように末尾に引数を渡すと、CMD の内容だけが柔軟に上書きされます。

⑤ 実践ハンズオン:ASP.NET Core Web API のコンテナ化

それでは、実際にコマンドを叩いて、C# Web APIプロジェクトを作成し、コンテナイメージをビルドして起動してみましょう!

C# Web API ビルドフロー
▲ 【図解④】dotnet publish から docker build、そしてコンテナ起動への完全フロー

Step 1: ASP.NET Core Web API プロジェクトの作成と発行

ターミナル(PowerShell等)で新しいWeb APIプロジェクトを作成し、Releaseビルドで発行(publish)します。

# 1. 任意の作業ディレクトリへ移動し、Web APIを作成
dotnet new webapi -n MyWebApi -o MyWebApi
cd MyWebApi

# 2. Releaseモードでビルド&発行(成果物を ./publish フォルダへ出力)
dotnet publish -c Release -o ./publish

Step 2: リポジトリ直下に Dockerfile を作成

プロジェクトのルートディレクトリ(MyWebApi/ 直下)に、拡張子のない Dockerfile という名前のファイルを新規作成します。

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY ./publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyWebApi.dll"]

Step 3: docker build によるイメージ作成

docker build コマンドを実行して、Dockerfileからコンテナイメージをビルドします。

# -t はイメージのタグ(名前:バージョン)。末尾の「 . 」はビルドコンテキスト(カレントディレクトリ)
docker build -t my-webapi:v1 .

ビルドが完了したら、docker images で確認してみましょう。my-webapi:v1 という名前で約200MB前後の軽量イメージが完成しているはずです!

Step 4: コンテナの起動とアクセス確認

作成したイメージをバックグラウンド(-d)で起動し、ホストPCのポート8080をコンテナのポート8080へバインドします。

# コンテナ起動
docker run -d -p 8080:8080 --name my-webapi-app my-webapi:v1

# 稼働ステータス確認
docker ps

ブラウザで http://localhost:8080/weatherforecast にアクセスするか、PowerShellで Invoke-RestMethod http://localhost:8080/weatherforecast を実行してみましょう!
C#のコントローラーからJSON形式の天気予報データが即座に返却されれば、コンテナ化は大成功です!🎉

⑥ Git連携とIaCの黄金ルール(.dockerignoreの必須設定)

完成したDockerfileは、必ずC#ソースコードと一緒にGitでコミットします。
しかし、ここでベテランが必ず同時に用意しなければならない超重要ファイルがあります。それが .dockerignore です!

# .dockerignore ファイル
**/.git
**/.vs
**/bin
**/obj
💡 なぜ .dockerignore が不可欠なのか?

docker build を実行する際、Docker CLIは指定されたディレクトリ配下の全ファイルを「ビルドコンテキスト」としてDockerデーモンへ転送します。
.dockerignore を書かないと、開発環境の肥大化した bin/ や obj/、Visual Studioの一時ファイル(.vs)まで丸ごと転送されてしまい、ビルド速度が大幅に低下するだけでなく、意図しないキャッシュ汚染を引き起こします。Gitの .gitignore とセットで必ず配置しましょう!

⑦ ベテランがハマる落とし穴とベストプラクティス

罠① ポート番号の不一致(.NET 8の8080変更問題)
.NET 7以前のASP.NET Coreコンテナはデフォルトでポート80を使用していましたが、.NET 8以降は非rootユーザー実行のセキュリティ標準化に伴い「ポート8080」が標準になりました。
旧来の感覚で -p 80:80 とマッピングするとブラウザからアクセスできないため、-p 8080:8080(またはホストポートを任意の番号にして -p 5000:8080)と指定しましょう。

罠② WORKDIR を設定せずに直下に展開してしまう
WORKDIR /app を書かずに COPY . / などとしてしまうと、Linuxコンテナのルートファイルシステム上にDLLや設定ファイルが散らばり、OSのシステムディレクトリを汚損する原因になります。作業ディレクトリの明示は必須です。

罠③ Debugビルド成果物をそのままコンテナに入れてしまう
dotnet build 直後の bin/Debug フォルダはシンボルファイルや最適化されていないアセンブリで膨れ上がっています。本番向けイメージには、必ず dotnet publish -c Release で最適化・トリミングされたクリーンな成果物を投入してください。

📌 本日のまとめ & 明日へのステップ
  • Dockerfile はコンテナの設計図であり、IISの仮想ディレクトリやアプリプールの手動構築を完全にコード化(IaC)する。
  • 基本構文の5大命令:FROM(土台)、WORKDIR(作業場所)、COPY(成果物配置)、EXPOSE(ポート宣言)、ENTRYPOINT(起動コマンド)。
  • ENTRYPOINT はコンテナの固定役割(dotnet)、CMD は可変引数のデフォルト値として使い分けるのが鉄則。
  • docker build -t my-image:tag . でイメージを生成し、docker run -d -p 8080:8080 で即座にWeb APIを起動できる。
  • Dockerfileと .dockerignore はC#ソースコードと一緒にGitリポジトリへコミットし、チーム全員で環境を共有する。
次回【Day 17】予告:
『マルチステージビルドの魔術』〜SDKとRuntimeを分離し、コンテナイメージを劇的に軽量化&安全化するプロの技〜

コメント

このブログの人気の投稿

【Perfume】Perfume 3rd Tour 「JPN」さいたまスーパーアリーナに行って参りました~

Perfume 3rd Tour 「JPN」1月28日、29日の2daysで参戦して参りました。 ファンクラブ会員の選考抽選会に28日、29日の両日で申し込んでいたんですが、両方とも当選していたという嬉しい誤算。 仕事だぁ、なんだかんだと紆余曲折ありまして28日の参戦は危ぶまれていたのですが、なんとかかんとか28日は40分遅刻しながらも参戦、29日はフル参戦する事が出来ました(∩´∀`)∩

Perfume、2025年末で“コールドスリープ(活動休止)”へ──東京ドーム2daysの記録と、公式・各界・ファンの声

  1) 公式発表・基本情報 活動休止(コールドスリープ)を正式発表 2025年9月21日、公式サイト「 Perfumeより 」で、2026年から一度コールドスリープに入ると発表。再始動の意思(“新しいPerfume”として戻る)も明記。 Perfume Official Site 今後の運用告知(配信・上映など) 同21日付の「 今後のPerfumeに関して 」で、9/23(火・祝)東京ドーム公演の LIVESHIP全世界生配信 および 全国ディレイビューイング 決定を案内。特設サイトも併記。 Perfume Official Site +1 公式グッズ **「Perfume Calendar 2026」**発売決定(B2壁掛け/表紙+2カ月1枚×6枚+ポスター)。テーマは“フルーツ”。 Perfume Official Site 2) 東京ドーム2days(9/22・23)要点 公演タイトル: ZO/Z5 Anniversary “ネビュラロマンス” Episode TOKYO DOME 。日程・開場/開演・会場・物販等の実務情報は特設で公開。 Perfume Official Site 9/23公演を世界配信(LIVESHIP) /ディレイビューイング実施。 Perfume Official Site 海外向け報道(英語)も「 indefinite hiatus 」として広く配信。 The Times of India 国内英字メディアも速報。 朝日新聞 3) 現地レポ( メリ爺 )から見える空気 あなたの現地記録(9/24公開)を、ファクトと現場情景の両面で反映: 両日参戦 。22日は アリーナ 、23日は 1階席から俯瞰 。前日の発表を受け、開演前のザワつき→MC後に“いつもの一体感”へ。開演は22日 18:45 頃。オープニングは**P³ツアー東京ドーム(2020/2)**と同趣向で“回収”の演出。 メリ爺のゲーム万歳 MC所感 :解散ではなく前向きな休止で不安を和らげる内容。 かしゆか の涙、 のっち の気丈さ、 あ〜ちゃん の思い出語り──3人の結束と「 また戻る 」約束が強く刻まれた。 メリ爺のゲーム万歳 体感時間 : “3時間弱”級のボリューム ながら“過去一...

ニンテンドースイッチでオンラインゲームを遊ぶには?

モンスターハンターライズが発売になって、家族でモンハン楽しみたい人が増えたみたいですね。 某ブログの検索キーワードを調べると、モンハンを家族でやるにはどうしたらいいのか?を調べている人が沢山いるのがわかります。 ※これでも一部  家族で協力するにはSwitch2台、ソフトも2つ購入する必要があります。 1台のスイッチでは遊べませんし、ソフト1つでも遊べません。 でも、1台のスイッチで別々アカウントがあれば交代で遊ぶこともできますよ。セーブデータもしっかり分かれます。 Switchのオンラインゲームを家族で遊ぶ方法については以下の記事にまとめてますのでよろしければ参考にしてみてくださいね。 家族でモンスターハンターライズDL版のオンラインプレーを楽しむ方法