いよいよ本日より「第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の新規デプロイといえば以下のような骨の折れる作業でした。
Windows Serverにログインし、IISマネージャーを開き、アプリケーションプールを作成して.NET CLRバージョンを選択し、仮想ディレクトリを掘って物理パスを割り当て、アクセス権限(IIS_IUSRS等)を設定する……。
どれだけ分厚いExcel手順書を作っても、作業者の操作ミスやサーバーごとの環境差異によって「開発機では動いたのにステージングサーバーでHTTP 500エラー」というトラブルが日常茶飯事でした。
しかしDockerの世界では、これらすべてのサーバー構築手順が「リポジトリ直下のたった1枚のテキストファイル(Dockerfile)」に凝縮されます!
OSの環境準備、フォルダ作成、成果物の配置、ポート開放、起動プロセスの定義まで、すべてが数行のコードとして記述され、Gitで厳格にバージョン管理されるのです。
📊 旧来のIIS手動構築 と 現代のDockerfileコード化 の対比表
③ Dockerfileの基本構造と5大必須命令
Dockerfileは、上から下に向かって1行ずつ実行される「コンテナイメージの組み立て指示書」です。
まずはASP.NET Core Web APIを動かすための最小構成のDockerfileを見てみましょう。
# 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(固定実行コマンド): コンテナの「主たる役割」を定義します。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プロジェクトを作成し、コンテナイメージをビルドして起動してみましょう!
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
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リポジトリへコミットし、チーム全員で環境を共有する。
『マルチステージビルドの魔術』〜SDKとRuntimeを分離し、コンテナイメージを劇的に軽量化&安全化するプロの技〜
コメント
コメントを投稿