Deploy and scale an Orleans app on Azure
In this quickstart, you deploy and scale an Orleans URL shortener app on Azure Container Apps. The app allows users to submit a full URL to the app, which returns a shortened version they can share with others to direct them to the original site. Orleans and Azure provide the scalability features necessary to host high traffic apps like URL shorteners. Orleans is also compatible with any other hosting service that supports .NET.
At the end of this quickstart, you have a scalable app running in Azure to provide URL shortener functionality. Along the way you learn to:
- Pull and Azure Developer CLI template
- Deploy an Orleans app to Azure
- Scale the app to multiple instances
Prerequisites
- An Azure account with an active subscription. Create an account for free.
- Azure Developer CLI
- .NET 8
- Docker
Get and deploy the sample application
The sample application is available as an Azure Developer CLI template. Through this quickstart; you pull the template application, deploy the template and sample code to Azure, change the template to implement your preferred persistence grain, deploy the necessary resources, and then deploy the final application.
Open a terminal in an empty directory.
Authenticate to the Azure Developer CLI using
azd auth login
. Follow the steps specified by the tool to authenticate to the CLI using your preferred Azure credentials.azd auth login
Get the sample application using the AZD template
orleans-url-shortener
and theazd init
command.azd init --template orleans-url-shortener
During initialization, configure a unique environment name.
Tip
The environment name will also be used as the target resource group name. For this quickstart, consider using
msdocs-orleans-url-shortener
.Deploy the Azure Cosmos DB for NoSQL account using
azd up
. The Bicep templates also deploy a sample web application.azd up
During the provisioning process, select your subscription and desired location. Wait for the provisioning and deployment process to complete. The process can take approximately five minutes.
Once the provisioning of your Azure resources is done, a URL to the running web application is included in the output.
Deploying services (azd deploy) (✓) Done: Deploying service web - Endpoint: <https://[container-app-sub-domain].azurecontainerapps.io> SUCCESS: Your application was provisioned and deployed to Azure in 5 minutes 0 seconds.
Use the URL in the console to navigate to your web application in the browser.
In the browser address bar, test the
shorten
endpoint by adding a URL path such as/shorten?url=https://www.microsoft.com
. The page should reload and provide a new URL with a shortened path at the end. Copy the new URL to your clipboard.{ "original": "https://www.microsoft.com", "shortened": "http://<container-app-name>.<deployment-name>.<region>.azurecontainerapps.io:<port>/go/<generated-id>" }
Paste the shortened URL into the address bar and press enter. The page should reload and redirect you to the URL you specified.
Deploy extra services
The original deployment only deployed the minimal services necessary to host the URL shortener app. To use an Azure data service for grain persistence, you must first configure the template to deploy your preferred service.
Using the terminal, run
azd env set
to configure theDEPLOY_AZURE_TABLE_STORAGE
environment variable to enable deployment of Azure Cosmos DB for NoSQL.azd env set DEPLOY_AZURE_TABLE_STORAGE true
Using the terminal, run
azd env set
to configure theDEPLOY_AZURE_COSMOS_DB_NOSQL
environment variable to enable deployment of Azure Cosmos DB for NoSQL.azd env set DEPLOY_AZURE_COSMOS_DB_NOSQL true
Run
azd provision
to redeploy your application architecture with the new configuration. Wait for the provisioning process to complete. The process can take approximately two minutes.azd provision
Tip
Alternatively, you can run
azd up
again which will both provision your architecture and redeploy your application.
Install NuGet packages
Prior to using the grain, you must install the corresponding Microsoft.Orleans.Clustering.*
and Microsoft.Orleans.Persistence.*
NuGet packages. These services are using role-based access control for passwordless authentication, so you must also import the Azure.Identity
NuGet package.
Change your current working directory to ./src/web/.
cd ./src/web
Import the
Azure.Identity
package from NuGet usingdotnet add package
.dotnet add package Azure.Identity --version 1.*
Import the
Microsoft.Orleans.Clustering.AzureStorage
andMicrosoft.Orleans.Persistence.AzureStorage
packages.NuGet package Clustering Microsoft.Orleans.Clustering.AzureStorage
Persistence Microsoft.Orleans.Persistence.AzureStorage
dotnet add package Microsoft.Orleans.Clustering.AzureStorage --version 8.* dotnet add package Microsoft.Orleans.Persistence.AzureStorage --version 8.*
Import the
Azure.Identity
package from NuGet usingdotnet add package
.dotnet add package Azure.Identity --version 1.*
Import the
Microsoft.Orleans.Clustering.Cosmos
andMicrosoft.Orleans.Persistence.Cosmos
packages.NuGet package Clustering Microsoft.Orleans.Clustering.Cosmos
Persistence Microsoft.Orleans.Persistence.Cosmos
dotnet add package Microsoft.Orleans.Clustering.Cosmos --version 8.* dotnet add package Microsoft.Orleans.Persistence.Cosmos --version 8.*
Configure and redeploy the sample app
The sample app is currently configured to create a localhost cluster and persist grains in-memory. When hosted in Azure, Orleans can be configured to use more scalable, centralized state using a data service in Azure.
Add the following
using
directives:using Azure.Identity; using Orleans.Configuration;
Find and remove the current
builder
configuration code in the src/web/Program.cs file.builder.Host.UseOrleans(static siloBuilder => { siloBuilder .UseLocalhostClustering() .AddMemoryGrainStorage("urls"); });
Replace the
builder
configuration with the example here, which implements these key concepts:- A conditional environment check is added to ensure the app runs properly in both local development and Azure hosted scenarios.
- The
UseAzureStorageClustering
method configures the Orleans cluster to use Azure Table Storage and authenticates using the DefaultAzureCredential class. - Use the
Configure
method to assign IDs for the Orleans cluster.- The
ClusterID
is a unique ID for the cluster that allows clients and silos to talk to one another. - The
ClusterID
can change across deployments. - The
ServiceID
is a unique ID for the application that is used internally by Orleans and should remain consistent across deployments.
- The
if (builder.Environment.IsDevelopment()) { builder.Host.UseOrleans(static siloBuilder => { siloBuilder .UseLocalhostClustering() .AddMemoryGrainStorage("urls"); }); } else { builder.Host.UseOrleans(siloBuilder => { var endpoint = new Uri(builder.Configuration["AZURE_TABLE_STORAGE_ENDPOINT"]!); var credential = new DefaultAzureCredential(); siloBuilder .UseAzureStorageClustering(options => { options.ConfigureTableServiceClient(endpoint, credential); }) .AddAzureTableGrainStorage(name: "urls", options => { options.ConfigureTableServiceClient(endpoint, credential); }) .Configure<ClusterOptions>(options => { options.ClusterId = "url-shortener"; options.ServiceId = "urls"; }); }); }
Replace the
builder
configuration with the example here, which implements these key concepts:- A conditional environment check is added to ensure the app runs properly in both local development and Azure hosted scenarios.
- The
UseCosmosClustering
method configures the Orleans cluster to use Azure Cosmos DB for NoSQL and authenticates using the DefaultAzureCredential class. - Use the
Configure
method to assign IDs for the Orleans cluster.- The
ClusterID
is a unique ID for the cluster that allows clients and silos to talk to one another. - The
ClusterID
can change across deployments. - The
ServiceID
is a unique ID for the application that is used internally by Orleans and should remain consistent across deployments.
- The
if (builder.Environment.IsDevelopment()) { builder.Host.UseOrleans(static siloBuilder => { siloBuilder .UseLocalhostClustering() .AddMemoryGrainStorage("urls"); }); } else { builder.Host.UseOrleans(siloBuilder => { var endpoint = builder.Configuration["AZURE_COSMOS_DB_NOSQL_ENDPOINT"]!; var credential = new DefaultAzureCredential(); siloBuilder .UseCosmosClustering(options => { options.ConfigureCosmosClient(endpoint, credential); }) .AddCosmosGrainStorage(name: "urls", options => { options.ConfigureCosmosClient(endpoint, credential); }) .Configure<ClusterOptions>(options => { options.ClusterId = "url-shortener"; options.ServiceId = "urls"; }); }); }
Run
azd deploy
to redeploy your application code as a Docker container. Wait for the deployment process to complete. The process can take approximately one minute.azd deploy
Tip
Alternatively, you can run
azd up
again which will both provision your architecture and redeploy your application.
Verify the app's behavior
Validate that your updated code works by using the deployed application again and checking to see where it stores data.
In the browser address bar, test the
shorten
endpoint again by adding a URL path such as/shorten?url=https://learn.microsoft.com/dotnet/orleans
. The page should reload and provide a new URL with a shortened path at the end. Copy the new URL to your clipboard.{ "original": "https://learn.microsoft.com/dotnet/orleans", "shortened": "http://<container-app-name>.<deployment-name>.<region>.azurecontainerapps.io:<port>/go/<generated-id>" }
Paste the shortened URL into the address bar and press enter. The page should reload and redirect you to the URL you specified.
Optionally, you can verify that the cluster and state data is stored as expected in the storage account you created.
In the Azure portal, navigate to the resource group that was deployed in this quickstart.
Important
The environment name specified earlier in this quickstart is also the target resource group name.
Navigate to the overview page of the Azure Storage account.
Within the navigation, select Storage browser.
Expand the Tables navigation item to discover two tables created by Orleans:
OrleansGrainState: This table stores the persistent state grain data used by the application to handle the URL redirects.
OrleansSiloInstances: This table tracks essential silo data for the Orleans cluster.
Select the OrleansGrainState table. The table holds a row entry for every URL redirect persisted by the app during your testing.
Navigate to the overview page of the Azure Cosmos DB for NoSQL account.
Within the navigation,select Data Explorer.
Observe the following containers you created earlier in this guide:
OrleansStorage: This table stores the persistent state grain data used by the application to handle the URL redirects.
OrleansCluster: This table tracks essential silo data for the Orleans cluster.
Scale the app
Orleans is designed for distributed applications. Even an app as simple as the URL shortener can benefit from the scalability of Orleans. You can scale and test your app across multiple instances using the following steps:
Navigate back to the resource group that was deployed in this quickstart.
Navigate to the overview page of the Azure Container Apps app.
Within the navigation, select Scale.
Select Edit and deploy, and then switch to the Scale tab.
Use the slider control to set the min and max replica values to 4. This value ensures the app is running on multiple instances.
Select Create to deploy the new revision.
After the deployment is finished, repeat the testing steps from the previous section. The app continues to work as expected across several instances and can now handle a higher number of requests.