Loading...

Migrate classic Cloud Service to CSES when SKU is unsupported without original project

Migrate classic Cloud Service to CSES when SKU is unsupported without original project

With the impending retirement of the classic Cloud Service (CS) on August 31st, 2024, an increasing number of users have initiated the migration of their classic Cloud Service to Cloud Service Extended Support (CSES). To facilitate this transition, an official feature known as in-place migration has been introduced, enabling the seamless migration of classic CS to CSES without incurring any downtime. However, certain limitations exist, with the VM size used by the CS role being a notable factor. As per documentation, the A-series, encompassing Small, Medium, and Large VM sizes, is no longer supported in CSES, necessitating their conversion to corresponding VM sizes as a preliminary step.

 

To apply a change in the VM size utilized in classic CS, a redeployment/upgrade is required subsequent to modifying the VM size in the .csdef file. While this is generally a straightforward operation, in cases where the project deployed in the classic CS is considerably dated, there is a possibility that the original project may be lost. Consequently, re-packaging the project into .cspkg and .cscfg files for redeployment/upgrade becomes unfeasible.

 

This blog will primarily address this specific scenario and outline strategies for resolving this predicament.

 

Pre-requirement:

  1. A healthy and running classic CS with project deployed in production slot. The used VM size of at least one role is A-series.

Running classic CS with unsupported SKU in CSESRunning classic CS with unsupported SKU in CSES

 

  1. A classic Storage Account under same subscription as classic CS. (The UI to create classic Storage Account in Azure Portal is already invisible because this resource type is supposed to be retired for new creation. But it’s still possible to use command to create it for now. Sample command like: New-AzResource -ResourceName <accountname> -ResourceGroupName <resourcegroupname> -ResourceType "Microsoft.ClassicStorage/StorageAccounts" -Location <location> -Properties @{ AccountType = "Standard_LRS" } -ApiVersion "2015-06-01")
  2. Install Az PowerShell module in local machine.

 

 

Attention! By following this way, a short downtime is unavoidable. If this needs to be applied on a production environment, please do the same test in another environment at first.

 

 

Details:

  1. Refer to New Deployment Based On Existing Classic Cloud Service - Microsoft Community Hub to get the .cspkg and .cscfg files at first. (Please remember to install the .pfx certificate in the machine where the Get Package request will be sent.)

 

The expected result is that the .cspkg and .cscfg files will be found in the classic storage account container. Please download them to local machine.

 

  1. (optional) If the new CSES needs to use same IP address as original classic CS, please follow these steps.
    1. Install legacy Azure PowerShell module
    2. Reserve current IP as reserved IP address

 

 

 

New-AzureReservedIP –ReservedIPName <reserved ip name> –Location <classic CS location> -ServiceName <classic CS name>

 

 

 

 

Reserve IP address resultReserve IP address result

 

 

The reserved IP address will be found in a resource group called Default-Networking.

Reserved IP addressReserved IP address

 

c. Cut down the association between reserved IP and classic CS.

After running this command, the classic CS IP address will be changed. If the application/client side is using IP address to connect to classic CS, it will start failing.

 

 

 

Remove-AzureReservedIPAssociation –ReservedIPName <reserved ip name> -ServiceName <classic CS name>

 

 

 

 

Remove association resultRemove association result

 

Reference of step b and c can be found here: Manage Azure reserved IP addresses (Classic) | Microsoft Learn

 

d. Refer to this document, convert the reserved IP address into a public IP address which can be used by CSES.

 

 

 

Move-AzureReservedIP -ReservedIPName <reserved IP name> -Validate Move-AzureReservedIP -ReservedIPName <reserved IP name> -Prepare Move-AzureReservedIP -ReservedIPName <reserved IP name> -Commit

 

 

 

Convert reserved IP to public IP addressConvert reserved IP to public IP address

 

After the command is finished, you will find the converted public IP in a resource group called <publicipaddress-name>-Migrated.

JerryZhangMS_4-1707463118918.png

 

3. By default the public IP address is without any domain name. If it’s needed, please configure it in Configuration page.

public IP address DNS name labelpublic IP address DNS name label

4. Move the public IP address to the same resource group where the new CSES resource will be created.

move public IP address to other resource groupmove public IP address to other resource group

 

 

  1. (optional) If the classic CS is using certificate, create a Key Vault resource in the same subscription and same region, then upload the certificate(s) into Key Vault, Certificates. For more information, please refer to here.
  2. Create a Virtual Network in the same resource group and same region as new CSES resource.
  3. Open the downloaded .cscfg file with any text editor and add/modify the NetworkConfiguration part:

 

 

<NetworkConfiguration> <VirtualNetworkSite name="xxx" /> <AddressAssignments> <InstanceAddress roleName="xxx"> <Subnets> <Subnet name="xxx" /> </Subnets> </InstanceAddress> </AddressAssignments> </NetworkConfiguration>

 

 

