container-publish について
.NET 10 SDKで.NETアプリをOCIコンテナイメージとして発行する方法をまとめたスキルです。MSBuildによる設定、イメージの種類、対象アーキテクチャ、Docker不要のアーカイブ出力を扱います。
主な機能
- 01dotnet publishによるOCIイメージ構築
- 02MSBuildプロパティでのイメージ設定
- 03chiseledなどのイメージ選択
- 04マルチアーキテクチャイメージの発行
- 05イメージのtarアーカイブ出力
活用シーン
- 01本番環境向けASP.NET Core APIのパッケージ化
- 02x64およびarm64イメージの発行
- 03CIスキャン用コンテナアーカイブの作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ codewithmukesh/ dotnet-claude-kit --skill container-publishインストール後、Claude Code で/container-publishを入力して読み込まれたか確認します。
詳細
コンテナーの発行(Dockerfile なし)
基本原則
- Dockerfile は不要です — .NET 10 SDK は
dotnet publish /t:PublishContainerから OCI 準拠のコンテナーイメージを直接ビルドします。作成や保守が必要な Dockerfile はありません。 - 本番環境では Chiseled イメージを使用します —
noble-chiseledベースイメージを使用します。シェルもパッケージマネージャーもなく、Linux コンポーネントは 100 個以上ではなく 7 個です。攻撃対象領域を最小限に抑えられます。 - デフォルトで非 root です — .NET 10 コンテナーイメージは自動的に
appユーザーとして実行されます。本番環境で root に変更しないでください。 - 構成は .csproj に記述します — すべてのコンテナー設定は MSBuild プロパティであり、プロジェクトとともにバージョン管理されます。別ファイルとの設定ずれもありません。
パターン
最小限のコンテナー発行
プロジェクトファイルを変更する必要はありません。そのまま発行します。
dotnet publish /t:PublishContainer --os linux --arch x64
これにより、デフォルトの aspnet:10.0 ベースイメージを使用したコンテナーイメージが、ローカルの Docker デーモンに作成されます。
本番環境向けの .csproj 構成
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ContainerRepository>mycompany/myapp-api</ContainerRepository>
<ContainerFamily>noble-chiseled</ContainerFamily>
</PropertyGroup>
<ItemGroup>
<ContainerPort Include="8080" Type="tcp" />
<ContainerEnvironmentVariable Include="ASPNETCORE_HTTP_PORTS" Value="8080" />
<ContainerEnvironmentVariable Include="DOTNET_EnableDiagnostics" Value="0" />
<ContainerLabel Include="org.opencontainers.image.vendor" Value="MyCompany" />
</ItemGroup>
</Project>
レジストリへの発行
まず docker login で認証し、レジストリを指定します。
# GitHub Container Registry
docker login ghcr.io
dotnet publish /t:PublishContainer --os linux --arch x64 \
-p ContainerRegistry=ghcr.io \
-p ContainerImageTag=1.0.0
# Azure Container Registry
az acr login --name myregistry
dotnet publish /t:PublishContainer --os linux --arch x64 \
-p ContainerRegistry=myregistry.azurecr.io
# Docker Hub (requires username prefix in repository)
dotnet publish /t:PublishContainer --os linux --arch x64 \
-p ContainerRegistry=docker.io \
-p ContainerRepository=myuser/myapp
マルチアーキテクチャイメージ
1 回の発行で、複数のプラットフォーム向けのイメージをビルドできます。
<PropertyGroup>
<RuntimeIdentifiers>linux-x64;linux-arm64</RuntimeIdentifiers>
<ContainerRuntimeIdentifiers>linux-x64;linux-arm64</ContainerRuntimeIdentifiers>
</PropertyGroup>
dotnet publish /t:PublishContainer
これにより OCI イメージインデックスが作成されます。レジストリが適切なアーキテクチャを自動的に提供します。
複数のタグ
# Bash — note the quoting for semicolons
dotnet publish /t:PublishContainer --os linux --arch x64 \
-p ContainerImageTags='"1.0.0;latest"'
または、プロジェクトファイルに記述します。
<ContainerImageTags>1.0.0;latest</ContainerImageTags>
tarball として保存(Docker 不要)
ビルドマシンにコンテナーランタイムは必要ありません。CI でのスキャンに便利です。
dotnet publish /t:PublishContainer --os linux --arch x64 \
-p ContainerArchiveOutputPath=./images/myapp.tar.gz
# Scan with Trivy before pushing
trivy image --input ./images/myapp.tar.gz
Chiseled イメージのバリエーション
| ContainerFamily | 用途 | シェル | サイズ |
|---|---|---|---|
| (デフォルト) | 汎用(Debian) | あり | 約 220 MB |
noble-chiseled | 本番環境向け(シェルなし) | なし | 約 110 MB |
noble-chiseled-extra | ローカライズ対応の本番環境向け(ICU) | なし | 約 120 MB |
alpine | 小さいサイズ、シェルあり | あり | 約 112 MB |
<ContainerFamily>noble-chiseled</ContainerFamily>
<ContainerFamily>noble-chiseled-extra</ContainerFamily>
Native AOT の場合、SDK は chiseled-aot を自動選択します。
<PublishAot>true</PublishAot>
GitHub Actions を使った CI/CD
jobs:
publish:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- uses: actions/checkout@v5
- uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.0.x'
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- run: |
dotnet publish src/MyApp.Api/MyApp.Api.csproj \
/t:PublishContainer --os linux --arch x64 \
-p ContainerRegistry=ghcr.io \
-p ContainerRepository=${{ github.repository_owner }}/myapp \
-p ContainerImageTag=${{ github.sha }}
アンチパターン
非推奨のプロパティ名を使用しないでください
<ContainerImageName>myapp</ContainerImageName>
<ContainerRepository>myapp</ContainerRepository>
PublishProfile=DefaultContainer を使用しないでください
# BAD — old approach, inconsistent across project types
dotnet publish -p:PublishProfile=DefaultContainer
# GOOD — use the MSBuild target directly
dotnet publish /t:PublishContainer
Linux をターゲットに指定し忘れないでください
# BAD on Windows — may produce a Windows container
dotnet publish /t:PublishContainer
# GOOD — explicitly target Linux
dotnet publish /t:PublishContainer --os linux --arch x64
プッシュ前の認証を省略しないでください
# BAD — fails with CONTAINER1013 error
dotnet publish /t:PublishContainer -p ContainerRegistry=ghcr.io
# GOOD — authenticate first
docker login ghcr.io
dotnet publish /t:PublishContainer -p ContainerRegistry=ghcr.io
OS パッケージが必要な場合に SDK による発行を使用しないでください
<ContainerBaseImage>myregistry/custom-base:1.0</ContainerBaseImage>
選択ガイド
| シナリオ | 推奨事項 |
|---|---|
| 標準的な ASP.NET Core API | noble-chiseled を使った SDK コンテナー発行 |
| Worker サービス/コンソールアプリ | SDK コンテナー発行(.NET 10 のネイティブサポート) |
| ネイティブ OS パッケージが必要 | Dockerfile(またはカスタムベースイメージと SDK による発行) |
| Azure Functions | Dockerfile(SDK による発行ではサポートされていません) |
| Docker デーモンのない CI | ContainerArchiveOutputPath を使った tarball 出力 |
| マルチアーキテクチャのデプロイ(x64 + arm64) | ContainerRuntimeIdentifiers プロパティ |
| 本番イメージのサイズ | noble-chiseled(約 110 MB)または Native AOT(約 10 MB) |
| ローカル開発 | dotnet publish /t:PublishContainer --os linux --arch x64 |
| レジストリへのプッシュ | ContainerRegistry + docker login |
コメント
Markdown 対応