Why chose Terraform?

1. Configuration Management vs Provisioning

Chef, Puppet, Ansible, and SaltStack are all configuration management tools, meaning they are designed to install and manage software on existing servers. CloudFormation and Terraform are provisioning tools, which means it's designed to build servers (as well as set up load balancers, databases, networking, etc.) and server configuration is left to another tool. The two concepts/work of these tools are not completely different, they can do the things that the other can also do. But here we will focus on which cases configuration management or provisioning would be appropriate.

For example, if you use Docker, most of the config work has already been done. In Docker images, most of the software that the server you need is already installed and configured. Once you have your Docker images, all you need to do is run it. What you really need to do here is provision the servers to run these containers, so Terraform will be a better fit than other configuration management tools.

2. Mutable Infrastructure vs Immutable Infrastructure

Configuration management tools like Chef, Puppet, Ansible, and SaltStack often modify an existing system. For example, if you want Chef to install a new version of OpenSSL, it will run the software update command on your server. Through many update runs, each server will have different status changes. This leads to the problem of configuration drift, which means that the servers will differ slightly which makes the configuration control difficult to investigate and reproduce.

Conversely, if you use a provisioning tool like Terraform, when deploying a machine image created by Docker, every change will create a new deployment (just like changing a variable in functional programming returns a new variable). Just like the OpenSSL version update example above, you would create a new Docker image with the new version of OpenSSL installed, deploy that image to the new servers and delete the old servers (also be aware if those servers are databases). server). This will reduce the possibility of configuration drift and make it easier to know the current state of the server. You can also easily deploy any previous version (rollback).

3. Procedural vs Declarative

Chef and Ansible promote procedural style, which means you'll write detailed, step-by-step code. Terraform, CloudFormation, SaltStack, and Puppet all encourage writing in a declarative style, which means you'll write code that is the state you need and they'll find a way to set up themselves.

For example, you want to deploy 10 servers (eg EC2 instances of AWS) to run version 1 of your app called v1. With Ansible, you write procedural like this:

- ec2:
    count: 10
    image: ami-v1
    instance_type: t2.micro

And declarative with Terraform, you simply write:

resource "aws_instance" "example" {
  count = 10
  ami = "ami-v1"
  instance_type = "t2.micro"
}

Terraform saw that there were 10 servers before, so now it only needs to create 5 more servers. To be sure, use a terraform plan to see the change

$> terraform plan
+ aws_instance.example.11
    ami:                      "ami-v1"
    instance_type:            "t2.micro"
+ aws_instance.example.12
    ami:                      "ami-v1"
    instance_type:            "t2.micro"
+ aws_instance.example.13
    ami:                      "ami-v1"
    instance_type:            "t2.micro"
+ aws_instance.example.14
    ami:                      "ami-v1"
    instance_type:            "t2.micro"
+ aws_instance.example.15
    ami:                      "ami-v1"
    instance_type:            "t2.micro"
Plan: 5 to add, 0 to change, 0 to destroy.

Similarly, what if you want to deploy v2? With Ansible, write to find previously deployed servers and update v2 to each server. With Terraform, simply change the ami version:

resource "aws_instance" "example" {
  count = 15
  ami = "ami-v2"
  instance_type = "t2.micro"
}

This is a simple example, in fact, Ansible can let you use tags to find out which EC2 instances exist before deploying (using instance_tags and count_tag for example) but this is quite complicated ( For example, you have to find instances both by image version, availability zone,...).

To summarize, there are two main problems with procedural IAC:

  • Procedural code is difficult to capture the current state of the system. For example, reading the above 3 Ansible templates is not enough to know what we have deployed. You will have to know the application order of each template. In other words, with Ansible or Chef, you have to know the full history of every change that has happened.

  • Procedural code is not highly reusable.

In contrast, with declarative IAC like Terraform, the system status will be reflected in the current code, the codebase will be less and easier to understand. However, it also has a bad side. Since you don't have access to the entire programming language, the configuration will be a bit limited. Some infrastructure changes like rolling, zero-downtime deployment are often difficult to configure according to declarative code. But Terraform also provides some functions like input variables, output variables, modules, create_before_destroy and count which makes the config clear and clean.

4. Master vs Masterless

Chef, Puppet and SaltStack all require you to run on the master server to save state and update system changes. Every time you want to update something, you need to use the client (UI or CLI) to run commands on the master server, the master server will push those changes to other servers or those servers will pull the latest update from master server. This has a few problems:

  • Extra infrastructure: you will have to deploy 1 or more servers for high availability and scalability

  • Maintainance: you will have to maintain, upgrade, backup, monitor and scale the master server

  • Security: you need to create a way to communicate between client-server and other master server-servers. Which is to open more ports, auth system,... this can create more opportunities for attackers.

Ansible, CloudFormation, Heat and Terraform are all masterless by default, more precisely one of them will rely on the master server but it is also part of the system you are using, not the part you need to manage. For example, Terraform will communicate with the system through the API cloud provider, which can be understood as the API server is the master server (you almost do not need to care about them). Ansible works over SSH so you don't need to go through any extra infrastructure.

Conclusion

We have already compared the popular IAC tools, and in reality you will combine many tools to build your infra because each has its own strengths and weaknesses. For example, you use Terraform to deploy the entire infrastructure such as network architecture (VPC, subnet, routes), data store (MySQL, Redis), load balancers,... Then use Ansible to deploy your application on those servers. To summarize, the table below is a list of popular IAC tools. So if you want to use an open-source tool that supports immutable infrastructure, declarative code and client-only architecture, then Terraform is the most logical choice.

Last updated