Learn about 5 types of typical Terraform setups from monolithic to microservices infrastructures.
In this in-depth talk, Nicki first follows the typical journey of one of OpenCredo's clients to CI/CD (Continuous Integration/Continuous Delivery) and DevOps. She describes how a client's infrastructure often evolves using Terraform, highlighting common pain points and showing typical approaches.
Later, Nicki shows how to orchestrate development with Terraform, moving from a purely local development system hosted on a laptop, to a dev team using shared state and perhaps shared services—with Consul and Vault. However, there's a bootstrap problem here: Who builds the infrastructure that builds the infrastructure?
Okay, welcome everybody. I'm going to be talking about evolving your infrastructure with. So a little bit about me and the company. I'm a CTO at a company called OpenCredo, and we're a hands-on, consultancy that specializes in helping organizations to adapt and adopt emerging technologies to solve their business problems. And quite often, this involves building end-to-end, large scale applications and systems, and large parts of making this a success is by implementing continuous DevOps practices and tooling and approaches.
This is where much of the HashiCorp tooling comes in quite handy. So as the premier HashiCorp partner, we've dealt with quite a lot of different clients, along their Terraform journey, and helped them with that. And this talk is going to look to pull some of the insights from the various clients that we've worked with, and some of the journeys that they've had, in terms of evolving Terraform as they've moved along.
So in terms of this talk, the agenda is going to be primarily focusing on how you can evolve Terraform to progressively adapt and manage your infrastructure, your organization, and your infrastructure changes. We're then also going to briefly look at the related topic of orchestrating Terraform, and some of the challenges and areas around that. And then we're going to conclude.
To start, what we're going to do, is follow a journey of a representative client, or in this case, a combination of representative clients, as they embark on a Terraform journey, starting out using Terraform to create their infrastructure. I'm going to highlight some of the common pain points that people typically encounter as they go along this journey, and then have a look at how we can evolve Terraform as we go through this process.
Hopefully, as a result, we'll emerge with a better understanding of how you can use Terraform to evolve infrastructure, and in doing so, we'll also identify some common patterns and approaches that people typically find themselves in. I want to stress; there's no absolute right or wrong way of doing things. Different clients have got very different setups and requirements and although I'm going to give you a linear-type progression of what the representative clients would go through, it may not always look exactly like that.
But the aim is to highlight the main areas that you might find as you go along your Terraform journey. To make this talk a little bit less abstract, a little bit more concrete, we're going to say we have our representative client, and they're trying to deliver a software system, which is an e-commerce system. And this is delivered as a set of microservices in an Amazon infrastructure. In this case, they're choosing to use Terraform to create the underlying environment itself, that underpins Terraform. And it's using Kubernetes as the mechanism for deploying the microservices.
So there's a new feature in Terraform which is using Terraform to deploy the microservices through Kubernetes itself. It's not going to be used for that. We're going to use it to create the underlying infrastructure. The infrastructure is relatively simple. To begin with, we start with an Amazon VPC, we have a public subnet where we're going to have things like a NAT gateway, a bastion box, and then we've also got a single private subnet, where we're going to house our Kubernetes cluster. So, it'll have a single master node and three nodes, to begin with. And for any database needs, we're going to use Amazon RDS to make that possible.
So we have Terry. She's starting as a dev ops engineer. And she discovered programmable infrastructure and Terraform, she’s excited, this is going to make a big difference to help her manage the infrastructure differently. And to start off with, she creates a sample proof of concept for getting up to speed with Terraform, and quite often, it will start looking something like this:
There will be a single Terraform file, which will define the resources that she wants to create, some hard code and values, maybe a few variables as well, and a local tfstate file. And she likes what she sees; she's quite happy with this. Proof of concept's going okay. So, she even starts creating the test infrastructure off the back of this.
Now, time moves on. Pressure builds, and the need to deliver more formal environments becomes a bit more urgent. And the boss thinks, “I needed this production infrastructure yesterday, please can you create it?”. So, she decides, “that's okay.” My best course of action: I'm going to take the proof of concept set-up that I created, and I'm going to create my test and production infrastructure out of that.
She starts off, she makes the copy of the test resources that she originally had, and duplicates that for the production set-up. But she thinks, “well maybe I can do a little bit better. At least I can create two separate files, one for the Terraform production set-up, one for the Terraform test set-up”. But we still maintained things with a separate tfstate file. She runs
terraform apply, the test infrastructure comes up, the production infrastructure comes up, and all is well.
Now time passes again, the test team come along, and they say, “I need a change to the test infrastructure. We want potentially look at expanding the Kubernetes cluster, we need to increase the CIDR range of the VPC, and can you please make the change for us in test?”. So, she says: “this is easy. I'm going to go to my test file, I'm going to change the particular set-up, make it a little bit bigger, but I also want to make sure I don't impact production. So, I'm going to rename my
terraform.tf file to a
terraform.tf.backup file, and make sure that Terraform doesn't change it in the production infrastructure”. So,
terraform apply, off she goes, and as you can imagine, things didn't go too well for Terry. Although she renamed the backup file, as you're all aware, Terraform operates off the tfstate file as a single source of truth, and Terraform thought that she removed the production resources, so it ended up deleting everything in production.
This initial set-up is what I would call a classic Terralith setup. This is my name for a relatively monolithic configuration and one of the typical reasons why you see this pattern emerging with clients, is because they take a proof of concept setup and they evolve it quite quickly into production without necessarily thinking about splitting things up. And it happens more often than you think.
The characteristics of a Terralith setup is that you have a single state file which rules everything, so your test and your production infrastructure. You also have typically a single state file where all the definitions are created, some hardcoded config, and management in local state.
Now the primary issue with the Terralith is that you can't manage the individual environments differently. So, it's very risky from an organizational perspective to go and make a change for a test system, and you inadvertently change production. So, Terry has noted this, and she says “this is problematic, but I've found a few other problems with this particular setup.
The config is not that intuitive. I've got this big file of stuff, and I'm not sure exactly what's going on here, and it's quite a lot of maintenance for me, there's a lot of duplication definitions, and maybe there's a way that we can try and sort this out”. So, she says, “let's get some help in, and see if we can evolve this.”
So we end up evolving the infrastructure for the first time, and we move to, what I would call the multi-Terralith. This is the second phase where the biggest change that you can make to make this infrastructure better is to have separate environment state management. And this is a massive bonus in terms of reducing the risk from an operational perspective of at least not destroying your production infrastructure as you go along.
To deal with some of the maintenance and the readability side of things, we're also going to move to multiple Terraform definition files, and start using variables a little bit better. In terms of managing the environment separately, in our single repository that we had before, we create two different directories, a test, and a production infrastructure, we copy all the resources over, well we duplicate it, and we make sure that we have a separate tfstate file managing both our test and our production setup.
To help make things a little bit more reasonable, we've broken that single file up also into multiple files. Different clients do this differently, sometimes they'll break it down at a technical level, so in this case, she decided to go for networks and VM's, but other people will break it up into logical components as well. But whatever makes sense, that's fine.
And also, to make things a little bit easier to read or manage, we've now got variables. So at least we can define the aspects that I want to make configurable in my environment, compared to the stuff that I want to have hard-coded. And we at least evolved our infrastructure to get to a point where it's a little bit more manageable now.
So our original pain points that we had with the Terralith were that we couldn't manage our environments separately, it's quite hard to understand, and there was a lot of maintenance, in terms of the duplication.
With our multi-Terralith we've ticked the first box. We've at least managed to get to a setup now where we can manage our environment separately, and we've done some work around making the configuration a bit more intuitive. You can argue there's probably still a little bit more to do in that case. And to move forward and address some of the duplication, we need to evolve our infrastructure again.
So we move onto the third evolution of our Terraform setup. And this is one that I would call the Terramod setup. And as the name implies, it's a version of Terraform that looks to make use of modules to create reusable components that you can start composing your infrastructure out of.
Terraform has built-in support for modules, and we're going to use this as the base building block to change our Terraform setup. The characteristics of the Terramod setup is that, as I've said before, we're going to go for reusable modules, and we're going to change our environment definitions to start composing themselves out of these modular definitions that we're going to create. We're also going to have to change the repository structure a little bit as we go along as well.
Terry's decided, “this is how I want to logically break up my module. She's got to find some way of breaking the modules up”, and she's decided to go for three main areas. So, there's a core area, a Kubernetes cluster area, and a database. For the core area, she sees this as the fundamental part of the Amazon structure, things like the VPC's, the subnets, and also the creation of things like the bastion host. Then there's the Kubernetes cluster, which is going to hold the Kubernetes setup, and a separate area for the database. And she's going to have her modules split up that way.
In terms of restructuring, and in terms of a single repository that we had, we now have an environment's directory, and we create a test-and-prod area as we had before, and we also have a separate modules area. We also then start to define the different logical components— in this case, we've split it up by the three areas, the database, core, and Kubernetes, and we define that underneath the modules area.
Now for each module, if we have a look at the core module over here, we want to define all of the resources that make up the creation of, the components involved in that particular piece. So, for the core setup, we create things like the Amazon VPC, and the public subnet, and the private subnets that underpin the core area.
We also want to make sure that we have a very clear contract that defines what are the inputs, what are the outputs that constitute this module. The convention that I tend to use here is to have an input
.tf file which very much specifies, this is what I expect to be able to configure my module with, and an output
.tf to configure the outputs.
So in this particular example, you can pass in things like the CIDR range, how big your VPC is going to be, and likewise, how big you want the DMZ CIDRs and the private subnet as well. We also have an output, and this is required, because our modules, we're going to have to start composing them together, which means that we have to understand, what the outputs are that I want to make available from my module so the other modules can start composing them. And this must be done explicitly by exposing outputs.
We want to make sure that the modules have got a clear contract as to what we expect the inputs and the outputs to be. So for each core environment, the Terraform file that we have now becomes more of a gluing module, so rather than having all of this resource together, we now specify that the environment file consists of a Kubernetes cluster, a core module, and a database module. And these refer to the modules that we've created here.
But we also must start weaving the inputs from one into the other. Because we're using modules, we can take the output of a module that we explicitly created in our output
.tf file, and weave that straight into one of the other ones. The example over here is we have our core module, and that creates our private subnet, and we need that private subnet ID to be able to be passed as input, into our Kubernetes cluster module, so that we can make sure it gets created in the right subnet. And the example is standard Terraform code as to how you do that.
Crucially, because all of the modules are configurable, there's a very clear contract which means that for the different environments we can start configuring things differently. So maybe you want to say in your test environment, I only need three nodes for my Kubernetes clusters, but in production, I want five. And now that you've got separate areas for your test and production, you can have different variables that configure things differently.
So some clients will take this even further, and they'll have quite different test and production setups, some of them are not quite as complicated.. And you can compose things differently depending on what you're trying to do.
If we go back to the multi-Terralith, which was the previous setup, we'd at least manage to evolve our environments separately, we had more intuitive configuration, and with the Terramod setup, we've taken the intuitive configuration forward.
So the environments now, when you have a look at them, you can say, “oh, my environment is composed out of a Kubernetes cluster, a database, and a core module.” We've gone some way to reducing the duplicate definitions. So previously we were duplicating everything in the test and the production setup. Now we're composing it with modules, and we're passing in different values. And that's made the setup more DRY or ‘Don't Repeat Yourself,’ which is the programmer's acronym.
This is great. We now have to move on to the next setup, which will allow us to further reduce the duplication, we need to evolve our infrastructure again, and this is what I call the Power Terramod setup. And this one builds on the Terramod setup, and it takes the use of modules to a new level. You'll end up having nested modules, or modules within modules. And the characteristics of the Terramod setup is that you have these nested modules, and they typically come in two different flavors. There's a set of base modules, which are more low-level infrastructure-type setups. And then you have the logical or the system-specific modules which are the ones that we've seen now.
Sometimes, people will end up creating their own separate module repository. For the moment we're going to stick with one, but this is also something which people end up doing. So, where we left off, we had our structure, we had the environments, we had our modules definition, and we had already structured things to having our logically composed modules as we had before.
Now we simply add these base modules as well. And the example we have here is that maybe you want a very low-level module that says, “this is exactly how I created VPC on Amazon,” or “this is how I create a public or private subnet in Amazon.” And those are the base infrastructure-specific setups.
Previously, in our core module, we had all the direct resources being defined in there. We had the VPC in the subnet, and this changes now to suddenly being composed of modules itself. We have our core module being composed of our base modules. And it doesn't have to only be this way. You can compose system modules from system modules and base modules from base modules. It depends on the level that you want to go.
But, there's a but. There is a current issue in Terraform which prevents you from fully being able to take advantage of this. And that is the ability to support a count parameter for the modules. So as some of you are aware, in some of the resources, you can typically say, in an instance, “I want five of these instances,” and Terraform will take care of creating that for you. Unfortunately, you can't do that for modules.
So, you can't say, “I want five of this module” and have it created on the fly for you. And it's a little bit of a pain because what you'll end up doing is in your environment Terraform file, you'll end up having to duplicate these definitions. So, if you wanted maybe three private subnets, if that's how you define your modules, you'd literally have to go and define the module three times in the environment configuration file. So it's a little bit of a pain, but you can get around it.
Our Terramod recap: Terramod had addressed most of the duplicate definitions. Our Power Terramod takes that even further with our nested modules, and we've got to the point where we've managed to reduce it as far as we can, given the current restrictions. So, this is great. Terry's chuffed. Things are working out well for her. And she hasn't accidentally destroyed production recently which is a good thing. She understands her code. In fact, she's building a team now. And she's got some new team members that she wants to teach the ropes.
Recently she got a little heads up from the finance guys, and they said “ah, we've been getting some information, some analytics about the environments, and your bastion box is costing a lot of money. And I think it's over provisioned, and you need to reduce the size”. So, she reckons, “this is not a problem., It's a simple change. I can give it to one of my new team members, Frankie, and he's going to make the change for me”.
So Frankie goes along, he downloads the repository, he locates the correct environment production file, and he says, “where's the variable? Oh, there it is. It's the bastion flavor, R4 large, probably a little bit big, let's make it an M4 large, and this should be fine. I double checked, yes, it is the variable that's going into my core module, that's where I've defined the bastion box. Everything is good”. He didn't get the memo about doing a
terraform plan first, he reckons all is well. I'm going to do a
terraform apply. So unfortunately for him, things also didn't work out all that well.
So, he now seems to have unexpectedly triggered a rebuilding of his Kubernetes nodes. So, what happened there? In this case, all he wanted to do was change the bastion box flavor. Unfortunately, there was a little bit of a typo in the configuration, and the same variable that was being used to configure the bastion box was passed into the Kubernetes node cluster. And as a result, Terraform thought “well, the Kubernetes nodes are changing, so I'm going to rebuild the Kubernetes cluster.”
Now you might say, if he had done a plan, he would have seen this, but you know, he was quite confident anyway. That also happens a lot, more often than you think. Although it's not quite as bad as taking out the whole of production, we have hit the next pain point that a lot of people tend to hit in these circumstances. They are unable to change one part of the system without seemingly affecting an unrelated other part of their infrastructure. To deal with that, we again need to look at evolving our Terraform to the next phase of its evolution.
So we go for pass five. And this takes us to what I would call the Terraservices setup. This looks at taking the logical components that we had before, and treating those as isolated units, and managing them independently. This will definitely isolate the risk and the management that people have in terms of managing the infrastructure where all I wanted to do was change the bastion box and somehow, I affected my Kubernetes cluster. If we can manage the core infrastructure separately from the Kubernetes cluster, that will allow you to at least get around some of these big risk components.
And the name is akin to microservices because I do think there's some similarity in the evolution of how wegot here. So, the characteristics of Terraservices is that we have, we break up components up into logical modules and we manage them separately. So now we move to having one state file per component, rather than per environment. And typically, if you haven't done so already, you will start moving to a distributed or a mode state type of setup.
This is required and helpful when you start moving to teams as well. But this comes with additional complexity. So as with microservices, when you start moving to microservices, suddenly now I've got to glue these things together, and as we'll see, moving to this setup introduces additional operational complexity as Armon was saying in his analogy earlier.
In our Powermod setup, we saw that we had these three different areas, and we had created them as modules. But it was still ruled by a single environment file, a state file for that environment. With Terraservices, we're now going to have one state file ruling each of these. So, we'll end up going from one Terraform state file for each of the environments, to having one for each of the main components that we have per environment. So, in this case, we'll end up having six.
In terms of the implications of connecting things, that needs to change now. So previously, this was the Terramod setup, where we're weaving the module inputs and outputs into each other. And that now needs to change so that we can deal with these separate state files. So there's not a massive change that you need to do to make this work, but the setup is that previously we still had our reference to our core module, so here we have the core Terraform module file itself, and it's still incorporated to the core module itself, but now it explicitly has to also export the output of the module to make it output for itself, so that other services that want to reuse its core input will be able to do so.
The example here is the private subnet ID. So the core setup needs to output that so that when the Kubernetes service needs to import it, it will be able to get hold of it. And although it's redundant here, we start also getting the definition of the Terraform backend. This is a new feature in 0.9+. And although it's redundant, you don't need to specify the local setup. I've put a here because I want to show how you move to the remote state and move forward.
So in terms of how you configure the components that want to now consume another component, it starts looking something like this. You need to import the component that you want to connect to. In this case, our Kubernetes cluster says there's some stuff that the core component output, and I need that. So, we use the Terraform remote states data source reference, and we, in this case, point at the local backend where our core tier state file was. And then we import that and we pass it through to our Kubernetes setup moving forward.
Frankie and Terry are much happier again. They've further isolated the changes to the system, and they've reduced messing up one part of the infrastructure that's potentially unrelated to the other. But she's noted that there are a few other problems now. And she's dealing with this local state file, which is proving a little bit more problematic then it was in the past, because now there's sort of more than one of her, and it seems to be tripping her team up. And not everybody pools from Git religiously, and although there are warnings when they run Terraform, it's still a little bit painful.
Security is also not that happy, because they've said there are some secrets which are exposed in the state file, and you're committing it up into Git, this is not a good thing. And as she's noted before, this is not a simple case of running her Terraform apply anymore. She now needs to think about what she's doing, because if she hasn't run the core component first, the VPC and everything won't exist. There needs to be an order of how she does things. So she needs to run the core first, then the Kubernetes cluster, then the database, or whatever the particular setup is.
So in terms of moving to a remote state setup, this is simple. Previously, we had the local reference to the Terraform state file. And now all we do is we change, and we say, “I want to use a remote backend.” In this case, it's Amazon S3. And we can also then get that tfstate file out of Git, which will also help us with some of the security issues that we had before, where we're committing clear text, secrets exposed in our state file into Git.
So the services needing to make use of these particular environments, they also then use, they change the Terraform remote state file to now refer to the S3 backend instead of the local backend. And as a bonus, from a team perspective, we start getting more things. So specifically with the S3 backend, you have the concept of locking, and this is only a very recent thing that was introduced from 0.9 onward, but it's handy from a team perspective when you want to try and prevent some of your teammates from potentially clobbering your stuff.
From a security perspective, at least with the S3 backend, we can encrypt it, which means that we don't have our Terraform state file address with the secrets exposed. And yeah, it's a move in the right direction for teams. From a Git repository perspective, we can keep absolutely everything in the same state file, but what we've seen also in some organizations and in some clients is that they land up having different teams that are responsible for different parts of the infrastructure.
So you may have a core team that's responsible for setting up fundamental parts of infrastructure, the VPC's, because maybe there's direct connect or something that is a little bit more complicated to set up, and then other teams which are responsible for creating other sections.
Once you've structured your code in a mechanism or in a way like this, it's a little bit easier to start migrating these into their own repositories and dealing with them as independent entities. So you can literally take the core module and create a perfectly separate repo to deal with that.
If you were using the common nested modules as well, what happens is that typically people will have to create a common module repository itself, and then reuse the references for the Git references in their individual modules in order to incorporate that, which also brings in versioning and other kinds of things which I won't get into at the moment. But that's a consideration as well.
So our Terraservices setup allows us to evolve and manage our infrastructure in a better way. We've isolated and reduced our risk. And we've now aided with at least trying to move towards a setup where the teams can start working a little bit better. We also have the remote setup, remote state, which has made things better.
But there's no such thing as a free lunch and moving to such a setup requires quite a lot more orchestration and management than it did before. So the last part of the talk that I'm going to talk about is orchestrating Terraform and some of the concerns and challenges that people have in this particular area for the Terraservices setup, but in general as well.
So this was our target infrastructure. And we always have some system or processes or tooling that we use to run and orchestrate and manage our Terraform. So as there was a progression with the structure of our Terraform, I'd argue that there's also similar thinking in terms of how do we evolve the processes that go around this and managing that as we evolve as a team as well.
So to begin with, we had Terry, and all she had was her single developer laptop, not a problem. It was a relatively simple setup. There was a single Git repository. We had a local state file which was committed into Git. And with one state file per environment, it's relatively simple. As a human process, you run Terraform there and apply it as you see fit and generate everything as well. And where there's one of you, you can typically get away with it. When you start having more developers that are trying to do things concurrently, things become a little bit more problematic.
Now you've suddenly got to coordinate amongst each other and make sure you don't overwrite everybody's stuff, make sure you're working off the latest code.. And from a human perspective, and at least not stepping on everybody's toes, moving to actual proper remote setup, something like S3 is a massive winner at least from that perspective. This is not only restricted to the Terraservices setup.
Many people get to remote state before then. But from a team perspective, it's quite important. It also gives you things like locking if you're in the later versions of Terraform, and a central place to manage your state. But it's also not perfect, you can still have people that pull the wrong version of the code, and even though you've got the state in a central place, you can run it against the wrong version of the code and still get yourself into both problems.
And as the setup itself starts getting more complicated, so with the Terraservices, now suddenly we have multiple state files, and this needs coordination orchestration. So how do I know that I need to run my core module first and then my Kubernetes. . You can't rely on Terraform to do that, because you've now got to make this work yourself. And if I'm honest, I think the main mechanism that people use to do this is manually talking to each other, readme files and it's run this one first, then this one, then that one, then that one, etc.. And that is the primary mechanism that a lot of people use for this.
Additionally, we didn't quite go into detail on this, but with the Terraservices setup, sometimes what people end up doing is, they don't create the infrastructure, they also will invoke a provisioning tool, so something like Ansible or Puppet, in order to install software on the box afterwards. So, if we think about the Kubernetes cluster, maybe you use Ansible or Puppet to install Kubernetes in the setup itself.
When you start having to share variables between Terraform and these provisioners, it also starts getting messy. So, you can output things from Terraform and have scripts which scrape it and then try and somehow get it into Puppet and Ansible or whatever. But as a mechanism for dealing with this, some people will move to a shared services type setup. And that will be running something like Consul or Vault to store the values that you could start sharing it between the different components that need it.
But this starts getting a little complicated. Because now you seem to have introduced another whole system that builds the system or builds infrastructure. So, who builds the infrastructure that builds infrastructure? And somebody's got to create the S3 buckets, somebody's got to create the Vault cluster and the Consul cluster.. And again, what typically happens, I'd say is that many clients deal with this as a separate area. So if they get to the point where this is the type of setup they have, they'll have a whole team which is dedicated to managing the infrastructure that builds the infrastructure.
But as an initial progression, what a lot of people will do, is at least try and start moving towards some centralized way of dealing with things. And the first step on their journey I would argue quite often is to reach for something like Jenkins as a place to at least have Terraform, a single place where you can run Terraform. So you might define your Terraform configuration and all the developers, all of the people who are involved in creating infrastructure, go to Jenkins and say, run the creation of whatever the particular environment is that you want. So it's a single place that people can see what's going on.
It's not perfect, because stuff goes wrong, and then inevitably you have to download it onto a laptop anyway and taint and apply and fix things. But it's the first step that most people go for. But quite often, many clients will end up writing their own custom systems and tooling. And you'll see this quite a lot, so there's a lot of batch scripts out there, which bring things together, quite complex systems as well, and we have been involved in helping a few people Q some of these things. And you'll see things like Terragrunt and Terrahelp and various combinations of systems coming together to create the tooling that ultimately is used to build your infrastructure.
And there are even SaaS offerings, or things like HashiCorp Enterprise Products, which are also there to try and help with some of this setup What's my point? My point is that it's not about the structure of your code, you also need to think about how you're going to evolve the processes and the orchestration system that manages this. There's no silver bullet here. I wish there was. But there's quite often a lot of manual intervention and coordination that's required for many people to get this right, and custom systems of doing things together. But the key thing is to think about it, because if you completely ignore this, when you start having multiple people trying to create your infrastructure at the same time, you will end up in a lot of trouble.
So the conclusion for this talk is that we've had a look at how you can evolve your Terraform setup. And we did this by taking a journey through a representative set of clients and looking at the pain points that they had along the way, and how they can evolve things. These are the typical setups that we see in clients.
Not everybody ends up in exactly one of these setups, and there are probably various other combinations as well. But the one you don't want to be in is the Terralith, where you're managing your test and your production infrastructure in the same state file. If you are, then I'd say the definite area you'd at least want to get to is the multi-Terralith, where you're managing your test and your production infrastructure separately.
In terms of moving to more readability, and the maintainability side of things, the Terramod and the Power Terramod setup and its use of modules, was a way to try and deal with that complexity and make things a little bit more comprehensible, and also maintainable, so that people coming to your organization can also start to understand how is it that you've created your infrastructure, and you're managing it.
With the Terraservices setup, we saw that this was the way where we can get to the point where we don't accidentally destroy different parts of the infrastructure that maybe we weren't expecting to do. And the benefits involved in that is it can help moving towards a multi-team setup, where you've got different teams or different roles responsible for creating different part of the infrastructure.
The nice thing with that as well is that there are some infrastructure moves at very different paces, so if you think about the core module, So creating that is not necessarily going to change that often as compared to maybe the way you configure your Kube cluster or something like that. And don't forget about the people. For single man setups, it's quite easy to have a very simple setup. And there's nothing wrong with that. But as you evolve, as you have more teams and more complicated setups, you need to think about these things.
So with that, thank you very much, and I hope that was helpful.