Enterprise-grade MSBuild integration for Docker containerization. Automatically generate Dockerfiles for .NET projects, customize with pre/post scripts, and integrate Docker build into your MSBuild pipeline. Zero manual steps, full CI/CD support, reproducible container builds. Generates optimized multi-stage Dockerfiles during dotnet build with support for custom entrypoints and build arguments.
$ dotnet add package JD.MSBuild.ContainersMSBuild tasks, targets, and props to integrate OCI containers with your .NET projects
Automate Docker containerization during dotnet build. Zero manual steps, full CI/CD support, reproducible container builds with granular control over every step of the process.
dotnet add package JD.MSBuild.Containers
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<!-- Enable Docker integration -->
<DockerEnabled>true</DockerEnabled>
<!-- Generate Dockerfile (default when DockerEnabled=true) -->
<DockerGenerateDockerfile>true</DockerGenerateDockerfile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JD.MSBuild.Containers" Version="*" />
</ItemGroup>
</Project>
Run dotnet build and a Dockerfile will be generated in your project directory.
<PropertyGroup>
<DockerEnabled>true</DockerEnabled>
<DockerGenerateDockerfile>true</DockerGenerateDockerfile>
<DockerBuildImage>true</DockerBuildImage>
<DockerBuildOnPublish>true</DockerBuildOnPublish>
</PropertyGroup>
Run dotnet publish to generate the Dockerfile and build the Docker image.
<PropertyGroup>
<DockerEnabled>true</DockerEnabled>
<!-- Don't generate, use existing Dockerfile -->
<DockerGenerateDockerfile>false</DockerGenerateDockerfile>
<!-- Build the image -->
<DockerBuildImage>true</DockerBuildImage>
<DockerBuildOnPublish>true</DockerBuildOnPublish>
<!-- Optional: specify custom Dockerfile location -->
<DockerfileSource>$(MSBuildProjectDirectory)\custom.Dockerfile</DockerfileSource>
</PropertyGroup>
JD.MSBuild.Containers is designed as a configurable OCI MSBuild shim integration. Every feature can be independently enabled or disabled:
docker build during MSBuild| Mode | Generate | Build | Use Case |
|---|---|---|---|
| Generate-Only | ✅ | ❌ | Review/commit Dockerfiles, manual builds |
| Build-Only | ❌ | ✅ | Use existing Dockerfiles, custom templates |
| Full Automation | ✅ | ✅ | Complete CI/CD, zero manual steps |
| Custom Hooks | ➖ | ➖ | Execute scripts only, manual everything else |
| Property | Default | Description |
|---|---|---|
DockerEnabled | false | Master switch for Docker integration |
DockerGenerateDockerfile | true (when enabled) | Controls Dockerfile generation |
DockerBuildImage | false | Controls Docker image building |
DockerRunContainer | false | Controls container execution |
DockerPushImage | false | Controls pushing to registry |
| Property | Default | Description |
|---|---|---|
DockerGenerateOnBuild | true | Generate Dockerfile during Build |
DockerBuildOnBuild | false | Build image during Build |
DockerBuildOnPublish | true | Build image during Publish |
DockerRunOnBuild | false | Run container after Build |
DockerPushOnPublish | true | Push image after Publish |
| Property | Default | Description |
|---|---|---|
DockerPreBuildScript | - | Path to pre-build script |
DockerPostBuildScript | - | Path to post-build script |
DockerPrePublishScript | - | Path to pre-publish script |
DockerPostPublishScript | - | Path to post-publish script |
DockerExecutePreBuildScript | true (if script set) | Enable pre-build script |
DockerExecutePostBuildScript | true (if script set) | Enable post-build script |
DockerExecutePrePublishScript | true (if script set) | Enable pre-publish script |
DockerExecutePostPublishScript | true (if script set) | Enable post-publish script |
| Property | Default | Description |
|---|---|---|
DockerImageName | $(AssemblyName).ToLower() | Docker image name |
DockerImageTag | latest | Docker image tag |
DockerRegistry | - | Container registry URL |
DockerBaseImageRuntime | mcr.microsoft.com/dotnet/aspnet | Runtime base image |
DockerBaseImageSdk | mcr.microsoft.com/dotnet/sdk | SDK base image |
DockerBaseImageVersion | Auto-detected | Base image version |
| Property | Default | Description |
|---|---|---|
DockerBuildContext | $(MSBuildProjectDirectory) | Docker build context |
DockerBuildArgs | - | Additional build arguments |
DockerBuildPlatform | - | Target platform (e.g., linux/amd64) |
DockerBuildTarget | - | Target stage in multi-stage builds |
DockerUseMultiStage | true | Use multi-stage Dockerfiles |
DockerOptimizeLayers | true | Optimize Docker layers |
| Property | Default | Description |
|---|---|---|
DockerfileOutput | $(MSBuildProjectDirectory)\Dockerfile | Generated Dockerfile path |
DockerfileSource | $(MSBuildProjectDirectory)\Dockerfile | Existing Dockerfile path |
DockerOutput | $(BaseIntermediateOutputPath)docker\ | Build output directory |
DockerTemplateFile | - | Custom Dockerfile template |
| Property | Default | Description |
|---|---|---|
DockerUseFingerprinting | true | Enable incremental builds |
DockerLogVerbosity | minimal | Logging level (quiet/minimal/normal/detailed/diagnostic) |
DockerCommand | docker | Docker CLI command |
DockerProjectType | Auto-detected | Project type (console/library) |
DockerExposePort | 8080 (ASP.NET) | Exposed port |
DockerUser | app | Container user |
DockerCreateUser | true | Create non-root user |
Perfect for committing Dockerfiles to version control and reviewing before build:
<PropertyGroup>
<DockerEnabled>true</DockerEnabled>
<!-- DockerGenerateDockerfile defaults to true -->
<!-- DockerBuildImage defaults to false -->
</PropertyGroup>
dotnet build
# Dockerfile generated at ./Dockerfile
# No Docker image built
Use your own hand-crafted Dockerfile:
<PropertyGroup>
<DockerEnabled>true</DockerEnabled>
<DockerGenerateDockerfile>false</DockerGenerateDockerfile>
<DockerBuildImage>true</DockerBuildImage>
<DockerBuildOnPublish>true</DockerBuildOnPublish>
<!-- Optional: custom Dockerfile location -->
<DockerfileSource>$(MSBuildProjectDirectory)\deploy\Dockerfile</DockerfileSource>
</PropertyGroup>
dotnet publish
# Uses existing Dockerfile at ./deploy/Dockerfile
# Builds Docker image
Generate and build automatically:
<PropertyGroup>
<DockerEnabled>true</DockerEnabled>
<DockerGenerateDockerfile>true</DockerGenerateDockerfile>
<DockerBuildImage>true</DockerBuildImage>
<DockerBuildOnPublish>true</DockerBuildOnPublish>
<DockerImageName>myapp</DockerImageName>
<DockerImageTag>$(Version)</DockerImageTag>
<DockerRegistry>myregistry.azurecr.io</DockerRegistry>
</PropertyGroup>
dotnet publish
# Generates Dockerfile
# Builds image: myregistry.azurecr.io/myapp:1.0.0
<PropertyGroup>
<DockerEnabled>true</DockerEnabled>
<DockerGenerateDockerfile>true</DockerGenerateDockerfile>
<DockerBuildImage>true</DockerBuildImage>
<DockerBuildOnPublish>true</DockerBuildOnPublish>
<DockerPushImage>true</DockerPushImage>
<DockerPushOnPublish>true</DockerPushOnPublish>
<!-- Pre/Post scripts -->
<DockerPreBuildScript>$(MSBuildProjectDirectory)\scripts\pre-build.sh</DockerPreBuildScript>
<DockerPostPublishScript>$(MSBuildProjectDirectory)\scripts\deploy.ps1</DockerPostPublishScript>
<DockerRegistry>myregistry.azurecr.io</DockerRegistry>
<DockerImageName>myapp</DockerImageName>
<DockerImageTag>$(GitVersion_SemVer)</DockerImageTag>
</PropertyGroup>
<PropertyGroup>
<DockerEnabled>true</DockerEnabled>
<DockerGenerateDockerfile>true</DockerGenerateDockerfile>
<DockerBuildImage>true</DockerBuildImage>
<DockerBuildOnBuild>true</DockerBuildOnBuild>
<DockerRunContainer>true</DockerRunContainer>
<DockerRunOnBuild>true</DockerRunOnBuild>
<!-- Container configuration -->
<DockerPortMappings>8080:8080</DockerPortMappings>
<DockerEnvironmentVariables>ASPNETCORE_ENVIRONMENT=Development</DockerEnvironmentVariables>
<DockerVolumeMappings>$(MSBuildProjectDirectory)/data:/app/data</DockerVolumeMappings>
</PropertyGroup>
dotnet build
# Generates Dockerfile
# Builds image
# Starts container with port mappings
Execute only specific scripts:
<PropertyGroup>
<DockerEnabled>true</DockerEnabled>
<DockerGenerateDockerfile>true</DockerGenerateDockerfile>
<!-- Define scripts -->
<DockerPreBuildScript>$(MSBuildProjectDirectory)\scripts\setup.sh</DockerPreBuildScript>
<DockerPostBuildScript>$(MSBuildProjectDirectory)\scripts\cleanup.sh</DockerPostBuildScript>
<!-- Enable only pre-build script -->
<DockerExecutePreBuildScript>true</DockerExecutePreBuildScript>
<DockerExecutePostBuildScript>false</DockerExecutePostBuildScript>
</PropertyGroup>
JD.MSBuild.Containers provides extensibility points at every stage:
Build:
├─ BeforeDockerGeneration
├─ DockerResolveInputs
├─ DockerComputeFingerprint
├─ DockerGenerateDockerfile
├─ AfterDockerGeneration
├─ DockerExecutePreBuildScript
├─ BeforeDockerBuild
├─ DockerBuild
├─ AfterDockerBuild
├─ DockerExecutePostBuildScript
├─ BeforeDockerRun
├─ DockerRun
└─ AfterDockerRun
Publish:
├─ DockerExecutePrePublishScript
├─ DockerPublish (generates + builds)
├─ DockerExecutePostPublishScript
└─ DockerPushImage (if enabled)
Clean:
└─ DockerClean (removes generated files)
You can define custom targets that depend on or extend these hooks:
<Target Name="MyCustomPreBuild" BeforeTargets="DockerBuild">
<Message Text="Running custom logic before Docker build" Importance="high" />
</Target>
<Target Name="MyCustomPostBuild" AfterTargets="AfterDockerBuild">
<Message Text="Running custom logic after Docker build" Importance="high" />
</Target>
| Feature | JD.MSBuild.Containers | Built-in SDK | Docker Desktop |
|---|---|---|---|
| Auto-generate Dockerfiles | ✅ | ❌ | ❌ |
| Granular control | ✅ | ❌ | ❌ |
| Build-only mode | ✅ | ❌ | N/A |
| Generate-only mode | ✅ | N/A | N/A |
| Pre/Post scripts | ✅ | ❌ | ❌ |
| MSBuild integration | ✅ | Limited | ❌ |
| Incremental builds | ✅ | ❌ | ❌ |
| Custom templates | ✅ | ❌ | N/A |
| Multi-stage support | ✅ | ❌ | ✅ |
This project maintains comprehensive code coverage with automated reporting:
See CODE_COVERAGE.md for detailed configuration and usage.
Contributions are welcome! Please open an issue first to discuss changes.
This project is licensed under the MIT License. See LICENSE for details.