Container Publish

codewithmukesh/dotnet-claude-kit/skills/container-publish

by codewithmukesh23300897f4d1No license754 starsListed Oct 8, 2026Updated Oct 8, 2026Repository updated 2 months ago

Dockerfile-less containerization using the .NET 10 SDK container publishing feature. Covers MSBuild properties, chiseled images, multi-arch builds, and registry publishing — all without writing a Dockerfile. Load this skill when the user wants to containerize without a Dockerfile, or mentions "dotnet publish container", "PublishContainer", "ContainerRepository", "ContainerFamily", "chiseled", "distroless", "container publish", "SDK container", "no Dockerfile", or "containerize without Docker".

Instructions onlyDevOps & Cloud
AI-generated overview

Containerize .NET apps without a Dockerfile using the .NET 10 SDK container publishing feature.

What it does
Explains how to build OCI-compliant container images directly from dotnet publish /t:PublishContainer instead of writing a Dockerfile. It covers MSBuild container properties such as ContainerRepository, ContainerFamily and ContainerPort, chiseled and distroless base image variants, multi-architecture builds, multiple tags, tarball output, and publishing to registries like ghcr.io, Azure Container Registry and Docker Hub. It also lists anti-patterns and a decision guide for choosing between SDK publishing and a Dockerfile.
When to use it
Use when containerizing a .NET application without a Dockerfile, or when the user mentions dotnet publish container, PublishContainer, ContainerRepository, ContainerFamily, chiseled, distroless, or containerize without Docker. Also useful for setting up multi-arch image builds or registry pushes from CI. Not applicable to workloads the SDK cannot publish, such as Azure Functions or images needing native OS packages.
Requirements
No scripts are shipped; it is instructions only. Requires the .NET 10 SDK, and a Docker daemon or registry access for local image output and pushes. Registry publishing needs prior authentication such as docker login, az acr login, or a CI token; tarball output avoids needing a container runtime.

Container Publishing (No Dockerfile)

Core Principles

  1. No Dockerfile needed — The .NET 10 SDK builds OCI-compliant container images directly from dotnet publish /t:PublishContainer. No Dockerfile to write or maintain.
  2. Chiseled images for production — Use noble-chiseled base images: no shell, no package manager, 7 Linux components vs 100+. Smallest attack surface.
  3. Non-root by default — .NET 10 container images run as the app user automatically. Never override to root in production.
  4. Configuration in the .csproj — All container settings are MSBuild properties, versioned with your project. No separate files to drift.

Patterns

Minimal Container Publish

No project file changes needed. Just publish:

bash
dotnet publish /t:PublishContainer --os linux --arch x64

This creates a container image in your local Docker daemon using the default aspnet:10.0 base image.

Production-Ready .csproj Configuration

xml
<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>

Publishing to a Registry

Authenticate with docker login first, then specify the registry:

bash
# GitHub Container Registrydocker login ghcr.iodotnet publish /t:PublishContainer --os linux --arch x64 \    -p ContainerRegistry=ghcr.io \    -p ContainerImageTag=1.0.0
# Azure Container Registryaz acr login --name myregistrydotnet 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

Multi-Architecture Images

Build images for multiple platforms with a single publish:

xml
<PropertyGroup>    <RuntimeIdentifiers>linux-x64;linux-arm64</RuntimeIdentifiers>    <ContainerRuntimeIdentifiers>linux-x64;linux-arm64</ContainerRuntimeIdentifiers></PropertyGroup>
bash
dotnet publish /t:PublishContainer

This produces an OCI Image Index — registries serve the correct architecture automatically.

Multiple Tags

bash
# Bash — note the quoting for semicolonsdotnet publish /t:PublishContainer --os linux --arch x64 \    -p ContainerImageTags='"1.0.0;latest"'

Or in the project file:

xml
<ContainerImageTags>1.0.0;latest</ContainerImageTags>

Save as Tarball (No Docker Required)

No container runtime needed on the build machine. Useful for CI scanning:

bash
dotnet publish /t:PublishContainer --os linux --arch x64 \    -p ContainerArchiveOutputPath=./images/myapp.tar.gz
# Scan with Trivy before pushingtrivy image --input ./images/myapp.tar.gz

Chiseled Image Variants

ContainerFamilyUse CaseShellSize
(default)General purpose (Debian)Yes~220 MB
noble-chiseledProduction (no shell)No~110 MB
noble-chiseled-extraProduction with localization (ICU)No~120 MB
alpineSmall size, has shellYes~112 MB
xml
<!-- Standard chiseled (InvariantGlobalization=true) --><ContainerFamily>noble-chiseled</ContainerFamily>
<!-- Chiseled with ICU for localization --><ContainerFamily>noble-chiseled-extra</ContainerFamily>

For Native AOT, the SDK auto-selects chiseled-aot:

