Add Dockerfiles to your .NET app model
With .NET Aspire it's possible to specify a Dockerfile to build when the app host is started using either the AddDockerfile or WithDockerfile extension methods.
Add a Dockerfile to the app model
In the following example the AddDockerfile extension method is used to specify a container by referencing the context path for the container build.
var builder = DistributedApplication.CreateBuilder(args);
var container = builder.AddDockerfile(
"mycontainer", "relative/context/path");
Unless the context path argument is a rooted path the context path is interpreted as being relative to the app host projects directory (where the AppHost *.csproj
folder is located).
By default the name of the Dockerfile which is used is Dockerfile
and is expected to be within the context path directory. It's possible to explicitly specify the Dockerfile name either as an absolute path or a relative path to the context path.
This is useful if you wish to modify the specific Dockerfile being used when running locally or when the app host is deploying.
var builder = DistributedApplication.CreateBuilder(args);
var container = builder.ExecutionContext.IsRunMode
? builder.AddDockerfile(
"mycontainer", "relative/context/path", "Dockerfile.debug")
: builder.AddDockerfile(
"mycontainer", "relative/context/path", "Dockerfile.release");
Customize existing container resources
When using AddDockerfile the return value is an IResourceBuilder<ContainerResource>
. .NET Aspire includes many custom resource types that are derived from ContainerResource.
Using the WithDockerfile extension method it's possible to continue using these strongly typed resource types and customize the underlying container that is used.
var builder = DistributedApplication.CreateBuilder(args);
var pgsql = builder.AddPostgres("pgsql")
.WithDockerfile("path/to/context")
.WithPgAdmin();
Pass build arguments
The WithBuildArg method can be used to pass arguments into the container image build.
var builder = DistributedApplication.CreateBuilder(args);
var container = builder.AddDockerfile("mygoapp", "relative/context/path")
.WithBuildArg("GO_VERSION", "1.22");
The value parameter on the WithBuildArg method can be a literal value (boolean
, string
, int
) or it can be a resource builder for a parameter resource. The following code replaces the GO_VERSION
with a parameter value that can be specified at deployment time.
var builder = DistributedApplication.CreateBuilder(args);
var goVersion = builder.AddParameter("goversion");
var container = builder.AddDockerfile("mygoapp", "relative/context/path")
.WithBuildArg("GO_VERSION", goVersion);
Build arguments correspond to the ARG
command in Dockerfiles. Expanding the preceding example, this is a multi-stage Dockerfile which specifies specific container image version to use as a parameter.
# Stage 1: Build the Go program
ARG GO_VERSION=1.22
FROM golang:${GO_VERSION} AS builder
WORKDIR /build
COPY . .
RUN go build mygoapp.go
# Stage 2: Run the Go program
FROM mcr.microsoft.com/cbl-mariner/base/core:2.0
WORKDIR /app
COPY --from=builder /build/mygoapp .
CMD ["./mygoapp"]
Note
Instead of hardcoding values into the container image, it's recommended to use environment variables for values that frequently change. This avoids the need to rebuild the container image whenever a change is required.
Pass build secrets
In addition to build arguments it's possible to specify build secrets using WithBuildSecret which are made selectively available to individual commands in the Dockerfile using the --mount=type=secret
syntax on RUN
commands.
var builder = DistributedApplication.CreateBuilder(args);
var accessToken = builder.AddParameter("accesstoken", secret: true);
var container = builder.AddDockerfile("myapp", "relative/context/path")
.WithBuildSecret("ACCESS_TOKEN", accessToken);
For example, consider the RUN
command in a Dockerfile which exposes the specified secret to the specific command:
# The helloworld command can read the secret from /run/secrets/ACCESS_TOKEN
RUN --mount=type=secret,id=ACCESS_TOKEN helloworld
Caution
Caution should be exercised when passing secrets in build environments. This is often done when using a token to retrieve dependencies from private repositories or feeds before a build. It is important to ensure that the injected secrets are not copied into the final or intermediate images.
.NET Aspire