Configuration Management with Octopus and PowerShell DSC

Published on: 1 Dec 2016 by: Paul Stovell

PowerShell Desired State Configuration (DSC) is the PowerShell team's take on a declarative approach to configuring servers, and is an alternative to the imperative approach of standard PowerShell scripts. PowerShell DSC can be used for many of the common configuration tasks that need to run when a new server is provisioned. Some useful examples:

  • Installing Windows features, like IIS for web servers
  • Setting environment variables
  • Setting file and folder permissions

While Octopus focuses on continually delivering new versions of an application (the applications you are building yourself), these kinds of tasks are one-off and are usually done by a different set of tools. Over the last 6 months we've been working on a number of features that actually combine together to make Octopus a really effective configuration management tool when combined with PowerShell DSC.

In this post, I want to demonstrate how Octopus can be used to manage, test and promote PowerShell DSC scripts, and how Octopus and PowerShell DSC can be used together.

Overview

In this post, I'm going to show you how to:

  • Use Octopus to run a PowerShell DSC script to install IIS on our web servers
  • Use health checks in Octopus to detect "drift" from the DSC script (an IIS feature being disabled)
  • Set up email alerts when drift is detected
  • Use auto deployments in Octopus to correct the drift (fix IIS)
  • Test new versions of our DSC script, and promote them between environments

Octopus as an alternative to PowerShell DSC Push/Pull Servers

Microsoft supports two ways to deploy PowerShell DSC scripts between servers - "push" and "pull" servers. This is a central server that stores the configurations for each of your nodes.

For most of our customers, they've already set up our Octopus and Tentacle agents between the machines, and guess what: Octopus and Tentacle can be configured in listening (push) and polling (pull) modes! And it has some benefits: Octopus/Tentacle communication is secure, doesn't expect machines to be on the same domain, supports proxy servers, and many other features.

So if you're using Octopus and Tentacle, you should just be able to deploy your PowerShell DSC scripts using Octopus, without requiring a DSC pull/push server. One less thing to manage!

Demo environment

I've set up three virtual machines in Hyper-V to build this demo: an Octopus server, and two servers which will be our web servers. One will be a "test" server, the other will be "production":

Octopus and Tentacles in Hyper-V

I set up SQL Server and Octopus on the Octopus server, and I set up Tentacle (in polling mode) on the two web servers. I didn't add any other Windows features or do anything else to configure them.

First DSC script

Before we get into IIS, let's first make a very simple DSC script that sets an environment variable. We'll make a new project in Octopus called "Configuration", which will contain a PowerShell Script step that has our DSC script:

Configuration project

Here's the script:

Configuration WebServerConfiguration
{  
  Node "localhost"
  {  
    Environment HelloMessageVariable
    {
        Ensure = "Present"
        Name = "HelloMessage"
        Value = "Hello, world!"
    }
  } 
}

WebServerConfiguration -OutputPath "C:\DscConfiguration"

Start-DscConfiguration -Wait -Verbose -Path "C:\DscConfiguration"

The script does three things:

  1. It defines the configuration. Note that we use localhost since this script will run directly on each web server.
  2. It invokes the configuration (which generates the .mof files), sending the output to a folder
  3. It applies the configuration from that folder

In Octopus we can then create a release of this project, and deploy it. The DSC script will run on the remote machine, see that the environment variable doesn't exist, and create it:

Deploying the DSC script

We can see that the variable has been created on the machine:

Variable has been set

If we modify the environment variable in Windows (for example, a naughty developer manually changed the variable when debugging something and forgot to tell anyone), the next time the DSC script runs, it will be overridden:

The variable gets overriden

Now, that's pretty interesting, but DSC isn't doing much right now that couldn't be done with standard PowerShell (although it is more declarative, which is nice). We still had to re-deploy the DSC script to force it to be overridden.

Detecting drift

The powerful thing about DSC's declarative model is the ability to detect drift - when the reality of what's configured on the machine doesn't match what it was supposed to be configured.

PowerShell provides a Test-DscConfiguration function that can be used to check if the machine has drifted. We can set up a custom health check policy in Octopus to run this every time we check the health of a machine:

Custom policy

Here is the script:

$result = Test-DscConfiguration -Verbose -ErrorAction SilentlyContinue

if ($result -eq $false) {
    Write-Host "Machine has drifted"
    Fail-HealthCheck "Machine has drifted"
} elseif ($result -eq $true) {
    Write-Host "Machine has not drifted"
} else {
    Write-Host "No configuration has been applied to the machine yet"
}

If the machine drifts (in this case, someone editing the variable), the machine will now appear as unhealthy in the Environments page:

Unhealthy machine

You can combine this with our Subscriptions feature to receive an email notification when a machine becomes unhealthy. Here's what the subscription might look like:

Subscription

Which would result in:

Email notification of drift

Automatically correcting drift

When the machine drifts from its desired configuration, it will become "unhealthy" in Octopus. This is convenient as we can set up an automatic deployment Trigger in Octopus to automatically deploy the current DSC script on top of the machine. This will re-apply the configuration, and correct the drift.

Trigger to auto deploy

Testing and promoting DSC changes

Octopus is used to dealing with promoting application releases between environments, and this approach works well for DSC scripts. If you have a new version of a DSC script, it's a good idea to apply it to servers in your test environment before rolling it out to your production environments. Here we can see that I've put version "1.0.1" of my DSC script into production, and I'm currently testing some new versions of the script:

Promoting DSC scripts

IIS

In the introduction I used installing IIS as an example of something that could be done with DSC, though to keep the examples simple we focussed on setting an environment variable. Here's an example of a DSC script that installs IIS:

Configuration WebServerConfiguration
{  
  Node "localhost"
  {        
    WindowsFeature InstallWebServer
    {
      Name = "Web-Server"
      Ensure = "Present"
    }

    WindowsFeature InstallAspNet45
    {
      Name = "Web-Asp-Net45"
      Ensure = "Present"
    }
  } 
}

WebServerConfiguration -OutputPath "C:\DscConfiguration"

Start-DscConfiguration -Wait -Verbose -Path "C:\DscConfiguration"

PS: Here's a great way to get the names of those features - in a PowerShell session on a Windows Server 2012 R2 instance, if you call Get-WindowsFeature, you'll see a nice tree with the name of each feature:

Windows Features

Summary

While Octopus focuses on what's traditionally called "Application Release Automation", we have a growing number of customers using it for Configuration Management too. PowerShell DSC and Octopus make it easy to dip your toes into the configuration management space, and the flexibility means you can build projects that contain a mix of PowerShell DSC, traditional scripts, Chocolatey commands, and application deployment.

The new features we've added in the last 6 months - automatic deployment triggers and custom health check policies - really help to close the loop when using Octopus to deploy, manage and test PowerShell DSC scripts. In 2017 we have more plans around PowerShell DSC, and we're aiming to put one of our RFC blog posts out early next year with our ideas.

If you want to learn more about PowerShell DSC, I really like this article: PowerShell DSC: The Basics.

Are you using PowerShell DSC with/without Octopus?