Reputation: 73
I am looking for a way to programmatically scale up/down an Azure app service instance. This question has been asked before (e.g. in the link below) several months back and the answer was not possible at the time, so I am just wondering if something has changed and/or some new feature is available now.
Is possible to programmatically scale Azure instances?
Please note that we would like to do this on "Azure app services", not the old style "Azure cloud services".
The reason that we would like to do the scaling programmatically is so that we can control it using on our custom metrics. We did not find a way to publish our custom metrics to Azure and it can then be used by Azure to do the autoscaling either.
We did find that the Azure autoscale rule can accept an Azure storage queue length, so theoretically we can control the queue length by adding/removing messages to the queue, but it is kind of a hack and also it only works if the queue is created in the classic Azure web portal, not the new Azure portal.
Upvotes: 6
Views: 4552
Reputation: 1389
The C# package that @Tom Sun has provided in his answer has been deprecated, which is Microsoft.Azure.Management.WebSites, by clicking on it, it suggests you to use Azure.ResourceManager.AppService as an alternative.
here is a QuickStart and you can find more docs within the new package link.
I'll write a simple example in C# to scale up an existing app service plan within azure using an azure function app with http trigger :
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.Resources;
using Azure.Core.Diagnostics;
using Azure.ResourceManager.AppService;
namespace Company.Function
{
public class HttpTrigger1
{
private readonly ILogger<HttpTrigger1> _logger;
public HttpTrigger1(ILogger<HttpTrigger1> logger)
{
_logger = logger;
}
[Function("HttpTrigger1")]
public async Task<IActionResult> RunAsync([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req)
{
_logger.LogInformation("C# HTTP trigger function processed a request.");
//this is needed for authentication, you need to provide the following env vars:
// `AZURE_CLIENT_ID` `AZURE_TENANT_ID` `AZURE_CLIENT_SECRET`
// either in your `local.settings.json` or within azure env vars
ArmClient client = new ArmClient(new DefaultAzureCredential());
//this one for logs you can remove it
using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger();
try {
string resourceGroupName = "resource-group-where-your-app-reside";
string appServicePlanName = "your-appService-plan-name";
SubscriptionResource subscription = await client.GetDefaultSubscriptionAsync();
ResourceGroupCollection resourceGroups = subscription.GetResourceGroups();
ResourceGroupResource resourceGroup = await resourceGroups.GetAsync(resourceGroupName);
AppServicePlanCollection appServicePlans = resourceGroup.GetAppServicePlans();
AppServicePlanResource WebApiStagingWestAppServicePlan = resourceGroup.GetAppServicePlan(appServicePlanName);
//log AppServicePlan name and its SKU
_logger.LogInformation($"{WebApiStagingWestAppServicePlan.Data.Name}");
_logger.LogInformation($"{WebApiStagingWestAppServicePlan.Data.Sku.Name}");
AppServicePlanData appServicePlanData = WebApiStagingWestAppServicePlan.Data;
//update the appService Plan data with your desired SKU to scale up to
appServicePlanData.Sku.Name = "B2";
appServicePlanData.Sku.Tier = "Basic";
appServicePlanData.Sku.Size = "B2";
appServicePlanData.Sku.Family = "B";
appServicePlanData.Sku.Capacity = 1;
//and for the magic, scaling time
ArmOperation<AppServicePlanResource> operation = await appServicePlans.CreateOrUpdateAsync(Azure.WaitUntil.Completed, appServicePlanName, appServicePlanData);
_logger.LogInformation("App Service Plan SKU updated successfully.");
}
catch (Exception e)
{
_logger.LogInformation($"{e.Message}");
_logger.LogInformation("uWu");
throw;
}
return new OkObjectResult("Welcome to Azure Functions!");
}
}
}
and we are done, if you run it locally within your visual studio code, and clicked on the generated endpoint the existing app service plan will be scaled depending on the SKU data you provided.
just make sure to add the right credentials for azure service principal within your local.settings.json
as mentioned in the Docs, which are AZURE_CLIENT_ID
AZURE_TENANT_ID
AZURE_CLIENT_SECRET
.
Upvotes: 1
Reputation: 24569
Is it possible to scale Azure app services programmatically
Yes, we can do that use REST API or SDK. I test the REST API using the fiddler, details please refer to the snapshot, for how to get the authorization, please refer to the document.
Header info:
Body info:
If C# code is possible, please have a try to use
Microsoft.Azure.Management.WebSites to scale Azure app services. More detail info about SDK please refer to the packages.config file.
How to registry Azure AD App and how to get Application ID, secretKey and tenantId please refer to the document. The following is the demo code.
var subscriptionId = "Your subscrption";
var appId = "Registried Azure Application Id";
var secretKey = "Secret Key";
var tenantId = "tenant Id";
var resourceGroup = "resource group name";
var servicePlanName = "service plan name";
var context = new AuthenticationContext("https://login.windows.net/" + tenantId);
ClientCredential clientCredential = new ClientCredential(appId, secretKey);
var tokenResponse = context.AcquireTokenAsync("https://management.azure.com/", clientCredential).Result;
var accessToken = tokenResponse.AccessToken;
TokenCredentials credential = new TokenCredentials(accessToken);
var webSiteManagementClient = new Microsoft.Azure.Management.WebSites.WebSiteManagementClient(credential);
webSiteManagementClient.SubscriptionId = subscriptionId;
var servicePlan = webSiteManagementClient.AppServicePlans.ListByResourceGroupWithHttpMessagesAsync(resourceGroup).Result.Body.Where(x=>x.Name.Equals(servicePlanName)).FirstOrDefault();
//scale up/down
servicePlan.Sku.Family = "P";
servicePlan.Sku.Name = "P1";
servicePlan.Sku.Size = "P1";
servicePlan.Sku.Tier = "Premium";
servicePlan.Sku.Capacity = 2; // scale out: number of instances
var updateResult = webSiteManagementClient.AppServicePlans.CreateOrUpdateWithHttpMessagesAsync(resourceGroup, servicePlanName, servicePlan).Result;
packages.config file:
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Azure.Management.Websites" version="1.6.0-preview" targetFramework="net462" />
<package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="3.13.8" targetFramework="net462" />
<package id="Microsoft.Rest.ClientRuntime" version="2.3.5" targetFramework="net462" />
<package id="Microsoft.Rest.ClientRuntime.Azure" version="3.3.5" targetFramework="net462" />
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net462" />
</packages>
Check the result from the portal.
Note: If the Azure Service plan is updated, it will apply to all of WebApps in the Service plan.
Upvotes: 11