Chapter 9: Deploying Aspire apps to production
Introduces the move from local Aspire orchestration to production deployment and previews the chapter’s topics.
After this chapter you will be able to
- Deployment-specific host configuration. Explain why an Aspire host might run multiple service replicas or choose different services for local and deployed environments.
- Aspire replica configuration. Describe how the Aspire host configures multiple instances of a service, using the section's webfrontend example.
- Shared and individual addresses. Explain why replicas show the same endpoint URL in the dashboard and where to find each instance's own address.
- Local Azure SQL substitute. Explain why an Aspire app can use containerized SQL Server locally when it uses Azure SQL Server in Azure.
- Execution mode database selection. Describe how AppHost selects containerized SQL Server for local runs and Azure SQL for publishing, and what remains unchanged for hosted services.
- Migration tracking and ordering. Explain how Entity Framework migrations record schema changes so deployments apply only changes that have not already been applied.
- Automatic startup migration service. Describe how the API uses a registered background service to apply migrations on startup and seed data afterward without conflicting startup code.
- Dashboard command registration. Describe how the Redis reset operation is bound to the Aspire dashboard and enabled for the cache resource.
- Manifest generation and purpose. Explain that an Aspire manifest describes the application and its services in JSON and is the first step in publishing. Describe generating it from the Aspire host project folder and where the output file appears.
- Manifest structure and resource types. Describe the roles of the schema and resources elements, and distinguish the cache container resource from the apiservice project resource in the example.
- Aspire manifest deployment scope. Distinguish Aspire’s cloud-agnostic design from what its manifest alone can deploy at the time described: services to Azure Container Apps.
- Azure deployment workflow. Describe the deployment sequence: run the initial command in the Aspire host project folder and follow its prompts, log in to Azure, then run the deployment command after configuring Azure Container Apps.
- Visual Studio publishing workflow. Describe how to start an Aspire deployment from Visual Studio and select its Azure Container Apps destination, including the Azure Developer CLI prerequisite.
- Editable deployment files. Explain why someone might generate deployment files instead of relying on Aspire’s default in-memory deployment, and describe what `azd infra gen` produces.
- Resource group Bicep scope. Describe the edits the section calls for to scope the generated Bicep deployment to a resource group.
- Terraform cloud portability. Distinguish Terraform from Bicep in terms of cloud support.
- Direct manifest conversion workflow. Describe how Aspire.Terraform generates Terraform files directly from an Aspire manifest, including the order of the steps stated in the section.
- Aspire manifest conversion requirement. Explain why an Aspire manifest must be converted before deployment to Kubernetes and name the tool the section identifies for doing it.
- Aspir8 generation workflow. Describe how Aspir8 is installed and run from the Aspire App Host project folder, producing aspirate.json before converting the App Host manifest into Kubernetes deployment files.
- Kubernetes connection and verification. Describe how to configure kubectl for a specific Kubernetes cluster and verify the connection before deploying.
- Aspire resource deployment. Explain how kubectl deploys the generated Aspire resources and what role kustomization.yaml plays.
- CI/CD pipeline purpose and stages. Explain that a CI/CD pipeline can automate the end-to-end build and deployment process, potentially starting from a commit or pull request, and describe the kinds of checks and steps it can include.
- Azure Developer CLI preparation. Describe the common Azure Developer CLI steps given before building the pipelines: run `azd init` in the Aspire host project directory, run `azd login`, and optionally use `azd up` to check deployment.
- Pipeline creation and environments. Describe what the pipeline setup prompts for, where it creates the workflow file, and how that file can serve different deployment environments.
- Automated test gate. Explain why automated test steps should be added to the default pipeline and what happens when a test fails.
- Deployed environment variable access. Explain why a variable available to the pipeline needs an additional step before the Bicep templates and deployed application can use it.
- Azure DevOps pipeline scaffolding. Describe the prerequisites for creating an Azure DevOps pipeline from the Aspire host project directory and the files the step generates.
- Pipeline YAML customization. Describe how the generated Azure DevOps pipeline relates to a GitHub Actions workflow and how it can be adapted.
- Scaffolded Kubernetes pipeline YAML. Explain why it is useful to scaffold a pipeline for Kubernetes deployment and what to do with the generated YAML afterward.
What it builds on
- Host application startup and service registration (chapter 1) · Registering services in the host application
- Integrating with Azure SQL Server (chapter 3) · Earlier integration with Azure SQL Server
- Service discovery in Aspire (chapter 1) · Aspire service discovery
- Adding a Keycloak container to an Aspire host (chapter 2) · The AppHost configuration for the Keycloak container
- Using Entity Framework (chapter 3) · Use of Entity Framework with the SQL database
- Managing the Redis cache (chapter 7) · Prior work with managing the Redis cache.
Section by section
Introduction
Introduces the move from local Aspire orchestration to production deployment and previews the chapter’s topics.
9.1 Predeployment modifications of Aspire-hosted systems
The section explains why an Aspire-hosted system may need changes before deployment: scaling services, choosing environment-specific substitutes, updating database schemas, and handling backed-up message queues.
- Deployment-specific host configuration: Explain why an Aspire host might run multiple service replicas or choose different services for local and deployed environments.
Why it matters: These choices let the hosted system suit both expected production load and local development. - Deployment-time database migrations: Describe why a hosted database may need migrations and what Aspire can be configured to do when a new version is deployed.
Why it matters: Schema changes can be accounted for as part of deploying a new application version. - Dashboard queue-clearing command: Explain the message-queue problem that could motivate a custom Aspire dashboard command and what that command would do.
Why it matters: The dashboard can provide an operational action for queues that have become backed up.
Key terms: replicas, local substitutes, Aspire host, database migrations, schema, Aspire dashboard, custom command, message queues, message broker
9.1.1 Running multiple instances of a service
This section explains why services run multiple replicas, how to configure them in Aspire, and why those replicas share a dashboard endpoint.
- Purpose of service replicas: Explain why a distributed service might run multiple replicas and how requests reach them.
Why it matters: It explains the problem that running multiple instances is meant to solve. - Aspire replica configuration: Describe how the Aspire host configures multiple instances of a service, using the section's webfrontend example.
Why it matters: This is the configuration step that makes Aspire launch multiple service instances. - Shared and individual addresses: Explain why replicas show the same endpoint URL in the dashboard and where to find each instance's own address.
Why it matters: It resolves the apparent contradiction between separate replicas and identical dashboard URLs.
Key terms: scale out, replicas, load balancer, WithReplicas(), AppHost.cs, webfrontend, dashboard, front-facing addresses, logs, HTTP port
9.1.2 Running environment-specific services
Shows how to use a local substitute for an Azure-specific service and keep local-only AppHost configuration out of deployment scripts.
- Local Azure SQL substitute: Explain why an Aspire app can use containerized SQL Server locally when it uses Azure SQL Server in Azure.
Why it matters: A close local substitute lets you debug without needing the Azure-specific service on your machine. - Execution mode database selection: Describe how AppHost selects containerized SQL Server for local runs and Azure SQL for publishing, and what remains unchanged for hosted services.
Why it matters: The AppHost can choose the right database for each mode without requiring changes to its consumers. - Local-only AppHost guards: Explain why local-only AppHost configuration should use builder.ExecutionContext.IsRunMode rather than builder.Environment.IsDevelopment().
Why it matters: The run-mode guard prevents local configuration from being included in deployment infrastructure.
Key terms: Azure SQL Server, standard containerized version of SQL Server, AppHost, ExecutionContext, IsRunMode, IsPublishMode, AddAzureSqlServer(), service discovery, builder.Environment.IsDevelopment(), builder.ExecutionContext.IsRunMode
9.1.3 Managing database migrations
Explains how Entity Framework migrations track schema changes and how an Aspire-hosted API can apply them automatically on deployment.
- Migration tracking and ordering: Explain how Entity Framework migrations record schema changes so deployments apply only changes that have not already been applied.
Why it matters: This explains how schema updates can be repeated across deployments without repeating changes already made. - Migration generation prerequisites: Describe what must be in place to generate a migration and what the generated migration files represent.
Why it matters: These prerequisites let the API project generate schema changes that can later be applied on deployment. - EnsureCreated migration incompatibility: Explain why a database created with EnsureCreated() cannot be updated with migrations without manual modification.
Why it matters: It flags a database-creation choice that otherwise blocks the migration approach described here. - Automatic startup migration service: Describe how the API uses a registered background service to apply migrations on startup and seed data afterward without conflicting startup code.
Why it matters: It connects the prepared migrations to automatic schema updates on each deployment.
Key terms: database migrations, schema, migration, Microsoft.EntityFrameworkCore.Design, Entity Framework CLI tools, database context, entity type, Migrations folder, model snapshot, EnsureCreated()
9.1.4 Modifying the dashboard
This section shows how to add a Redis cache-reset command to the Aspire dashboard before deployment.
- Redis cache reset purpose: Explain why an application might need a dashboard command to reset its Redis cache.
Why it matters: The reason for the command helps explain why this dashboard customization is useful. - Dashboard command registration: Describe how the Redis reset operation is bound to the Aspire dashboard and enabled for the cache resource.
Why it matters: This connects the Redis operation to a command someone can invoke from the dashboard.
Key terms: Redis cache, distributed locks, cache invalidated, Redis, FLUSHALL, CommandOptions, WithCommand(), Redis cache resource
9.2 Preparing Aspire for deployment
This section introduces the Aspire manifest as the JSON description of an application used to begin publishing it.
- Manifest generation and purpose: Explain that an Aspire manifest describes the application and its services in JSON and is the first step in publishing. Describe generating it from the Aspire host project folder and where the output file appears.
Why it matters: The manifest is the application description used as the starting point for publishing. - Manifest structure and resource types: Describe the roles of the schema and resources elements, and distinguish the cache container resource from the apiservice project resource in the example.
Why it matters: Reading the resource definitions shows which services come from container images and which come from application projects.
Key terms: manifest files, manifest.json, --output-path, Aspire host project, schema, resources, cache, Redis, Docker image, container.v0
9.3 Deploying to Azure Container Apps
Introduces Azure Container Apps as the deployment target supported by the Aspire manifest alone and identifies the Azure Developer CLI as the tool to install before deploying.
- Aspire manifest deployment scope: Distinguish Aspire’s cloud-agnostic design from what its manifest alone can deploy at the time described: services to Azure Container Apps.
Why it matters: This distinction keeps the design goal from being mistaken for a deployment capability of the manifest alone. - Azure deployment tool prerequisite: State that deploying to Azure Container Apps requires installing the Azure Developer CLI first; the section points to installation instructions for Windows, Linux, and macOS but does not supply the commands in its text.
Why it matters: Installing the CLI is the prerequisite this section gives for the deployment steps that follow.
Key terms: cloud-agnostic, Aspire manifest, Azure Container Apps, Azure Developer CLI
9.3.1 Using the Azure Developer CLI
This subsection outlines the prompted Azure Developer CLI workflow for deploying an Aspire application to Azure Container Apps and identifies the files created during setup.
- Azure deployment workflow: Describe the deployment sequence: run the initial command in the Aspire host project folder and follow its prompts, log in to Azure, then run the deployment command after configuring Azure Container Apps.
Why it matters: The order of setup, login, and deployment makes the production deployment steps easier to follow. - Generated deployment files: Explain what the initial command creates and the stated purpose of each generated file.
Why it matters: These files provide the deployment configuration and guidance for the next commands.
Key terms: Aspire host project folder, Azure Container Apps, Azure environment, azure.yaml, next-steps.md
9.3.2 Deploying from Visual Studio
This subsection shows how to deploy an Aspire app to Azure Container Apps through Visual Studio while still using the Azure Developer CLI.
- Visual Studio publishing workflow: Describe how to start an Aspire deployment from Visual Studio and select its Azure Container Apps destination, including the Azure Developer CLI prerequisite.
Why it matters: You can deploy from Visual Studio without using the command line directly, as long as the required CLI is available.
Key terms: App Host project, Publish, Azure Container Apps, Azure Developer CLI
9.3.3 Obtaining the deployment files
This section shows how to generate editable Aspire deployment files and adjust their Bicep scripts when deployment must be scoped to an Azure resource group.
- Editable deployment files: Explain why someone might generate deployment files instead of relying on Aspire’s default in-memory deployment, and describe what `azd infra gen` produces.
Why it matters: Editable files let you adapt a deployment to the Azure permissions you actually have. - Resource group Bicep scope: Describe the edits the section calls for to scope the generated Bicep deployment to a resource group.
Why it matters: Changing both Bicep files and removing obsolete references keeps the generated deployment consistently scoped to the resource group.
Key terms: in-memory files, azd infra gen, infra, resource group, Bicep, main.bicep, resources.bicep, rg variable
9.4 Converting Aspire manifest to Terraform
This section introduces Terraform as a cloud-independent alternative to Bicep and outlines how to generate Terraform files from an Aspire manifest.
- Terraform cloud portability: Distinguish Terraform from Bicep in terms of cloud support.
Why it matters: Terraform provides an option when deployment is not limited to Azure. - Direct manifest conversion workflow: Describe how Aspire.Terraform generates Terraform files directly from an Aspire manifest, including the order of the steps stated in the section.
Why it matters: The direct route avoids making Bicep files as an intermediate step. - Generated output verification: Explain why the output of Aspire.Terraform should be verified.
Why it matters: Generated deployment files should not be assumed correct without inspection.
Key terms: Terraform, Bicep, GCP, AWS, Aspire.Terraform, Aspire manifest, Aspire host project folder, scaffold, verify the outputs
9.5 Converting Aspire manifest to Kubernetes
Introduces Kubernetes as a deployment target for Aspire apps and explains that Aspire manifests must be converted into a Kubernetes-readable format.
- Kubernetes deployment capabilities: Describe Kubernetes as a platform for deploying and managing containerized applications across a cluster, and give examples of the capabilities it provides.
Why it matters: These capabilities explain why Kubernetes is a possible production target for an Aspire app. - Aspire manifest conversion requirement: Explain why an Aspire manifest must be converted before deployment to Kubernetes and name the tool the section identifies for doing it.
Why it matters: The conversion connects Aspire's application description to a form Kubernetes can use for deployment.
Key terms: Kubernetes, pods, scaling, load balancing, self-healing, service discovery, Aspire manifests, Aspir8
9.5.1 Using Aspir8
This section shows how Aspir8 turns an Aspire App Host manifest into Kubernetes deployment files and identifies the generated output.
- Aspir8 generation workflow: Describe how Aspir8 is installed and run from the Aspire App Host project folder, producing aspirate.json before converting the App Host manifest into Kubernetes deployment files.
Why it matters: This sequence connects the Aspire manifest to the files needed for Kubernetes deployment. - Generated deployment file structure: Describe the aspirate-output folder, including the top-level dashboard and kustomization files and the per-service subfolders.
Why it matters: Recognizing the output hierarchy helps you find the dashboard configuration and each service’s Kubernetes files.
Key terms: Aspir8, Aspire App Host manifest, aspirate.json, Kubernetes deployment YAML files, aspirate-output, dashboard.yaml, kustomization.yaml, service subfolders
9.5.2 Deploying to a Kubernetes cluster
This section explains how to connect kubectl to a Kubernetes cluster, verify the connection, and deploy the generated Aspire resources.
- Kubernetes connection and verification: Describe how to configure kubectl for a specific Kubernetes cluster and verify the connection before deploying.
Why it matters: Checking the target cluster first helps avoid attempting deployment through an unverified connection. - Aspire resource deployment: Explain how kubectl deploys the generated Aspire resources and what role kustomization.yaml plays.
Why it matters: The generated files can be applied as one distributed-app deployment rather than resource by resource. - Deployment automation rationale: Justify putting deployment scripts into CI/CD pipelines rather than running them manually.
Why it matters: The manual deployment shown here is a step toward an automated deployment process.
Key terms: kubectl, Kubernetes cluster, Azure CLI, AWS CLI, gcloud CLI, nodes, apply, YAML files, aspirate-output, kustomization.yaml
9.6 Building CI/CD pipelines for Aspire
This section explains what CI/CD pipelines automate and identifies the Azure Developer CLI steps to take before building an Aspire deployment pipeline.
- CI/CD pipeline purpose and stages: Explain that a CI/CD pipeline can automate the end-to-end build and deployment process, potentially starting from a commit or pull request, and describe the kinds of checks and steps it can include.
Why it matters: It clarifies what work the deployment pipeline is meant to automate. - Azure Developer CLI preparation: Describe the common Azure Developer CLI steps given before building the pipelines: run `azd init` in the Aspire host project directory, run `azd login`, and optionally use `azd up` to check deployment.
Why it matters: These steps establish the configuration and Azure access needed before following the pipeline examples.
Key terms: CI/CD pipelines, commit, pull request (PR), prebuild checks, azd init, azd login, azd up, Aspire host project directory, AZD config files
9.6.1 Creating a GitHub Actions pipeline
This section explains how a generated GitHub Actions deployment pipeline can be configured for different environments and improved with tests, provisioning diagnostics, and application settings.
- Pipeline creation and environments: Describe what the pipeline setup prompts for, where it creates the workflow file, and how that file can serve different deployment environments.
Why it matters: You can adapt the generated workflow rather than build a separate pipeline from scratch for every environment. - Automated test gate: Explain why automated test steps should be added to the default pipeline and what happens when a test fails.
Why it matters: A deployment pipeline should catch changes that break tests instead of merely building and deploying them. - Provisioning scope and diagnostics: Describe the two provisioning-related pipeline adjustments discussed: scoping deployment and investigating provisioning failures.
Why it matters: These adjustments let you target the intended Azure scope and diagnose provisioning problems. - Deployed environment variable access: Explain why a variable available to the pipeline needs an additional step before the Bicep templates and deployed application can use it.
Why it matters: A setting present during a pipeline run is not necessarily available to the application that the pipeline deploys.
Key terms: GitHub Actions, azure-dev.yml, .github, workflows, environment variables, automated tests, build, pipeline, Bicep, Azure resource group
9.6.2 Creating an Azure DevOps pipeline
This section explains how to scaffold an Azure DevOps pipeline for an Aspire deployment and when the generated YAML needs manual configuration or customization.
- Azure DevOps pipeline scaffolding: Describe the prerequisites for creating an Azure DevOps pipeline from the Aspire host project directory and the files the step generates.
Why it matters: The generated YAML gives you a starting point for an Aspire deployment pipeline. - Repository hosting limitation: Explain what changes when an Azure DevOps pipeline uses a repository hosted outside Azure DevOps.
Why it matters: Repository location determines whether pipeline setup can be completed entirely through the CLI. - Pipeline YAML customization: Describe how the generated Azure DevOps pipeline relates to a GitHub Actions workflow and how it can be adapted.
Why it matters: The scaffolded pipeline is a starting point, not a fixed deployment workflow.
Key terms: AZD, Aspire host project directory, .azdo, azure-dev.yml, Azure DevOps, Git repo, CLI, YAML file, YAML, GitHub Actions workflow
9.6.3 Building pipelines for Kubernetes deployment
The section recommends scaffolding a Kubernetes deployment pipeline before manually adapting its YAML.
- Scaffolded Kubernetes pipeline YAML: Explain why it is useful to scaffold a pipeline for Kubernetes deployment and what to do with the generated YAML afterward.
Why it matters: Scaffolding gives you a starting point without requiring you to write the whole pipeline from scratch.
Key terms: scaffold, boilerplate YAML, Kubernetes
9.7 Summary
Where this is used later
- Reconfiguring the infrastructure components (chapter 10) · Running environment-specific services
Concepts explained in this chapter
- deployment pipelineA software delivery pipeline is an automated sequence of steps for building, testing, or deploying software.
- database migrationA database migration is a controlled change to a database schema or associated database objects across application versions.
- schemaA database schema is the structure and organization of a database, including its tables and fields.
- load balancingThe distribution of incoming traffic across multiple service instances or resources.
- BicepBicep is a declarative domain-specific language for deploying Azure resources through infrastructure-as-code templates.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
