Octopus: Keeping Tentacles up to date
In Octopus, you use one central web portal to push NuGet packages out to many servers. On each server is a "Tentacle", a little Agent that receives NuGet uploads, and installs and configures packages according to conventions.
One of the annoying things about Tentacles at the moment is that as you get more than a few of them, the upgrade experience isn't very nice.
- First you download the new Octopus installer
- Remote desktop to the Octopus server and install it
- Now download the new Tentacle installer
- Remote desktop into every single staging/test/production server, and install it
Improving the upgrade process
I'd like to make this process easier, so I'm using this blog post as a way to come up with a solution. I'm going to make use of bootstrapping - that is, I'm going to use Tentacle to install Tentacle.
Currently, the Tentacle is a Windows Service EXE that works something like this:
- It starts
- It hosts a WCF service (net.tcp on port 10933)
- Packages are uploaded to it, and it installs them
Bootstrapping the Tentacle
To allow Tentacle to bootstrap itself, I'm going to do two things:
- Turn Tentacle into a Console App instead of a Windows Service
- Create "Suction cup" - a bootstrapper Windows Service that launches Tentacle
New installs
When you first install Tentacle to your test/staging/production server, the MSI will include a bundled NuGet package. On start-up, Suction Cup will install the package using the standard conventions. Then it will launch Tentacle.exe as a child process (much like IIS's main process launches each ASP.NET application pool child process).
Upgrades
Suppose a few weeks later, you download and install a new version of Octopus. The Octopus will include a Tentacle NuGet package matching the Octopus version. You can then navigate to the Environments page in Octopus, and click a button to deploy the new Tentacle package.
Now, here's the interesting bootstrapping part:
- Tentacle (v1) will deploy Tentacle (v2) to a side-by-side folder
- Tentacle (v1) will shut itself down (
Environment.Exit(0)
) - Suction Cup will realize that the Tentacle child process has shut down
- Suction Cup will find the latest installed version of Tentacle (now v2) and launch the new child process
Notes
This has some added benefits - for example, if something catastrophic happened during a deployment and Tentacle crashes, Suction Cup will automatically restart it.
One thing I'll need to detect is that if Tentacle repeatedly crashes in a short period of time, e.g., 5 times in 30 seconds, Suction Cup should wait a while before trying again - this way we don't fill up the event log.
Finally, since Suction Cup itself isn't upgraded during this process, I'm going to go with the approach that Suction Cup just needs to be 100% perfect from day 1 :)