How can I tell Octopus to only deploy when something has actually changed?

(Bob Walker) #1

We this scenario quite often. A single git repository houses:

  • Front-End
  • Web API
  • Processing Service
  • Database

On any given deployment, chances are pretty slim all four components were changed. Especially if only a few hours or few days have passed since the last deployment. Redeploying the same code is a waste of time and compute resources.

How can I tell Octopus to only deploy components which have changed?

(Bob Walker) #2

Octopus doesn’t know what has changed in a package since the last deployment. Could be 1 file, could be 100 files. If they are compiled into a .dll it is nigh impossible to how “different” something is.

Delta Compression can help with package transfers. If only a few files have changed then only those files will be transferred. If nothing has changed then nothing will be transferred. However, the rest of the deployment will still occur.

The truth center as to what has changed is the build server. It is monitoring source control and triggering builds based on changes. The build server will need to tell Octopus Deploy what it should deploy. There are a couple of ways to accomplish this.

Channel Per Component

One approach we have seen in the wild is to have a channel per component.

Steps can be bound for 1 to N number of channels.

The resulting deployment process would look like this:

The build server would see which files were changed and then determine which channel the release will be created for.

This works best when there are only two component channels. In the example from the question, you would have more than just four channels. You could have Database/Web, Database/Windows Service, Database/Rest API, Database/Web/Rest API, Database/Web/Windows Service, etc. etc. etc.

Project Per Component

What I’ve seen work best in the past is having a project per component. I worked on an application with all four components in a single git repo like the one from the example. We then have separate build definitions for each component. Most build servers, such as TeamCity, Azure DevOps and Jenkins allow you to monitor for changes in specific directories.

This allowed us to multi-thread the build (if we checked in changes to all four components, then four separate builds would kick off) as well as four separate deployments to a development environment.

The Octopus configuration would look like:

image

The specific projects would only have the steps to deploy their component.

The traffic cop project would use the deploy a release step. You can configure that step to Deploy if the selected release has a higher version than the current release in the environment.

I typically recommend the Traffic Cop project have a different lifecycle than the other projects. For example, if you had the following environments:

  • Development -> Pushed to Automatically by the build server
  • QA -> Pushed to Automatically after build server pushes to Development and successfully runs integration tests
  • Staging
  • Production

Development and QA are automatically deployed to. The traffic cop project’s lifecycle would be Staging -> Production. If 2 to N number of components in the application need to be pushed (Database and Website) then the traffic cop project would be used to push to staging and production.

For example, changes to Database and Web API were made. Because the build server is configured to only build on changes to specific directories, no new releases for website or windows services were created. When we create the traffic cop release, we would see the new changes for database and web api, but pre-existing releases for the website and windows service. Because we configured the deploy a release step to Deploy if the selected release has a higher version than the current release in the environment then it wouldn’t re-deploy the website and windows service. It would only deploy the database and web api.

If only one component was changed then there would be no need to use the traffic cop project.