(optional) If the step 2 is followed, please also add ReservedIPs part.

 

 

<NetworkConfiguration> <VirtualNetworkSite name="xxx" /> <AddressAssignments> <InstanceAddress roleName="xxx"> <Subnets> <Subnet name="xxx" /> </Subnets> </InstanceAddress> <ReservedIPs> <ReservedIP name="xxx" /> </ReservedIPs> </AddressAssignments> </NetworkConfiguration>

 

 

 

modified .cscfg filemodified .cscfg file

 

After modifying the .cscfg file, please upload the .cscfg and .cspkg file into a storage account, blob container, then generate and note down the SAS URL of these two files.

  1. If the step 2 is not followed, please manually create a public IP address with Basic sku and static IP address assignment mode.
  2. To create the new CSES resource, there are two possible ways: Using PowerShell command and using ARM template. The key point is to use the SKU override feature to replace the VM size setting in the .csdef file. (Attention! Since the VM size configured inside of the .csdef file is still the unsupported VM size, please remember to use the override SKU feature in ARM template or PowerShell command every time in the future as well. Otherwise the deployment/upgrade will be failed.
    • Using PowerShell script:

If the Key Vault is not used, remove the first $osProfile part and the last OSProfile parameter of New-AzCloudService command.

 

 

 

$keyVault = Get-AzKeyVault -ResourceGroupName <key vault resource group> -VaultName <key vault resource name> $certificate = Get-AzKeyVaultCertificate -VaultName <key vault resource name> -Name <certificate name in Key Vault> $secretGroup = New-AzCloudServiceVaultSecretGroupObject -Id $keyVault.ResourceId -CertificateUrl $certificate.SecretId $osProfile = @{secret = @($secretGroup)} $cspkgSAS = <SAS URL of cspkg file> $cscfgSAS = <SAS URL of cscfg file> $role1 = New-AzCloudServiceRoleProfilePropertiesObject -Name <Role1 name> -SkuName <new supported vm size> -SkuTier 'Standard' -SkuCapacity <instance number> $role2 = New-AzCloudServiceRoleProfilePropertiesObject -Name <Role2 name> -SkuName <new supported vm size> -SkuTier 'Standard' -SkuCapacity <instance number> $roleProfile = @{role = @($role1, $role2)} $publicIP = Get-AzPublicIpAddress -ResourceGroupName <public IP resource group> -Name <public IP name> $feIpConfig = New-AzCloudServiceLoadBalancerFrontendIPConfigurationObject -Name <frontend IP config name> -PublicIPAddressId $publicIP.Id $loadBalancerConfig = New-AzCloudServiceLoadBalancerConfigurationObject -Name <load balancer config> -FrontendIPConfiguration $feIpConfig $networkProfile = @{loadBalancerConfiguration = $loadBalancerConfig} # Create Cloud Service New-AzCloudService -Name <CSES name> -ResourceGroupName <resource group name> -Location <CSES Location> -AllowModelOverride -PackageUrl $cspkgSAS -ConfigurationUrl $cscfgSAS -UpgradeMode 'Auto' -RoleProfile $roleProfile -NetworkProfile $networkProfile -OSProfile $osProfile

 

 

 

  • Using ARM template:

If Key Vault is not used, remember to remove the secrets in osprofile, keep it empty as

"osProfile": {}, remove secrets parameter part in template file and remove secrets parameter from parameter file.

 

Template file:

 

 

{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "cloudServiceName": { "type": "string", "metadata": { "description": "Name of the cloud service" } }, "location": { "type": "string", "metadata": { "description": "Location of the cloud service" } }, "deploymentLabel": { "type": "string", "metadata": { "description": "Label of the deployment" } }, "packageSasUri": { "type": "securestring", "metadata": { "description": "SAS Uri of the CSPKG file to deploy" } }, "configurationSasUri": { "type": "securestring", "metadata": { "description": "SAS Uri of the service configuration (.cscfg)" } }, "roles": { "type": "array", "metadata": { "description": "Roles created in the cloud service application" } }, "publicIPName": { "type": "string", "defaultValue": "contosocsIP", "metadata": { "description": "Name of public IP address" } }, "upgradeMode": { "type": "string", "defaultValue": "Auto", "metadata": { "UpgradeMode": "UpgradeMode of the CloudService" } }, "secrets": { "type": "array", "metadata": { "description": "The key vault id and certificates referenced in the .cscfg file" } } }, "variables": { "cloudServiceName": "[parameters('cloudServiceName')]", "subscriptionID": "[subscription().subscriptionId]", "lbName": "[concat(variables('cloudServiceName'), 'LB')]", "lbFEName": "[concat(variables('cloudServiceName'), 'LBFE')]", "resourcePrefix": "[concat('/subscriptions/', variables('subscriptionID'), '/resourceGroups/', resourceGroup().name, '/providers/')]" }, "resources": [ { "apiVersion": "2020-10-01-preview", "type": "Microsoft.Compute/cloudServices", "name": "[variables('cloudServiceName')]", "location": "[parameters('location')]", "tags": { "DeploymentLabel": "[parameters('deploymentLabel')]" }, "properties": { "packageUrl": "[parameters('packageSasUri')]", "configurationUrl": "[parameters('configurationSasUri')]", "upgradeMode": "[parameters('upgradeMode')]", "allowModelOverride": true, "roleProfile": { "roles": "[parameters('roles')]" }, "networkProfile": { "loadBalancerConfigurations": [ { "id": "[concat(variables('resourcePrefix'), 'Microsoft.Network/loadBalancers/', variables('lbName'))]", "name": "[variables('lbName')]", "properties": { "frontendIPConfigurations": [ { "name": "[variables('lbFEName')]", "properties": { "publicIPAddress": { "id": "[concat(variables('resourcePrefix'), 'Microsoft.Network/publicIPAddresses/', parameters('publicIPName'))]" } } } ] } } ] }, "osProfile": { "secrets": "[parameters('secrets')]" } } } ] }

 

 

 

 

