Adaptations to Past Problems

Get an overview of configuration management tools and virtual machines.

Configuration management tools

Over time, we adopted configuration management tools like CFEngine, Chef, Puppet, Ansible, and so on. They allowed us to describe the desired state, and that was a game changer. We simply ran those tools, and they would evaluate what needed to be done and do it.

For example, we could say that the desired state is to have a specific version of the Apache server. Those tools would check the actual state in each of the servers, and, depending on the differences between our two states (desired and actual), they would install, upgrade, reconfigure, or delete resources.

Virtualization

A bit later, virtualization took over. We moved our workloads into virtual machines (VM), and that simplified quite a lot of things. At the same time, the adoption of configuration management tools increased. Combining these two tools seemed like a good match, but they still didn’t do everything we needed them to do.

The traditional configuration management tools are all based on the “promise theory,” and they all tried to accomplish the same objective. Their goal was to converge the actual into the desired state. That objective is as valid today as it was in the past. However, all those tools were based on ideas that were valid when we were working with bare metal servers. They all tried to modify the state of servers at runtime. While that’s the best we can do when using physical servers, that goes against one of the main benefits of virtualization.

Press + to interact
Benefits of virtualization
Benefits of virtualization

Configuration management tools and virtual machines

The ability to easily create or destroy a VM allowed us to move toward immutable infrastructure. Instead of trying to converge the actual into the desired state by changing what’s running inside the servers, we could adopt the principles of immutability. All VMs are based on images that many understand as a base setup. Today, we see those images as the full definition of what a server is. They’re supposed to be immutable, and no one is supposed to change them in any form or way. Whenever we needed to apply a change, we could create a new image. Instead of modifying servers from inside, we could converge the actual into the desired state by replacing the old VMs with new ones based on different images.

Upgrading an application

Conceptually, the approach mentioned above is the same one we’re using with containers today. When we want to upgrade an application, we don’t upgrade binaries inside a container. Instead, we build a new image and replace the existing containers with new ones based on that image.

The same idea is valid for infrastructure. If, for example, we want to upgrade servers to a newer version of Kubernetes, we tend to create a new VM image, and we do rolling upgrades of the nodes. We’d shut down a node with the older version, and create a new one based on a different image. That process would repeat until all the nodes are new. That allows us to have uniform and reliable servers, while also increasing how quickly the process goes.