문서Aspire 사용해 보기
문서사용해 보기

Add Dockerfiles to your app model

이 콘텐츠는 아직 번역되지 않았습니다.

With Aspire it’s possible to specify a Dockerfile to build when the AppHost is started using either the AddDockerfile or WithDockerfile extension methods.

These two methods serve different purposes:

  • AddDockerfile: Creates a new container resource from an existing Dockerfile. Use this when you want to add a custom containerized service to your app model.
  • WithDockerfile: Customizes an existing container resource (like a database or cache) to use a different Dockerfile. Use this when you want to modify the default container image for an Aspire component.

Both methods expect an existing Dockerfile in the specified context path—neither method creates a Dockerfile for you. To generate a Dockerfile from AppHost code instead, use the Dockerfile builder APIs or the Dockerfile factory APIs.

When to use AddDockerfile vs WithDockerfile

Section titled “When to use AddDockerfile vs WithDockerfile”

Choose the appropriate method based on your scenario:

Use AddDockerfile when:

  • You want to add a custom containerized service to your app model.
  • You have an existing Dockerfile for a custom application or service.
  • You need to create a new container resource that isn’t provided by Aspire components.

Use WithDockerfile when:

  • You want to customize an existing Aspire component (like PostgreSQL, Redis, etc.).
  • You need to replace the default container image with a custom one.
  • You want to maintain the strongly typed resource builder and its extension methods.
  • You have specific requirements that the default container image doesn’t meet.

In the following example the AddDockerfile extension method is used to specify a container by referencing the context path for the container build.

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const container: ContainerResource
container
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addDockerfile(name: string, contextPath: string, options?: {
dockerfilePath?: string;
stage?: string;
}): ContainerResource (+1 overload)

Adds a Dockerfile to the application model that can be treated like a container resource.

addDockerfile
(
"mycontainer", "relative/context/path");

Unless the context path argument is a rooted path the context path is interpreted as being relative to the AppHost project directory.

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 AppHost is deploying.

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const container: ContainerResource
container
= (await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.executionContext: PropertyAccessor<DistributedApplicationExecutionContext>

Execution context for this invocation of the AppHost.

executionContext
.
DistributedApplicationExecutionContext.isRunMode: () => Promise<boolean>

Returns true if the current operation is running.

isRunMode
())
? await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addDockerfile(name: string, contextPath: string, dockerfilePath?: string, stage?: string): ContainerResource (+1 overload)

Adds a Dockerfile to the application model that can be treated like a container resource.

addDockerfile
(
"mycontainer", "relative/context/path", "Dockerfile.debug")
: await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addDockerfile(name: string, contextPath: string, dockerfilePath?: string, stage?: string): ContainerResource (+1 overload)

Adds a Dockerfile to the application model that can be treated like a container resource.

addDockerfile
(
"mycontainer", "relative/context/path", "Dockerfile.release");

When using AddDockerfile the return value is an IResourceBuilder<ContainerResource>. Aspire includes many custom resource types that are derived from ContainerResource.

Using the WithDockerfile extension method it’s possible to take an existing Aspire component (like PostgreSQL, Redis, or SQL Server) and replace its default container image with a custom one built from your own Dockerfile. This allows you to continue using the strongly typed resource types and their specific extension methods while customizing the underlying container.

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const pgsql: PostgresServerResource
pgsql
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addPostgres(name: string, options?: {
userName?: string | ParameterResource;
password?: string | ParameterResource;
port?: number;
}): PostgresServerResource (+1 overload)

Adds a PostgreSQL resource to the application model. A container is used for local development.

addPostgres
("pgsql");
// This replaces the default PostgreSQL container image with a custom one
// built from your Dockerfile, while keeping PostgreSQL-specific functionality.
await
const pgsql: PostgresServerResource
pgsql
.
ContainerResource.withDockerfile(contextPath: string, options?: {
dockerfilePath?: string;
stage?: string;
} | undefined): PostgresServerResource (+1 overload)

Causes Aspire to build the specified container image from a Dockerfile.

withDockerfile
("path/to/context");
await
const pgsql: PostgresServerResource
pgsql
.
PostgresServerResource.withPgAdmin(options?: {
configureContainer?: ((obj: PgAdminContainerResource) => Promise<void>) | undefined;
containerName?: string;
} | undefined): PostgresServerResource (+1 overload)

Adds a pgAdmin 4 administration and development platform for PostgreSQL to the application model.

withPgAdmin
(); // Still works because it's still a PostgreSQL resource.

Use AddDockerfileBuilder or WithDockerfileBuilder when you need Aspire to generate a Dockerfile from AppHost code. These APIs are useful when the Dockerfile depends on AppHost configuration, when you want to compose Dockerfile fragments, or when you want to keep multi-stage image build logic near the resource definition.

AddDockerfileBuilder creates a new container resource and configures the generated Dockerfile in one step:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
import type { DockerfileBuilderCallbackContext } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const configureDockerfile = async (context: DockerfileBuilderCallbackContext) => {
const dockerfile = await context.builder();
await dockerfile
.from("node:22-alpine", { stageName: "build" })
.workDir("/app")
.copy("package*.json", "./")
.run("npm ci")
.copy(".", ".")
.run("npm run build");
await dockerfile
.from("nginx:alpine", { stageName: "runtime" })
.copyFrom("build", "/app/dist", "/usr/share/nginx/html")
.expose(80);
};
await builder.addDockerfileBuilder("frontend", "../frontend", configureDockerfile, {
stage: "runtime",
});
await builder.build().run();