Parameter file:

 

 

{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "cloudServiceName": { "value": <CSES name> }, "location": { "value": <CSES region> }, "deploymentLabel": { "value": "deployment label of cses by ARM template" }, "packageSasUri": { "value": <.csdef SAS URL> }, "configurationSasUri": { "value": <.cscfg SAS URL> }, "roles": { "value": [ { "name": <role1 name>, "sku": { "name": <new supported VM size>, "tier": "Standard", "capacity": <instance number> } }, { "name": <role2 name>, "sku": { "name": <new supported VM size>, "tier": "Standard", "capacity": <instance number> } } ] }, "publicIPName": { "value": <public IP address name> }, "upgradeMode": { "value": "Auto" }, "secrets": { "value": [ { "sourceVault": { "id": "/subscriptions/<subscription id>/resourceGroups/<resource group name>/providers/Microsoft.KeyVault/vaults/<key vault name>" }, "vaultCertificates": [ { "certificateUrl": "https://<key vault name>.vault.azure.net/secrets/<certificate name>/<secret ID>" } ] } ] } } }

 

 

 

Result:

newly created CSES resource using same IP addressnewly created CSES resource using same IP address

 

 

Published on:

Learn more
Azure PaaS Blog articles
Azure PaaS Blog articles

Azure PaaS Blog articles

Share post:

Related posts

Azure Storage - TLS 1.0 and 1.1 retirement

Overview TLS 1.0 and 1.1 retirement on Azure Storage was previously announced for Nov 1st, 2024, and it was postponed recently to 1 year later...

1 year ago

Efficient Management of Append and Page Blobs Using Azure Storage Actions

  Overview In Azure Storage, Blob Lifecycle Management (BLM) allows you to automate the management of your data based on rules defined by...

1 year ago

[Azure AI Search] Internal Server Error when creating CMK encrypted objects

Scenario Customers follow the Microsoft doc to create CMK encrypted objects (data source, index etc.), but get the 500 Internal Serv...

1 year ago

Optimizing Azure Table Storage: Automated Data Cleanup using a PowerShell script with Azure Automate

Scenario This blog’s aim is to manage Table Storage data efficiently. Imagine you have a large Azure Table Storage that accumulates logs from ...

1 year ago

Optimizing Azure Table Storage: Automated Data Clean-up using a PowerShell script with Azure Automat

Scenario This blog’s aim is to manage Table Storage data efficiently. Imagine you have a large Azure Table Storage that accumulates logs from ...

1 year ago

Restoring Soft-Deleted Blobs with multithreading in Azure Storage Using C#

Blob soft delete is an essential feature that safeguards your data against accidental deletions or overwrites. By retaining deleted data for a...

1 year ago

Performing simple Azure Table Storage REST API operations using curl command.

The blog provides guidance to perform simple Table Storage REST API operations such as Create table, Delete Table, Insert entity, Delete entit...

1 year ago

Bulk delete all the old jobs from the batch account

Deleting a Job also deletes all Tasks that are part of that Job, and all Job statistics. This also overrides the retention period for Task dat...

1 year ago

Utilizing Azure Storage and Runbooks for scheduled automated backups of Azure SQL Databases

In this article, we are going to provide detailed steps to create a scheduled Azure SQL Database backup to storage account using automation. T...

2 years ago

[Azure Service Bus] JMS messages getting dead-lettered

The article discusses a problem where numerous messages end up in the dead letter queue (DLQ) when the JMS service bus consumer connects to th...

2 years ago

Newsletter

Get the latest Dynamics 365 and Power Platform content in your inbox

A curated digest of community blogs, product news, videos, and podcasts — delivered without the noise.

Weekly updates Unsubscribe anytime Fresh community picks
We use your email only for the newsletter and you can unsubscribe at any time.
By subscribing, you agree to the privacy policy.