This sample was initially created from the aspire-samples/volumemount sample. It uses the Docker Integration and the Aspire CLI in an Actions Workflow to create and publish the container image into GitHub Container Registry, and produces Docker Compose artifacts.
📖 New! Read the Aspire App Lifecycle Guide - Learn about the complete development → local deploy → release workflow using this sample.
This sample demonstrates how to use Aspire to orchestrate a multi-container application with persistent data storage and automated deployment to production. It showcases:
- Persistent SQL Server volumes - Database data persists across container restarts
- Persistent file storage volumes - User-uploaded images persist across container restarts
- Aspire Docker Integration - Seamless configuration and orchestration of containerized services
- GitHub Actions CI/CD - Automated building, publishing, and deploying using the Aspire CLI
- Identity management - ASP.NET Core Identity with SQL Server backend
- Blazor Server UI - Interactive web application for file uploads
To run this sample, first install the Aspire prerequisites and the Aspire CLI.
# Navigate to the project root folder
cd VolumeMount
# Start the application
aspire runAspire will auto-detect and run the AppHost. The console will display the dashboard URL with a login token:
info: Aspire.Hosting.DistributedApplication[0]
Aspire version: 13.1.0
Dashboard: http://localhost:18888/login?t=abc123xyz...
Alternately, you can use an editor like Visual Studio Code to start debugging via the AppHost.
Open the dashboard link and click the blazorweb resource URL to launch the app.
The AppHost.cs file in the VolumeMount.AppHost project is the heart of the Aspire orchestration. It demonstrates:
var compose = builder.AddDockerComposeEnvironment("volumemount-env")
.WithProperties(env => { env.DashboardEnabled = true; })
.ConfigureComposeFile(composeFile =>
{
// Define top-level volumes for sharing across services
composeFile.AddVolume(new Volume
{
Name = "volumemount-blazor-uploads",
Driver = "local"
});
});var endpoint = builder.AddParameter("registry-endpoint");
var repository = builder.AddParameter("registry-repository");
builder.AddContainerRegistry("container-registry", endpoint, repository);This configures the container registry (GitHub Container Registry in this case) where the BlazorWeb container image will be pushed during deployment.
var sqlPassword = builder.AddParameter("sqlserver-password", secret: true);
var sqlserver = builder.AddSqlServer("sqlserver", password: sqlPassword)
.WithDataVolume("volumemount-sqlserver-data")
.WithLifetime(ContainerLifetime.Persistent)
.WithHostPort(1433)
.WithEndpoint("tcp", e =>
{
e.Port = 1433;
e.TargetPort = 1433;
e.Protocol = ProtocolType.Tcp;
e.IsProxied = false;
e.IsExternal = true;
});Key Features:
WithDataVolume()- Mounts a named volume to/var/opt/mssqlto persist database filesWithLifetime(ContainerLifetime.Persistent)- Container stays running across app restartsWithEndpoint()withIsProxied = falseandIsExternal = true- Allows direct connection from SQL Server Management Studio (SSMS) even when Aspire isn't running
var blazorweb = builder.AddProject<Projects.VolumeMount_BlazorWeb>("blazorweb")
.WithExternalHttpEndpoints()
.WithReference(sqlDatabase)
.WaitFor(sqlDatabase)
.WithRemoteImageTag("latest")
.PublishAsDockerComposeService((resource, service) =>
{
// Mount volume for persistent file uploads
service.AddVolume(new Volume
{
Name = "volumemount-blazor-uploads",
Source = "volumemount-blazor-uploads",
Target = "/app/wwwroot/uploads",
Type = "volume",
ReadOnly = false
});
// Configure permissions for file uploads
service.User = "root";
service.Command = new List<string>
{
"/bin/sh", "-c",
"chown -R app:app /app/wwwroot/uploads && chmod -R 755 /app/wwwroot/uploads && exec su app -c 'dotnet /app/VolumeMount.BlazorWeb.dll'"
};
});Key Features:
WithRemoteImageTag("latest")- Tags the container image for pushing to registryPublishAsDockerComposeService()- Customizes the Docker Compose service definition- Volume mounting to
/app/wwwroot/uploads- Persists user-uploaded images - Permission management - Ensures the app user can write to the uploads directory
- Purpose: Stores SQL Server database files (
.mdf,.ldf) - Mount Point:
/var/opt/mssqlinside the container - Benefits:
- Database persists across container restarts
- No data loss when redeploying applications
- Allows database upgrades without data migration
- Purpose: Stores user-uploaded image files
- Mount Point:
/app/wwwroot/uploadsinside the container - Benefits:
- Uploaded images persist across container restarts
- Multiple container instances can share the same upload storage
- Files remain available after application updates
Aspire not only helps you set up, develop, and locally run distributed apps, it also helps you with local and production deployment and workflows. Read the Aspire App Lifecycle Guide to learn about the complete development → local deploy → release workflow using this sample.