WithDockerfileBuilder applies a generated Dockerfile to an existing container resource. The image name provided when the resource is created is replaced by the generated Dockerfile build during publish:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
import type { DockerfileBuilderCallbackContext } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const configureDockerfile = async (context: DockerfileBuilderCallbackContext) => {
const dockerfile = await context.builder();
await dockerfile
.from("nginx:alpine", { stageName: "runtime" })
.copy(".", "/usr/share/nginx/html")
.expose(80);
};
await builder
.addContainer("frontend", "nginx:alpine")
.withDockerfileBuilder("../frontend", configureDockerfile, {
stage: "runtime",
});
await builder.build().run();

Generate a Dockerfile with a factory function

Section titled “Generate a Dockerfile with a factory function”

Use AddDockerfileFactory or WithDockerfileFactory when you need to generate a Dockerfile as a string from AppHost code. Unlike the Dockerfile builder APIs that use a fluent API to compose Dockerfile instructions, the factory APIs let you return Dockerfile content directly as a string — useful when you already have string-based Dockerfile generation logic or want to construct content conditionally.

The factory callback receives a DockerfileFactoryContext parameter that provides access to the resource and DI services when needed.

AddDockerfileFactory creates a new container resource and configures the generated Dockerfile in one step:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const container = await builder.addDockerfileFactory("myapp", "../myapp", async () => `
FROM node:22-alpine
WORKDIR /app
COPY . .
RUN npm ci
EXPOSE 3000
CMD ["node", "server.js"]
`);
await builder.build().run();

WithDockerfileFactory applies a factory-generated Dockerfile to an existing container resource:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
await builder.addContainer("myapp", { image: "placeholder", tag: "latest" })
.withDockerfileFactory("../myapp", async () => `
FROM nginx:alpine
COPY dist/ /usr/share/nginx/html
EXPOSE 80
`);
await builder.build().run();

The WithBuildArg method can be used to pass arguments into the container image build.

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const container: ContainerResource
container
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addDockerfile(name: string, contextPath: string, options?: {
dockerfilePath?: string;
stage?: string;
}): ContainerResource (+1 overload)

Adds a Dockerfile to the application model that can be treated like a container resource.

addDockerfile
("mygoapp", "relative/context/path");
await
const container: ContainerResource
container
.
ContainerResource.withBuildArg(name: string, value: string | ParameterResource): ContainerResource

Adds a build argument when the container is built from a Dockerfile.

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.

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const goVersion: ParameterResource
goVersion
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addParameter(name: string, options?: {
value?: string;
publishValueAsDefault?: boolean;
secret?: boolean;
}): ParameterResource (+1 overload)

Adds a parameter resource

addParameter
("goversion");
const
const container: ContainerResource
container
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addDockerfile(name: string, contextPath: string, options?: {
dockerfilePath?: string;
stage?: string;
}): ContainerResource (+1 overload)

Adds a Dockerfile to the application model that can be treated like a container resource.

addDockerfile
("mygoapp", "relative/context/path");
await
const container: ContainerResource
container
.
ContainerResource.withBuildArg(name: string, value: string | ParameterResource): ContainerResource

Adds a build argument when the container is built from a Dockerfile.

withBuildArg
("GO_VERSION",
const goVersion: ParameterResource
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.

Dockerfile
# 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"]

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.

apphost.mts
import {
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
} from './.aspire/modules/aspire.mjs';
const
const builder: IDistributedApplicationBuilder
builder
= await
function createBuilder(): IDistributedApplicationBuilder

Creates a new distributed application builder

createBuilder
();
const
const accessToken: ParameterResource
accessToken
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addParameter(name: string, options?: {
value?: string;
publishValueAsDefault?: boolean;
secret?: boolean;
}): ParameterResource (+1 overload)

Adds a parameter resource

addParameter
("accesstoken", {
secret?: boolean | undefined
secret
: true });
const
const container: ContainerResource
container
= await
const builder: IDistributedApplicationBuilder
builder
.
IDistributedApplicationBuilder.addDockerfile(name: string, contextPath: string, options?: {
dockerfilePath?: string;
stage?: string;
}): ContainerResource (+1 overload)

Adds a Dockerfile to the application model that can be treated like a container resource.

addDockerfile
("myapp", "relative/context/path");
await
const container: ContainerResource
container
.
ContainerResource.withBuildSecret(name: string, value: string | ParameterResource): ContainerResource

Adds a secret build argument when the container is built from a Dockerfile.

withBuildSecret
("ACCESS_TOKEN",
const accessToken: ParameterResource
accessToken
);

For example, consider the RUN command in a Dockerfile which exposes the specified secret to the specific command:

Dockerfile
# The helloworld command can read the secret from /run/secrets/ACCESS_TOKEN
RUN --mount=type=secret,id=ACCESS_TOKEN helloworld