xml
<PublishAot>true</PublishAot><!-- SDK picks runtime-deps:10.0-noble-chiseled-aot automatically -->

CI/CD with GitHub Actions

yaml
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 }}

Anti-patterns

Don't Use the Deprecated Property Names

xml
<!-- BAD — ContainerImageName is deprecated --><ContainerImageName>myapp</ContainerImageName>
<!-- GOOD — use ContainerRepository --><ContainerRepository>myapp</ContainerRepository>

Don't Use PublishProfile=DefaultContainer

bash
# BAD — old approach, inconsistent across project typesdotnet publish -p:PublishProfile=DefaultContainer
# GOOD — use the MSBuild target directlydotnet publish /t:PublishContainer

Don't Forget to Target Linux

bash
# BAD on Windows — may produce a Windows containerdotnet publish /t:PublishContainer
# GOOD — explicitly target Linuxdotnet publish /t:PublishContainer --os linux --arch x64

Don't Skip Authentication Before Push

bash
# BAD — fails with CONTAINER1013 errordotnet publish /t:PublishContainer -p ContainerRegistry=ghcr.io
# GOOD — authenticate firstdocker login ghcr.iodotnet publish /t:PublishContainer -p ContainerRegistry=ghcr.io

Don't Use SDK Publishing When You Need OS Packages

xml
<!-- BAD — SDK container publish cannot run apt-get or install native packages --><!-- There is no RUN equivalent -->
<!-- GOOD — create a custom base image with a Dockerfile first, then reference it --><ContainerBaseImage>myregistry/custom-base:1.0</ContainerBaseImage>

Decision Guide

ScenarioRecommendation
Standard ASP.NET Core APISDK container publishing with noble-chiseled
Worker service / console appSDK container publishing (native .NET 10 support)
Needs native OS packagesDockerfile (or custom base image + SDK publishing)
Azure FunctionsDockerfile (not supported by SDK publishing)
CI without Docker daemonTarball output with ContainerArchiveOutputPath
Multi-arch deployment (x64 + arm64)ContainerRuntimeIdentifiers property
Production image sizenoble-chiseled (~110 MB) or Native AOT (~10 MB)
Local developmentdotnet publish /t:PublishContainer --os linux --arch x64
Registry pushContainerRegistry + docker login

Source and attribution

Source:codewithmukesh/dotnet-claude-kitinskills/container-publishat commit2330089

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal

More from codewithmukesh/dotnet-claude-kit

Wrap Up

codewithmukesh

Captures end-of-session work, pending tasks and learnings into a handoff file, and reloads it at session start.

Productivity & Workflow754updated 2 months ago

Workflow Mastery

codewithmukesh

Claude Code workflow mastery for .NET developers. Covers parallel execution with git worktrees, plan mode strategy, verification loops, auto-formatting hooks, permission setup for dotnet CLI, prompting techniques, subagent patterns, and context discipline — token budget management, MCP-first navigation, lazy loading, and subagent isolation — all adapted for the .NET ecosystem. Load this skill when setting up Claude Code for a .NET project, optimizing workflows, running parallel sessions, when context is running low or sessions feel sluggish, when exploring a large codebase efficiently, or when the user mentions "productivity", "workflow", "parallel", "worktree", "plan mode", "permissions", "hooks", "10x", "setup Claude Code", "speed up development", "context", "tokens", "budget", "running out of context", "too many files", or "large codebase". Inspired by tips from Boris Cherny (creator of Claude Code) and the Anthropic team.

Awaiting classification754updated 2 months ago

Vertical Slice

codewithmukesh

Guides .NET developers in structuring applications with Vertical Slice Architecture, covering feature folders, endpoint grouping and handler patterns.

Software Development754updated 2 months ago

Testing

codewithmukesh

Testing strategy for .NET 10 applications. Covers xUnit v3, WebApplicationFactory for integration tests, Testcontainers for real database testing, Verify for snapshot testing, and the AAA pattern. Load this skill when writing tests, setting up test infrastructure, reviewing test coverage, or when the user mentions "test", "xUnit", "WebApplicationFactory", "Testcontainers", "integration test", "unit test", "bUnit", "snapshot test", "Verify", "test coverage", "AAA pattern", "WireMock", or "FakeTimeProvider".

Awaiting classification754updated 2 months ago

Tdd

codewithmukesh

Guided test-driven development workflow for .NET 10 using xUnit v3, WebApplicationFactory, Testcontainers, and Verify snapshots. Follows the strict red-green-refactor cycle. Use when: "TDD", "test-driven", "let's TDD this", "red green refactor", "write the test first", or when building a feature with clear acceptance criteria.

Awaiting classification754updated 2 months ago

Spec

codewithmukesh

Turns a vague feature idea into an agreed, persisted specification file through structured questioning rounds.

Productivity & Workflow754updated 2 months ago
Container Publish · skills/container-publish Agent Skill | SourceWeft