Azure Cloud Services

Azure announced that from June 30th 2018 support for Service Management API (which indicates Cloud Services) would be retired. Azure stated at the time that “Cloud Services is similar to Service Fabric in degree of control versus ease of use, but it’s now a legacy service and Service Fabric is recommended for new development”

We recommend reading the Azure guide to choosing a compute service to help choose a replacement you can deploy to Azure with.

This guide remains here for legacy applications.

Support for this feature will be deprecated in Octopus Server from the 2024.1 release.

Octopus Deploy supports deployment of Azure Cloud Services. This page will walk you through, step by step, setting up a deployment using the Octopus built-in Deploy an Azure Cloud Service step.

Step 1: Packaging

An Azure cloud service package is normally compiled into a .cspkg file. This file will need to be re-packed into a supported package for Octopus to consume. The easiest way to do this currently is to either create a simple zip file or use the NuGet.exe command line tool. For example, the resulting NuGet package will look like this:

Upload to a NuGet feed

In order to make the NuGet package accessible to Octopus it needs to be uploaded to a package repository. The built-in Octopus package repository is accessible from Library ➜ Packages and is a suitable place to upload your Cloud Service NuGet package:

Package feed

Step 2: Create an Azure account

If you haven’t already, create an Azure Management Certificate Account to grant Octopus Deploy access to your Azure Subscription.

Step 3: Create the Azure Cloud Service deployment step

Add a new Azure Cloud Service Deployment Step to your project. For information about adding a step to the deployment process, see the add step section.

Step 4: Configure your Azure Cloud Service step

Once an Account is selected, the list of Cloud Services and Storage Accounts available to the Azure subscription associated with the chosen Account will be populated for you to choose from.

SettingDefaultDescription
AccountThe Azure Account you want to target when deploying this cloud service. Select one from the list, or use a variable binding to select an account by its name or ID.
Cloud ServiceThe actual cloud service you want to target. Select one from the list, or use a variable binding to define the name of the cloud service.
Storage AccountThe Azure Storage Account where the Cloud Service Package (*.cspkg) file will be pushed in order to be deployed.
SlotYou can choose to deploy to either the Staging or Production slot.
SwapAzure allows staging and production deployments to be swapped, by switching virtual IP addresses. When deploying to production, Octopus can detect whether the current staging deployment can be swapped, and if so, it can do a swap rather than a new deployment.
If Always deploy is selected, the package will always be deployed to the selected Slot.
If Swap staging to production if possible is selected and the selected Slot is Production, then a swap will occur between Production and Staging (if there is a deployment in the Staging slot).
See VIP Swap for more information on how to configure a VIP swap.
Instance CountIf you have scaled your Windows Azure service using the management portal (for example, changing the role count from 1 to 4), during a deployment Octopus can be configured to keep the existing instance counts rather than using the instance counts defined in your cloud service configuration file.

Use variable binding expressions Any of the settings above can be switched to use a variable binding expression. A common example is when you use a naming convention for your different cloud services, like MyCloudService_Production and MyCloudService_Test - you can use environment-scoped variables to automatically configure this step depending on the environment you are targeting.

Deployment features available to Azure Cloud Service steps

The following features are available when deploying a package to an Azure Cloud Service:

Please note these features actually run on the Octopus Server prior to deploying the Cloud Service package to Azure. They don’t execute in the Azure Cloud Service instances you are eventually targeting.

Using custom scripts

Custom scripts typically rely on specific tools being available when they execute.

It is best that you control the version of these tools - your scripts will rely on a specific version that they are compatible with to function correctly.

The easiest way to achieve this is to use an execution container for your step.

If this is not an option in your scenario, we recommend that you provision your own tools on your worker.

Using the Azure tools bundled with Octopus Deploy is not recommended. Octopus bundles versions of the Azure Resource Manager Powershell modules (AzureRM) and Azure CLI. These were originally provided as convenience mechanisms for users wanting to run scripts against Azure targets. The versions bundled are now out of date, and we will not be updating them further.

From Octopus 2021.2, a warning will also appear in the deployment logs if the Azure tools bundled with Octopus Deploy are used in a step.

We recommend you configure Octopus Deploy to use your own version of the Azure PowerShell cmdlets and version of the Azure CLI.

If the Azure PowerShell module is available, it will be loaded for your convenience, and the subscription from the account associated with the target will be selected. This means you don’t have to worry about loading the Azure PowerShell module nor authenticating with Azure yourself.

You can write very straightforward scripts like the example below:

# Swap the staging slot into production
$ServiceName = $OctopusParameters["Octopus.Action.Azure.CloudServiceName"]
$Deployment = Get-AzureDeployment -Slot "Staging" -ServiceName $ServiceName
if ($Deployment -ne $null -AND $Deployment.DeploymentId  -ne $null) {
  Write-Host ("Current Status of staging slot for {0}" -f $ServiceName)
  $Deployment
  $MoveStatus = Move-AzureDeployment -ServiceName $ServiceName
  Write-Host ("Vip swap of {0} status: {1}" -f $ServiceName, $MoveStatus.OperationStatus)
} else {
  Write-Host ("There is no deployment in staging slot of {0} to swap." -f $ServiceName)
}

See the Azure PowerShell documentation for more information.

Deployment process

Deployment to an Azure Cloud Service proceeds as follows (more details provided below):

  1. Download the package from the package repository.
  2. Extract the package on the Octopus Server to a temporary location.
  3. Extract the Cloud Service package (.cspkg) to a temporary location.
  4. Any configured or packaged PreDeploy scripts are executed.
  5. Variable substitutions in Cloud Service configuration file (.cscfg).
  6. Substitute variables in templates (if configured).
  7. .NET XML configuration transformations (if configured) are performed.
  8. .NET XML configuration variables (if configured) are replaced.
  9. Any configured or package Deploy scripts are executed.
  10. Re-package the Cloud Service Package.
  11. Upload the Cloud Service Package to Azure Storage.
  12. Deploy the Cloud Service Package (see ‘Customizing the deployment process’ section below).
  13. Any configured or packaged PostDeploy scripts are executed.

Extract the Cloud Service package

Cloud Service Package files are extracted during deployment, in order to make available features such as .NET Configuration Transforms and Variable Substitution.

To extract the Cloud Service Package, it is first converted to the CTP format (also known as V20120315). This is the format described by Microsoft documentation, but is not used by default by the CSPack utility (passing the /useCtpPackageFormat switch is required for this format to be used). This is just an implementation detail, but the documented archive layout gives a good starting point to understanding the layout of the extracted package.

Setting the Octopus.Action.Azure.LogExtractedCspkg variable to true will cause the layout of the extracted package to be written into the Task Log. This may assist with finding the path to a particular file.

Disable Package Extraction and Re-Packaging

Based on customer reports and Azure community discussions, we believe Microsoft is no longer recommending Azure Cloud Services: https://docs.microsoft.com/en-us/azure/architecture/guide/technology-choices/compute-decision-tree. Several customers have reported timeout issues in regards to Azure Cloud Services and slow re-packing of CTP packages. Unfortunately, we cannot fix this issue, as noted here.

The issues around timeouts and slow re-repackaging can be mitigated by passing in the variable Octopus.Action.Azure.CloudServicePackageExtractionDisabled and setting the value to true. However, in doing so, variable substitution will no longer be available.

Variable substitutions in Cloud Service configuration file

Octopus will attempt to modify your .cscfg file. For example, take the following configuration:

<ServiceConfiguration serviceName="Humpty" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="2" osVersion="*" schemaVersion="2012-10.1.8">
  <Role name="Humpty.Web">
    <Instances count="1" />
    <ConfigurationSettings>
      <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true" />
      <Setting name="HelloMessage" value="Hello world! This is a web role!" />
    </ConfigurationSettings>
  </Role>
  <Role name="Humpty.Worker">
    <Instances count="1" />
    <ConfigurationSettings>
      <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true" />
      <Setting name="HelloMessage" value="Hello world! This is a worker!" />
    </ConfigurationSettings>
  </Role>
</ServiceConfiguration>

If a variable named HelloMessage is defined in your Octopus project variables, Octopus will automatically update it in the configuration file. You can also name the variable Humpty.Worker/HelloMessage to scope the setting to a specific web/worker role.

Customizing the deployment process

The deployment is performed using the open-source Calamari project. For backwards compatibility, Octopus will look for a PowerShell script called DeployToAzure.ps1. If a file with this name exists within your package, Octopus will invoke it. Otherwise, Octopus will continue to use it’s bundled Sashimi.AzureCloudService library.

If you choose to override the deployment script, remember that your DeployToAzure.ps1 file must exist at the root of your package. It cannot be located in a subfolder. For reference, you can see how this filename is detected in your extracted package here.

Deploying to multiple geographic regions

When your application is deployed to more than one geographic region, you are likely to need per-region configuration settings. You can achieve this result in many different ways, but the two most popular methods we have seen are:

  1. Cloud Regions: enable rolling deployments across multiple geographic regions.
  2. Environment-per-region: by creating an environment per region you can leverage lifecycles to create a strict release promotion process.

Both methods allow you to modify your deployment process and variables per-region, but have slightly different release promotion paths. Choose the one that suits you best.

Learn more

Help us continuously improve

Please let us know if you have any feedback about this page.

Send feedback

Page updated on Sunday, January 1, 2023