Container files
Konten ini belum tersedia dalam bahasa Anda.
Aspire provides APIs to inject files and directories into containers, enabling you to configure containerized resources with custom configuration files, scripts, certificates, and other assets. There are two complementary APIs:
WithContainerFiles: Injects files into containers at development time when they start duringaspire run.PublishWithContainerFiles: Copies files from one resource’s container into another resource’s container as build artifacts at publish time duringaspire publish.
Inject files at development time
Section titled “Inject files at development time”The WithContainerFiles extension method creates or updates files and directories inside a container at a specified destination path. It supports three approaches depending on your needs: inline entries for declarative file definitions, a source path for copying from the host file system, and an async callback for dynamic file generation.
Inline entries
Section titled “Inline entries”Use the inline entries overload to declaratively define files and directories using ContainerFileSystemItem objects. This is useful when file contents are known at build time or can be expressed as string literals.
var builder = DistributedApplication.CreateBuilder(args);
builder.AddContainer("myapp", "myapp:latest") .WithContainerFiles("/app/config", [ new ContainerFile { Name = "appsettings.json", Contents = """ { "Logging": { "LogLevel": { "Default": "Information" } } } """ }, new ContainerDirectory { Name = "scripts", Entries = [ new ContainerFile { Name = "init.sh", Contents = "#!/bin/bash\necho 'Initializing...'", Mode = UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute } ] } ]);
builder.Build().Run();In the preceding example:
- A JSON configuration file is created at
/app/config/appsettings.jsonwith the specified contents. - A nested
scriptsdirectory is created at/app/config/scripts/containing an executable shell script.
Source path
Section titled “Source path”Use the source path overload to copy files from a directory on the host machine into the container. This is useful when you have existing configuration files or assets on disk.
var builder = DistributedApplication.CreateBuilder(args);
builder.AddContainer("myapp", "myapp:latest") .WithContainerFiles("/app/config", "./config-files");
builder.Build().Run();Unless the source path is a rooted (absolute) path, it’s interpreted as relative to the AppHost project directory. All files in the source directory are copied to the destination path in the container at startup.
Async callback
Section titled “Async callback”Use the callback overload to generate files dynamically when the container starts. The callback receives a ContainerFileSystemCallbackContext that provides access to the IServiceProvider and the resource’s IResource model, enabling you to resolve services or inspect the app model.
var builder = DistributedApplication.CreateBuilder(args);
builder.AddContainer("worker", "worker:latest") .WithContainerFiles("/app/config", async (context, cancellationToken) => { var config = new { MachineName = Environment.MachineName, Timestamp = DateTime.UtcNow };
return [ new ContainerFile { Name = "runtime-config.json", Contents = JsonSerializer.Serialize(config) } ]; });
builder.Build().Run();The callback is invoked each time the container starts, so the generated files always reflect the current state.
File types
Section titled “File types”The WithContainerFiles API uses a type hierarchy rooted at the abstract ContainerFileSystemItem class. Each type represents a different kind of file system entry.
ContainerFile
Section titled “ContainerFile”ContainerFile represents a standard file. Set either Contents (a string) or SourcePath (an absolute path on the host) to provide the file data — the two are mutually exclusive.
// File with inline contentsvar configYaml = new ContainerFile{ Name = "config.yaml", Contents = "key: value"};
// File sourced from the host file systemvar dataCsv = new ContainerFile{ Name = "data.csv", SourcePath = "/path/to/data.csv"};Set ContinueOnError to true to allow the container to start even if creating this particular file fails:
var optionalJson = new ContainerFile{ Name = "optional-config.json", Contents = "{}", ContinueOnError = true};ContainerDirectory
Section titled “ContainerDirectory”ContainerDirectory represents a directory that can contain nested ContainerFileSystemItem entries, allowing you to build arbitrary directory trees.
var certsDir = new ContainerDirectory{ Name = "certs", Entries = [ new ContainerFile { Name = "ca.pem", SourcePath = "/path/to/ca.pem" }, new ContainerDirectory { Name = "private", Entries = [ new ContainerFile { Name = "server.key", SourcePath = "/path/to/server.key", Mode = UnixFileMode.UserRead } ] } ]};You can also populate a ContainerDirectory from files on disk using the static GetFileSystemItemsFromPath method:
var assetsDir = new ContainerDirectory{ Name = "assets", Entries = ContainerDirectory.GetFileSystemItemsFromPath( "/path/to/assets", searchOptions: SearchOption.AllDirectories)};ContainerOpenSSLCertificateFile
Section titled “ContainerOpenSSLCertificateFile”ContainerOpenSSLCertificateFile represents a PEM-encoded public certificate. In addition to placing the certificate file in the container, Aspire automatically creates an OpenSSL-compatible symlink ([subject hash].[n]) in the same directory — equivalent to running openssl rehash. This enables containers that use OpenSSL for certificate validation to discover the certificate automatically.
builder.AddContainer("myapp", "myapp:latest") .WithContainerFiles("/certs", [ new ContainerOpenSSLCertificateFile { Name = "ca-cert.pem", Contents = pemCertificateString } ]);File permissions and ownership
Section titled “File permissions and ownership”All WithContainerFiles overloads accept optional parameters to control file ownership and permissions.
Owner and group
Section titled “Owner and group”The defaultOwner and defaultGroup parameters set the default UID and GID applied to all created files and directories. Both default to 0 (root) when not specified. You can override ownership on individual items using the Owner and Group properties on any ContainerFileSystemItem.
builder.AddContainer("myapp", "myapp:latest") .WithContainerFiles("/app/data", [ new ContainerFile { Name = "shared.txt", Contents = "shared data" }, new ContainerFile { Name = "user-only.txt", Contents = "private data", Owner = 1000, Group = 1000 } ], defaultOwner: 33, // www-data defaultGroup: 33);In this example, shared.txt inherits the default owner/group of 33, while user-only.txt overrides with UID/GID 1000.
The umask parameter controls default permissions by subtracting (masking) permission bits from the base defaults. Without an explicit Mode set on an item:
- Directories start with
0777(read/write/execute for all) and have the umask subtracted - Files start with
0666(read/write for all) and have the umask subtracted
The default umask is 0022, which results in:
- Directories:
0755(owner: rwx, group: r-x, others: r-x) - Files:
0644(owner: rw-, group: r—, others: r—)
You can set Mode directly on individual items to override the umask-based default:
builder.AddContainer("myapp", "myapp:latest") .WithContainerFiles("/app/scripts", [ new ContainerFile { Name = "run.sh", Contents = "#!/bin/bash\necho 'Running'", Mode = UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute } ], umask: UnixFileMode.OtherRead | UnixFileMode.OtherWrite | UnixFileMode.OtherExecute);Persistent containers
Section titled “Persistent containers”For containers with ContainerLifetime.Persistent, changing the contents of container file entries causes the container to be recreated. Ensure any data written through WithContainerFiles is idempotent for a given app model configuration to avoid unintended container restarts.
Inject files at publish time
Section titled “Inject files at publish time”The PublishWithContainerFiles method copies files from one resource’s container into another resource’s container during aspire publish. This is the preferred approach for injecting files into containers at publish time.
A key use case is embedding single-page application (SPA) or static JavaScript frontends into a reverse proxy or web server container for production deployment. During development, frontend apps like Vite or React typically run as standalone dev servers. In production, however, the compiled static assets are often served by a backend API or a dedicated web server like Nginx. PublishWithContainerFiles bridges this gap by copying the built frontend output into the serving container as part of the publish process — no manual file copying or multi-stage Dockerfile required.
Embed a frontend in a backend
Section titled “Embed a frontend in a backend”var builder = DistributedApplication.CreateBuilder(args);
var frontend = builder.AddViteApp("frontend", "../frontend");
var api = builder.AddProject<Projects.Api>("api") .PublishWithContainerFiles(frontend, "./wwwroot");
builder.Build().Run();In this example:
- The
frontendresource builds inside its container, producing compiled JavaScript, CSS, and HTML. - During publish, Aspire copies those files from the frontend container into the
apicontainer at./wwwroot. - The resulting
apicontainer includes both the API code and the frontend static assets, ready to serve the full application.
Serve a frontend from YARP
Section titled “Serve a frontend from YARP”You can also embed frontend assets into a dedicated reverse proxy container:
var builder = DistributedApplication.CreateBuilder(args);
var frontend = builder.AddViteApp("frontend", "../frontend");
var nginx = builder.AddYarp("gateway") .PublishWithStaticFiles(frontend);
builder.Build().Run();This produces a self-contained Nginx container that serves the frontend application, with no external volume mounts or runtime file copying needed.
PublishWithContainerFiles only applies in publish mode — it has no effect during aspire run. The destination resource must implement IContainerFilesDestinationResource (such as ProjectResource), and the source resource must implement IResourceWithContainerFiles.
Customize the source path
Section titled “Customize the source path”By default, the source resource exports files from its container based on its configured output paths. Use WithContainerFilesSource to specify which path inside the source container to copy from:
var frontend = builder.AddViteApp("frontend", "../frontend") .WithContainerFilesSource("/app/dist");
var api = builder.AddProject<Projects.Api>("api") .PublishWithContainerFiles(frontend, "./wwwroot");Use ClearContainerFilesSources to remove any previously configured source paths before adding new ones.