IaC and GitOps
You can find a lot of articles and blog posts trying to make comparisons between IaC and GitOps to cover the differences and, usually, how GitOps builds upon IaC principles. I would say that they have a lot of things in common—they are very similar practices that use source control for storing the state. When you say IaC these days, you are referring to practices where infrastructure is created through automation and not manually, and the infrastructure is saved as code in source control just like application code.
With IaC, you expect the changes to be applied using pipelines, a big advantage over going and starting to provision things manually. This allows us to create the same environments every time we need them, reducing the number of inconsistencies between staging and production, for example, which will translate into developers spending less time debugging special situations and problems caused by configuration drift.
The way of applying changes can be both imperative and declarative; most tools support both ways, while some are only declarative in nature (such as Terraform or CloudFormation). Initially, some started as imperative but adopted declarative configuration as it gained more traction recently (see https://next.redhat.com/2017/07/24/ansible-declares-declarative-intent/).
Having your infrastructure in source control adds the benefit of using PRs that will be peer-reviewed, a process that generates discussions, ideas, and improvements until changes are approved and merged. It also makes our infrastructure changes clear to everyone and auditable.
We went through all these principles when we discussed the GitOps definition created by the Application Delivery TAG at the beginning of this chapter. But more importantly, there were some more in the GitOps definition that are not part of the IaC one, such as software agents or closed loops. IaC is usually applied with a CI/CD system, resulting in a push mode whereby your pipeline connects to your system (cloud, database cluster, VM, and so on) and performs the changes. GitOps, on the other hand, is about agents that are working to reconcile the state of the system with the one declared in the source control. There is a loop where the differences are calculated and applied until the state matches. And we saw how this reconciliation happens again and again until there are no more differences discovered, this being the actual loop.
This does not happen in an IaC setup; there are no operators/controllers when talking about applying infrastructure changes. The updates are done with a push mode, which means the GitOps pull way is better in terms of security, as it is not the pipeline that has the production credentials, but your agent stores them, and it can run in the same account as your production—or at least in a separate, but trusted one.
Having agents applying your changes also means GitOps can only support the declarative way. We need to be able to specify what is the state we want to reach; we will not have too much control over how to do it as we offload that burden onto our controllers and operators.
Can a tool that was previously defined as IaC be applied in a GitOps manner? Yes, and I think we have a good example with Terraform and Atlantis (https://www.runatlantis.io). This is a way of running an agent (that would be Atlantis) in a remote setup, so all commands will not be executed from the pipeline, but by the agent. This means it does fit the GitOps definition, though if we go into details, we might find some mismatches regarding the closed loop.
In my opinion, Atlantis applies infrastructure changes in a GitOps way, while if you apply Terraform from your pipeline, that is IaC.
So, we don’t have too many differences between these practices—they are more closely related than different. Both have the state stored in source control and open the path for making changes with PRs. In terms of differences, GitOps comes with the idea of agents and the control loop, which improves security and can only be declarative.