「[[.NET 開発基盤部会 Wiki>http://dotnetdevelopmentinfrastructure.osscons.jp]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。

-[[戻る>Github上の成果物]]
-戻る([[Docker]] / [[.NET Core on Linux]] / [[Github上の成果物]])
--[[ASP.NET Coreをコンテナ化する際の設定ポリシー]]
--ASP.NET Coreをスクラッチでコンテナ化する際の手順

*目次 [#c0c09feb]
#contents

*概要 [#fcae2f60]
生成AIを活用しスクラッチでコンテナ化する際の手順をメモ

*詳細 [#t0574a42]
-ASP.NET Core アプリケーションのコンテナ化を[[ツール>https://techinfoofmicrosofttech.osscons.jp/index.php?Visual%20Studio%20Tools%20for%20Docker]]に頼らず手動で行う。
-[[コチラ>https://techinfoofmicrosofttech.osscons.jp/index.php?.NET%20Core%E3%81%AEDocker%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E5%8C%96]]を確認すると、むしろ手動でないと問題になりそう(開発用は仕込みが多過ぎる)。

**[[Dockerファイル]]の作成 [#x64bcbd0]
プロジェクト・ルートに Dockerfile を作成

***ソース [#ib9f9929]
 dockerfile# ビルドステージ
 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
 WORKDIR /src
 
 # プロジェクト・ファイルをコピーして依存関係を復元
 COPY ["MyApp.csproj", "."]
 RUN dotnet restore "./MyApp.csproj"
 
 # ソースコードをコピーしてビルド
 COPY . .
 RUN dotnet build "MyApp.csproj" -c Release -o /app/build
 
 # 発行ステージ
 FROM build AS publish
 RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish /p:UseAppHost=false
 
 # 実行ステージ(軽量イメージ)
 FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
 WORKDIR /app
 EXPOSE 8080
 COPY --from=publish /app/publish .
 ENTRYPOINT ["dotnet", "MyApp.dll"]

***解説 [#s1de94fb]
※ マルチステージ・ビルドという手法を使っている。

-ステージ1: build

--buildステージを初期化~
各種のSDKを含む開発用の重量級イメージ
 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build

--buildステージの「カレント・ディレクトリ」を設定
 WORKDIR /src

--初めに、プロジェクト・ファイルをコピーして依存関係を復元
 COPY ["MyApp.csproj", "."]
 RUN dotnet restore "./MyApp.csproj"

--次に、ソース全体をコピーしてReleaseビルド
 COPY . .
 RUN dotnet build "MyApp.csproj" -c Release -o /app/build

-ステージ2: publish

--publishはbuildステージを引き継ぐ
 FROM build AS publish

--/app/publish へ本番用の成果物を生成~
(/p:UseAppHost=false は、OS依存の実行ファイルを生成しない設定)
 RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish /p:UseAppHost=false

-ステージ3: final(実行用・軽量ステージ)

--finalステージを初期化~
SDKを含まないランタイム専用の軽量イメージ
 FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final

--コンテナ内の「カレント・ディレクトリ」を設定
 WORKDIR /app

--ポート公開
 EXPOSE 8080

--publishステージで作られた成果物だけを取り込む
 COPY --from=publish /app/publish .

--アプリ起動
 ENTRYPOINT ["dotnet", "MyApp.dll"]

※ COPYコマンドのポイント

-角括弧を使うと、JSON配列形式で、スペースを含むパスを正確に扱える。
--COPY My App/MyApp.csproj .
--COPY ["My App/MyApp.csproj", "."]

-左右のオペランド
--COPY <ホスト側(コピー元)> <コンテナ側(コピー先)>
--COPY --from=前ステージ名 <前ステージ側(コピー元)>  <現ステージ側(コピー先)>

**.dockerignoreの作成 [#q752a553]

***ソース [#w683e16a]
 **/bin/
 **/obj/
 **/out/
 .git/
 .vs/
 *.user

***解説 [#e390d627]
不要なファイルをビルドコンテキストから除外。

**[[Dockerコマンド]]で実行 [#g3e94584]

***準備 [#k5b5fc4e]
-Dockerfileをビルドし名称付与されたイメージを生成
 docker build -t myapp:latest .

-使用する場合は、[[Dockerコンポーズを定義>#bd5d88af]]する。

***実行 [#r6de27c8]
-[[Dockerコマンド]]によるコンテナ起動
 docker run -d -p 8080:8080 --name myapp myapp:latest

-[[Dockerコマンド]]によるコンテナ起動
 docker compose up -d

-ログ確認
 docker logs myapp

-コンテナに入る
 docker exec -it myapp /bin/bash

**[[Dockerコンポーズ]] [#bd5d88af]
プロジェクト・ルートに docker-compose.yml を作成

***例1 [#h0721ef4]
最も簡潔な例

 version: '3.8'
 
 services:
   ap:
     build:
       context: .
       dockerfile: Dockerfile
     ports:
       - "8080:8080"
     environment:
       - ASPNETCORE_ENVIRONMENT=Production
       - ConnectionStrings__Default=Server=db;Database=MyDb;...
     depends_on:
       - db
 
   db:
     image: mcr.microsoft.com/mssql/server:2022-latest
     environment:
       - SA_PASSWORD=YourPassword123!
       - ACCEPT_EULA=Y
     ports:
       - "1433:1433"

***例2 [#r5664ea1]
2つのファイルを使用する場合

-定義

--DB側
 version: '3.8'
 
 services:
   db:
     image: mcr.microsoft.com/mssql/server:2022-latest
     environment:
       - SA_PASSWORD=YourPassword123!
       - ACCEPT_EULA=Y
     ports:
       - "1433:1433"
     networks:
       - shared-net
 
 networks:
   shared-net:
     name: myapp-network  # 固定名を指定(server側から参照するため)
     driver: bridge
※ 各サービスは「参加する」ネットワークを指定し、末尾で、そのネットワークの「定義」する。~
※ driver: bridge は networks のデフォルト値なので、今回のケースでは書かなくても動作は同じ。

--AP側
 version: '3.8'
 
 services:
   ap:
     build:
       context: .
       dockerfile: Dockerfile
     ports:
       - "8080:8080"
     environment:
       - ASPNETCORE_ENVIRONMENT=Production
       - ConnectionStrings__Default=Server=db;Database=MyDb;...
     networks:
       - shared-net
 
 networks:
   shared-net:
     name: myapp-network  # db側と同じ名前を指定する。
     external: true       # 新規作成せず、既存を使う。
※ ファイルを跨いだ depends_on は使えないため削除する。

-起動・停止

--起動
 # 1. まずDBを起動
 docker compose -f docker-compose.db.yml up -d
 # 2. DBが準備できたらサーバーを起動
 docker compose -f docker-compose.server.yml up -d

--停止
 # 停止する場合(逆順)
 docker compose -f docker-compose.server.yml down
 docker compose -f docker-compose.db.yml down

※ ネットワークはコマンドで作成してファイル中は全て「external: true」にすると起動順は任意になる。
 docker network create --driver bridge shared-net


**ホストビルド方式 [#w5b2ba11]
-ホストビルド方式では、コンテナ内部ではなく、ホストOS(WindowsやLinux上)側でビルドした生成物をコンテナに詰める方式。
-ホストでpublishした内容をコンテナに詰める方式なので、プロジェクト出力以外は別途コピーする必要がある。
-Dockerfile中にビルド・スクリプトを長々書く必要がないので良い。非常にメジャーな構成。
-CI/CDパイプラインでも一度ビルド・サーバ(Linux)で全ビルドを行い、ソレをコンテナに詰める方が楽。
-発展系の方式として、ビルド・サーバ自体をコンテナ化して「環境のドリフト」を防ぐと言う方法もある。

***Dockerファイル [#a00f35e6]
 # 実行ステージ(軽量イメージのみ)
 FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
 WORKDIR /app
 EXPOSE 8080
 COPY ./publish .
 ENTRYPOINT ["dotnet", "MyApp.dll"]

***ビルド&イメージ作成の手順 [#z4d347d5]
-1. ホストでビルド・発行
 dotnet publish "MyApp.csproj" -c Release -o ./publish /p:UseAppHost=false

-2. Dockerイメージをビルド
 docker build -t myapp .

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS