How can I have different variable values for a mixture of tenants and channels in Octopus Deploy?

I have a multi-tenanted project in Octopus which uses different channels for different release versions.
We have tenant variable values that change between each release version, and what we’d like to do is essentially “fix” certain variables to a specific value when a release is created for that channel.

For example, given the following configuration:

Channels:

  • Application v1.4 - where the release versioning follows: 1.4.1, 1.4.2, 1.4.3 …
  • Application v1.5 - where the release versioning follows: 1.5.1, 1.5.2, 1.5.3 …

Variables:

Let’s say we have a variable for our tenants, called Tenant.Application.PageSize. This variable should have the following values for tenant Rockstars Inc:

  • 10 when the release is created in channel Application v1.4.
  • 15 when the release is created in channel Application v1.5.

And for tenant BandJam Co the following values:

  • 20 when the release is created in channel Application v1.4.
  • 50 when the release is created in channel Application v1.5.

Is it possible to achieve this with Octopus?

The first thing to mention is that this problem probably wasn’t an intended use-case that Octopus variables were originally designed to solve.

When using tenanted variable values they are treated differently to other variables when you create a release, in that the tenant provided variable values are not included as part of the release snapshot.

So there are a couple of ways to look at solving this issue, but each of them will have pros and cons. One of the solutions means considering moving your variable values outside of Octopus Deploy itself. Let’s explore these options further below.

Use project variables scoped to channels

In this scenario, you would have your variable values stored as a project variable and you would add multiple values for your variable, with each value being scoped to the channel.

The advantage of this approach is that you are able to store different values for your variables according to the channel that you have configured in your project, as you can see below:

The downside is that scoping just by channel means it wouldn’t be possible to have different values for the variables for each of your tenants as well.

:warning: Although it is possible to also scope a variable value by tenant tag, this is not a recommended approach for this use-case, since you would have to create a tag for each variable value combination, and would add complexity and scale poorly.

Consider moving these variable values outside of Octopus

This next suggestion might seem a little strange coming from us here at Octopus, but we very much believe in the right tool for the right job. Sometimes that includes not using Octopus.

As there isn’t a single way to solve the exact problem, it’s worth asking if the values you are entering as variables are actually ones that need to be parameterized as an Octopus variable.

Next, we explore two similar alternatives in storing the values outside of Octopus:

  • As part of a configuration file that sits alongside your application code.
  • Inside a configuration store or database that can be accessed by your application at runtime, as opposed to deployment time.

:warning: Sensitive variable values.

It’s important to consider the right storage for the type of variable value you are dealing with.

Do not store sensitive or secret variable values in source control. Consider a password manager or key vault.

Add values to configuration file

Application settings such as the example used in this topic, Application.PageSize could be added as an item in a configuration file. That could be a JSON file if you are using .NET Core, an XML file if you are using an older style .NET Framework application, or a Java properties file.

If you wanted to have different values for the variable between versions of your application, a typical process to allow for this would be creating a branch per release in your source control provider.

In this setup, for the variables described you could have branches:

  1. release/1.4 - where the value for the Application.PageSize would be 10
  2. release/1.5 - where the value for the Application.PageSize would be 15

Extending this example further, where you have tenants in the mix too, you could also have these values stored in a tenant-specific configuration file which is packaged in Octopus and then have a step configured in Octopus, scoped to the tenant tags which require these specific variable values deployed.

This approach would also likely require you to make changes to any existing applications and associated Octopus project deployment processes.

Query values from a Database or other Configuration store

Similarly to adding the variable values to a configuration file, it’s possible to add these values to a database or another external configuration store such as Azure App Configuration or AWS AppConfig.

These stores typically have a client library you could then integrate with your application to read these values at runtime.