Tag Archives: Patterns & Practices
Octopus Deploy – Variables & Variable Sets

DevOps is a relatively new space in the software engineering world. There are a smattering of tools to aid in the automation of application deployments, but precious little guidance with respect to patterns and practices for using the new tools. As a guy who loves leaning on principles this lack of attention to best practices leaves me feeling a bit uncomfortable. Since I’m leading a migration to Octopus Deploy, I thought I would share some of the decisions we’ve made.

This series of posts is an attempt to start a conversation about best practices. I want to be clear: We have not been applying these ideas long enough to know what all of the ramifications are. Your mileage may vary.

Posts in this series
1. Environments
2. Roles
3. Variables & Variable Sets

Variables & Variable Sets

Octopus Deploy allows you to modify your application’s configuration through the use of variables. You can define variables at the project level, or share variable values between projects through variable sets. If you have relatively little sharing of variables between projects you will likely prefer to create variables at the project level. My team manages over 50 different applications. Many of them are web services designed to support SOA. The net impact is that we have a lot of shared variables and for this reason we define variables exclusively through variable sets. This saves us time hunting for where a given variable is defined.

We use 2 kinds of variable sets
1. Global
2. Role based

Global variable sets define values that might be required across the company irrespective of any particular application, or that are more easily managed together. For example, we wish to capture metadata about environments. Octopus itself does not have a facility for tagging environments with arbitrary metadata. To satisfy this goal we created a variable set called “environment” in which we create variables to indicate values such as “owner” and “abbr”. We use these values to compose the values of other variables such as dns addresses or email addresses.

We also have some environments for which we do not create dns addresses for the sites. In these environments we need to install web applications with alternate ports. We keep a variable sets to define the port number we use for web applications in these environments since they must be unique across the web server.

The number of global variable sets should be as small as possible.

Role based variable sets are variables defined for the specific roles they target. If we have a role called heroes-iis we will also have a variable set called heroes-iis. Since we create roles on a per-deployed-application basis, this helps us keep roles, projects, and variable sets linked. If heroes-iis as web service end points, this variable set may be included in some other project that depends on those end points.

Naming Conventions

It is important to have naming conventions for your variables. I highly recommend prefixing all variables in a variable set with the name of the variable set to avoid potential naming collisions. For example, If I have a variable set called heroes-iis it will have variables with names like:

  • heroes-iis.application-pool.name
  • heroes-iis.application-pool.password

Define a Standard Structure for Similar Variable Sets

Once you get the rhythm of installing applications with Octopus, you will discover that similar kinds of applications have similar variable definition needs. You can save yourself a lot of time and Chrome tabs by establishing a variable set template that you use when creating a variable set for each kind of application you deploy. Here is our variable set template for web applications being deployed to iis:

Variable Set Name Segment Field Variable Name Notes
name-iis application-pool name name-iis.application-pool.name The name of the application pool
username name-iis.application-pool.username the username the application pool runs under
password name-iis.application-pool.password the password the application pool runs under
host name.host This corresponds to the site name as registered in IIS. It does not include the protocol (http://, https://). It should be blank if the site is being deployed into an environment without a dns entry.
site-name name.site-name This will be just the name of the web application in environments that do not have a dns entry. If the environment has a dns entry, it should resolve the host property.
site-root name.site-root This is the url root for the site. It should include the protocol (http://, https://) as well as the port, and any additional routing information.
endpoints endpoint-name name.endpoints.endpoint-name A web service may expose one or more endpoints. These should have unique names. Their values should be defined with reference to the host and port variables.
connection-strings cs-name name.connection-strings.cs-name The name of the connection string in the config file.

Scope

Octopus Deploy allows you to scope variables by environment, role, or channel (as of 3.3). The scoping rules are as follows:

(environment1 OR environment2 OR ...) AND (role1 OR role2 OR ...) AND (channel1 OR channel2 OR ...)

I recommend that you scope variable values as broadly as possible. Use composed variable values where you can to minimize the number of variable values you have to maintain. For example:

<br />heroes-iis.connection-strings.heroes-db => "Server=#{environment.sql-server.url}; Database=#{heroes-db.database-name};"
heroes-db.database-name => #{HEROES_}#{environment.name}
environment.sql-server.url => http://sql-server.#{environment.name}.com

By using a composed variable value I don’t need to scope the connection string variable itself. Instead, I can confine scoping to environment.name and satisfy the resolution of all of the descendant variables. This minimizes the number of variables I have to actively maintain as new environments are created.

Octopus Deploy – Roles

DevOps is a relatively new space in the software engineering world. There are a smattering of tools to aid in the automation of application deployments, but precious little guidance with respect to patterns and practices for using the new tools. As a guy who loves leaning on principles this lack of attention to best practices leaves me feeling a bit uncomfortable. Since I’m leading a migration to Octopus Deploy, I thought I would share some of the decisions we’ve made.

This series of posts is an attempt to start a conversation about best practices. I want to be clear: We have not been applying these ideas long enough to know what all of the ramifications are. Your mileage may vary.

Posts in this series
1. Environments
2. Roles
3. Variables & Variable Sets

Roles

When you add machines into Octopus, you must specify environments and roles for that machine. For our purposes, environments were pretty easy to define. Roles however took some work. Here are the kinds of roles we defined.

Operating Systems

Example: windows, linux

This is pretty easy. We started with Linux and Windows for this type of role. I can see a day when we may need to additionally specify ubuntu-14 or 2k8-r2. In the meantime, YAGNI.

Environment Types

Example: dev, uat, integration, staging, prod, support

Our environment naming convention for developer environments is dev-{first initial}{last name}. For uat environments it’s uat-{team}. There is only one of each integration, staging, production, and support environments. There are certain variables that are defined consistently across all dev environments but may differ in uat environments. For this reason we are applying the environment type as a role across all machines in the relevant environments.

Commands

Example: hero-db.migrator

This is a standalone role. There will only be one machine in each environment that will have this role. It’s purpose is to execute commands on some resource in the enviornment that should not be run multiple times or concurrently. A good example of this is an Entity Framework database migration. We choose one machine in an environment that database migrations can be run from.

Applications

Example: webapp-iis, topshelf-service

Each deployable application has its own role. Not every application gets installed on every machine in an environment. We use the -iis affix for applications installed into IIS regardless of whether they’re sites or web services. We use the -service affix for Windows Services. We do this because we sometimes have a family of applications that have the same name but target a different kind of application.

Octopus Deploy – Environments

DevOps is a relatively new space in the software engineering world. There are a smattering of tools to aid in the automation of application deployments, but precious little guidance with respect to patterns and practices for using the new tools. As a guy who loves leaning on principles this lack of attention to best practices leaves me feeling a bit uncomfortable. Since I’m leading a migration to Octopus Deploy, I thought I would share some of the decisions we’ve made.

This series of posts is an attempt to start a conversation about best practices. I want to be clear: We have not been applying these ideas long enough to know what all of the ramifications are. Your mileage may vary.

Posts in this series
1. Environments
2. Roles
3. Variables & Variable Sets

Our Default Lifecycle

Before I begin, I should give you some background on our development ecosystem. Our Octopus Lifecycle looks like this:

dev => uat => integration => staging => prod => support

The Environments

Name Convention Purpose Notes
dev dev-{first initial}{last name} The primary purpose of these environments is to test the deployment tooling itself. We have 15 or so individual developer environments. Each developer gets their own environment with 2 servers (1 Linux, 1 Windows) and all of our 60 or so proprietary applications installed to it.
uat uat-{team} These environments are used by teams to test their work. We have 10 or so User Acceptance Testing environments. These are a little bit more fleshed out in terms of hardware. There are multiple web servers behind load balancers. The machines are beefier. These enviornments are usually owned by a single team, though they may sometimes be shared.
integration N/A Dress rehearsal by Development for releases The integration environment is much closer to production. When multiple teams are releasing their software during the same release window, integration gives us a rehearsal environment to make sure all of the work done by the various teams will work well together.
staging N/A Dress rehearsal by Support for releases Staging is exactly like integration except that it is not owned by the Development department. We have a team of people who are responsible for executing releases. This is their environment to verify that the steps development gave them will work.
prod N/A Business Use Prod is not managed by the deployment engineering team. We build the button that pushes to prod, but we do not push it.
support N/A Rehearsal environment for support solutions Support is a post-production environment that mirrors production. It allows support personnel to test and verify support tasks in a non-prod environment prior to running them in production.