In this section, we will learn about the difference between mutable
and immutable infrastructure.
In one of the previous lectures, we saw that when Terraform updates a resource,
such as updating the permissions of a local file,
it first destroys it and then recreates it with the new permission.
Why does Terraform do that?
To understand this, let us make use of a simple example.
Consider an application server running NGINX with the version of 1.17.
When a new version of NGINX is released,
we upgrade the software running on this web server.
First from 1.17 to 1.18.
Eventually, when a new version 1.19 is released, we upgraded the same way from 1.18 to 1.19.
This can be done using a number of different ways.
One simple approach is to download the desired version of NGINX
and then use it to manually upgrade the software on the web server
during a maintenance window.
Of course, we can also make use of tools such as ad-hoc scripts,
or configuration management tools such as Ansible to achieve this.
For high availability, instead of relying on one web server,
we can have a pool of these web servers all running the same software and code.
We would have to use the same software upgrade lifecycle for each of the servers
using the same approach that we use for the first web server.
This type of update is known as in-place update.
This is because the underlying infrastructure remains the same,
but the software and the configuration on these servers
are changed as part of the update.
This here is an example of a mutable infrastructure.
Updating software on a system can be a complex task,
and in almost all cases, there are bound to be a set of dependencies
that have to be met before an upgrade can be carried out successfully.
Let us assume that web server 1 and 2 have every dependency met
while we try to upgrade the version from 1.18 to 1.19.
As a result, these two servers are upgraded without any issues.
Web server 3, on the other hand, does not.
The upgrade fails on web server 3 because it has a few dependencies that are not met,
and as a result, it remains at version 1.18.
A failure in upgrade could be because of a number of reasons
such as network issues impacting the connectivity to the software repository,
file system full, or different version of operating system running on web server 3
as compared to the other two.
However, the important thing here to note is that we now have a pool of three web servers
in which one of the servers is running a different version of software
as compared to the rest.
Over time, with multiple updates and changes to this pool of servers,
there is a possibility that each of the servers vary from one another
maybe in software, or configuration, or operating system, et cetera.
This is known as a configuration drift.
For example, after a few update windows, our three web servers could look like this.
Web server 1 and 2 have NGINX version of 1.19, and web server 3 has a version of 1.18.
All three web servers
may also be running slightly different versions of operating system on them.
This configuration drift can leave the infrastructure in a complex state,
making it difficult to plan and carry out subsequent updates.
Troubleshooting issues would also be a difficult task
as each server would behave slightly differently from the other
because of this configuration drift.
Instead of updating the software versions on the web servers,
we can spin up new web servers with the updated software version,
and then delete the old web server.
So when we want to update NGINX 1.17 to 1.18,
a new server is provisioned with 1.18 version of NGINX.
If the update goes through, then the old web server is deleted.
This is known as immutable infrastructure.
Immutable means unchanged or something that you cannot change.
As a consequence, with immutable infrastructure,
we cannot carry out in-place updates of the resources anymore.
This doesn't mean that updating web servers this way will not lead to failures.
If the upgrade fails for any reason, the old web server will be left intact
and the failed server will be removed.
As a result, we do not leave much room for configuration drift to occur
between our servers,
ensuring that it is left in a simple easy-to-understand state.
Since we are working with Infrastructure as a Code,
immutability makes it easier to version the infrastructure
and to roll back and roll forward between versions.
Terraform as an infrastructure provisioning tool uses this approach.
Going back to our example,
updating the resource block for our local file resource
and changing the permission from 777 to 700
will result in the original file to be deleted
and a new file to be created with the updated permission.
By default, Terraform destroys the resource first
before creating a new one in its place.
What if we want the resource to be created first before the old one is deleted,
or to ignore deletion completely?
How do we do that?
These can be done by making use of lifecycle rules in our resource block,
and we will see how to do that next.