Infrastructure as Code 101. Part 1: What, Why, How?
Wouldn’t it be cool to be able to program your infrastructure just like you do with your software? To ditch the need to perform a lot of tedious manual tasks every time you need to set up a new machine? To manage and provision all the infrastructure pieces in an automated way using only code? Sure it would! Here’s your roadmap for infrastructure as code, based on Infrastructure as Code by Kief Morris.
Being a software house, we work on many projects using similar technology stacks, so the initial setup looks more or less the same for each project. By approaching infrastructure just like code, a lot of blocks can be defined just once and then reused in many different projects. This comes in handy not only because it saves time, but also because it helps enforce good practices for server provisioning and management. This way we create a reliable base to build on, especially for developers who are still mastering infrastructure setup from scratch. But first things first – let me explain what infrastructure as code is all about and how to make it work for you as well.
What is infrastructure as code?
Basically, it’s applying the same principles both for software infrastructure and software code. Essentially, by treating infrastructure like a piece of code you:
- define infrastructure in text files,
- store it in a version control system,
- test it and provision it with an automated process
What’s in it for you?
Sure, when your project is small and involves one or two machines, you may see the setup as a one-off task. You can perform it ad hoc and you don’t have to worry about it anymore. That might well be true in some cases, but more often than not you’ll have to go through it again at some point. And it might get tricky to have all the pieces work the same way they did before, unless you create a clear process for it.
When you have an entire fleet of servers, it’s next to impossible to manage them all manually. Also, working in a team where different people can ssh into the servers and change things manually can cause a real mess, especially if there is no documentation or if it isn’t kept up to date.
Having a clear way to spin up the infrastructure without any extra effort is invaluable.
Another reason is that, in general, infrastructure setup may not be an exciting task, because it’s very repetitive. Having an automated process handle it for you will relieve developers of that burden and let them concentrate on more challenging tasks.
When you put things into perspective, having a clear way to spin up the needed infrastructure without any additional thinking or effort is invaluable. Now, let’s get down to business: how does it really work and how to do things right?
The principles of Infrastructure as code
Every element of infrastructure should be easily reproducible
Since you want your system to be fault-tolerant, you need a way to be able to spin it up from scratch quickly and with no human effort. In order to achieve that, the whole process required to create an element of the system to be captured in scripts and tooling that can be invoked by a machine.
Processes should be repeatable
All the changes introduced to the system should be reflected in its definition files. You should be able to repeat any change carried out on your infrastructure in an automated way.
Systems should be consistent
Any changes should be deployed using an automated process to make sure that there are no inconsistencies between your machines. Manual changes via ssh should be eliminated.
Design is always changing
It’s impossible to accurately predict how the system will be used in practice and how its requirements will change over time. Everything should be designed to facilitate change – infrastructure should be there to help, not to complicate things even further.
Everything should be designed to facilitate change – infrastructure should be there to help, not to complicate things even further.
This is why automated infrastructure change management is very useful for delivering changes quickly and reliably.
To conform to the above principles, these practices will come in handy:
Best practices for infrastructure as code
Use definition files
Having definition files that describe the entire infrastructure means that a machine can provision and update all the servers you need with high speed and reliability.
Version all the things
We can clearly see the state of the system at any given time in the past because we have a full history of all the changes. It’s also possible to perform a code review, which can help identify many problems early on and makes sharing knowledge within the team a lot easier. You no longer need to worry that some knowledge about the infrastructure will get lost in the process.
Self-documented systems and processes
Since all the information about the system is kept safely in the version control system, there’s no need to document it separately. That’s the best kind of documentation there is: unlike the traditional documentation written by people for people, there’s just one way to interpret it, because an automated process takes it as input to update the system or create it from scratch.
Continuously test the systems and processes
Similarly to application code, continuous integration and delivery can also be achieved for infrastructure.
Infrastructure testing can be incorporated into a continuous integration and delivery pipeline.
Automated tests for infrastructure can be run to verify that:
- the creation or update of all the components was successful,
- all the infrastructure’s pieces can communicate as they’re supposed to,
- all the security requirements are met,
- the system scales as it’s supposed to,
and many, many others.
Small changes instead of batches
Introducing changes to the system in small steps makes it easier to find any issues quickly and identify what caused them. It’s vital to have a proper testing pipeline and monitoring setup so that no problems go unnoticed.
Services available continuously
Since you want your services to be up and running without any downtimes, possible failures and system updates should be handled smoothly. It usually means you need some redundant machines to make sure that if one of them fails, it can be recreated and in the meantime, other ones are able to pick up the slack. This in turn involves spinning up new machines automatically. When it comes to system updates, green blue deployment comes in handy.
It works the following way:
- First and foremost: there’s no need to touch the running production system.
- Provision new infrastructure and deploy the updated software version there.
- Run all the necessary tests to assure the new version is working as expected.
- Once you’re sure it’s good to go, switch the traffic from the old system to the new one.
This also makes rollbacks very easy. More information on this topic can be found in Martin Fowler’s article about BlueGreenDeployment.
There are many tools out there that can help you with taking advantage of infrastructure as code. At 10Clouds, we mainly use Ansible and CloudFormation. In the next part of this blog post, I’ll provide some practical examples of CloudFormation templates and how to use them.