In this series of tutorials, we’re going to show you a practical example of Continuous Delivery, from provisioning infrastructure to releasing your application. The goal is to illustrate key concepts for implementing Continuous Delivery into an environment.
Continuous Delivery is the holy grail of releasing changes in today’s hyper-paced world. It’s a term that needs to be fully understood by anyone who has a stake in application releases. This includes system administrators, network administrators, and application developers, to name a few.
As an example, we are going to show you how to handle continuous Delivery for a NodeJS API. From provisioning the application’s infrastructure, deploying the code, and then finally configuring the app for the environment we are deploying it to.
Everything we use in this tutorial is available for download from Github.
Three Repositories
Our solution is going to provide infrastructure provisioning, configuration management, and application deployment. We will split these into three different repositories as a way to manage change and separate responsibilities.
Each repository will have matching tags, so we can imperially know what configuration management commit works with which corresponding application deployment script. This is important for auditing and rollbacks. Often times during an emergency rollback, there is little time to investigate which will work together.
Our repositories will adhere to the following tagging scheme: a four segment version number. The first three will match the application version and the fourth will be reserved for script revisions. For example, if we are releasing version 5.12.2 of our application, our configuration management repo may be at version 5.12.2.1 and our deployment playbook could be at 5.12.2.20. We will always use the highest playbook revision for the particular application release version.
Therefore, our three Continuous Delivery repositories will be the following:
- Infrastructure
- Deployment
- Config
Provisioning Infrastructure
An application needs infrastructure, obviously. So our first task in our Continuous Delivery solution requires that the prerequisite infrastructure exists prior to performing any tasks.
We’re going to use Hashicorp’s Terraforms to create the network and provision our servers.
Configuration Management
Every server in the environment you are deploying an application to must have the exact same configuration — no exception. You immediately invalidate this the instant you make any manual changes.
Ansible will be our tool of choice in this example. We’ll use it to ensure every server group is configured precisely the same way and to allow us to roll out those changes instantly.
Application Deployment
An application build should never include environmental details. It should be as portable as possible, with environment settings applied during deployment.
This allows us to build one package that can be used in all environments — dev, staging, and production. This also enforced the idea that all environments are configured the same, as well as it ensures your code will work in all of them.
When you build for each environment you introduce inconsistencies. You can never be certain that your application in staging will run in production since it required a different build that likely introduced different parameters.
Ansible, much like any configuration management tool, provides a way to inject environmental details into our configurations via variables.
Handling Secrets and Sensitive Information
No sensitive information should ever be stored in your code or config management scripts. Sensitive information, such as public keys, certificates, and credentials should either be entered manually during deployment or, even better, fetched from a secure data vault.
We are going to fetch the database credentials from Hashicorp Vault. They will be pulled into our Ansible playbook and used to configure the application’s configuration file.
Task Scheduling
Continuous Delivery only works when everything is automated. We’ll show you how to use Jenkins to allow you to execute each task of your Continuous Delivery solution.