-
-
Notifications
You must be signed in to change notification settings - Fork 981
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: single terragrunt.hcl per environment? #759
Comments
Before I begin, I'll throw in a caveat that I'm working in an enterprise trying to balance our Infrastructure as Code for ~15 business units and ~500 systems containing ~1500 applications in a centralized cloud team. We are also currently still on Our usage of Terragrunt is a layered approach, which I'll attempt to break down:
That's the first core usage, our current plan is that it all lives within a single repository and churn of configuration here will be minimal. The repository currently looks like this:
With this setup, we are creating an
Within those After all of that is complete, we will have another set of Terraform configs (likely structured very similarly) that will just take an account and VPC ID and will lookup various resources (subnets/security groups) via a defined contract of tags and build out that particular Systems configuration (servers, ALB, IAM roles, S3 buckets, etc). There is a whole lot of connectivity (as well as resource sharing on the DB side to reduce cost) required between systems of a business unit and on-prem which is why each system is not it's own 'stack'. With all that said, I probably didn't address what you're asking. |
I am generally against using commandline arguments for targeting resources to deploy in a routine scenario, primarily because it is so easy to use |
Sounds a bit scary to me. The individual tfvars lets various teams in our organisation work on different aspects the infrastructure in nice isolation and there is low barrier of entry for newcomers when you are dealing with a single thing at the time. We also have a bunch tfvars generated by build automation and self-services (like deploying a new fargate service or creating a new rds cluster etc), that sounds very problematic if stuff would need to be appended to single shared file. Also how do you organise everything in that single file in a way that makes sense when you have hundreds or thousands of resources to manage? I think the possibility to use normal directory structures provides nice way of grouping relevant things and makes them easy to find. Personally in general I dislike massive configuration files and prefer a larger number of well structured smaller files. But I guess thats a bit like the mono repo discussion, everyone has their opinion and theres multiple sides to it :) |
I prefer the current structure of different folders for prod/staging etc with sub folders underneath for each module. It makes it easier to digest what is being used for a given environment by just looking at the folder structure. |
@brikis98 This may have been mentioned elsewhere (or possible and I can't figure it out) but why don't you recursively include all terragrunt.hcl files? If you did, I wouldn't have to move my state files from
This allows the flexibility to define variables at any hierarchy level. |
I think this is awesome, personally. That said if you're worried about the file getting too large, why not allow loading multiple .hcl files in a directory? That way people can still break up the module configs however they want, without needing to make a bunch of subdirectories. |
Yup! I mentioned just that in the original description:
|
This feature in itself is truly either an enabler or a blocker to my process of moving from our current standard terraform repos to terragrunt empowered repos. There is no way we will start segregating our state files by using the current terragrunt modular approach, however we obviously want to move away from the main.tf modules approach which implies so much unnecessary code duplication to reach the same result that we have right now in terms of state file (our safety net at the moment is whether the planned state file is unchanged or not, following a refactor of our code base to make it much prettier with no duplication at all and a modular approach). Also, it would be a great plus to completely avoid the provider, template, and terraform versions duplication between modules, and be able to apply those dynamically from the central hcl file to all modules used in a stack as required, in the same fashion that we declare the state file backend generically. I am not sure if any or all of these items can be achieved with current terragrunt, so far I have only seen duplicate declarations of provider and TF version requirements in the modules examples. |
I would prefer to have completely single for example:
|
I 'd like to implement the stack based terragrunt (no need environment based) For example, I need create one application which need reference several modules. But in the same environment, I may have several other applications to be managed as well So the terragrunt.hcl should support as below way:
I have mentioned the same idea in #957 so nothing else need be changed. We just need support |
One more thought on this RFC: if you take a step back and squint at it, I'm basically arguing for turning Terragrunt into a preprocessor for Terraform. This is similar to how SASS and Less are preprocessors for CSS code. Perhaps the way to think of it is that users write normal Terraform code, perhaps even in normal
The code in those files will look almost like 100% vanilla Terraform code: # Use normal Terraform syntax to define modules
module "frontend_app" {
# Use the source param to specify where the code for this module lives
source = "github.com/acme/modules.git//frontend-app?ref=v0.3.4"
# Specify input parameters the usual way
instance_type = "t2.micro"
instance_count = 10
# You can reference outputs from other modules the usual way
vpc_id = module.vpc.id
db_url = module.mysql.endpoint
}
module "mysql" {
# Each source can point to different module and different versions
source = "github.com/acme/modules.git//mysql?ref=v0.4.2"
# You can reference local variables the usual way
name = "${local.env_name}-mysql"
memory = 4096
disk_space = 250
vpc_id = module.vpc.id
}
module "vpc" {
source = "github.com/acme/modules.git//mysql?ref=v0.4.2"
name = local.env_name
cidr_block = "10.0.0.0/16"
}
# The normal way Terraform handles local variables
locals = {
env_name = "staging"
}
# Backend configuration defined the usual way
terraform {
backend "s3" {
bucket = "foo"
region = "us-east-1"
# The terragrunt_module_name() helper is the only Terragrunt-specific thing here
key = "${terragrunt_module_name()}/terraform.tfstate"
}
} When you run In other words, it's doing what we think Terraform should do natively, on top of more or less normal Terraform code. |
A pre-processor would be the perfect solution for Terraform and Terragrunt can handle dependency management. Right now terragrunt seems to be solving for 3 things:
Those could be 3 separate tools. |
About less code, that does sometimes make me think. I'm relatively new as a serious Terraformer / Terragrunter, but let's say I have similar environments across several regions, and I change something common like a module input variable. I have to go through all my terragrunt.hcls e.g.
and make the exact same change e.g. my I also have to go into This grates, but is still better than using vanilla Terraform or manual configuration. Are these things that resonate, or have I missed something (even something obvious) which is quite possible because there's a lot to learn? If so, happy to be pointed in the right direction. |
I believe the answer to your question is 'automation'. As in some kind of CI setup if you feel that you are safe to deploy everything at once. I can't imagine you actually want to deploy everything at the same time without some kind of promotion strategy though, as the larger your environments become, the more fragile they can be. I think you want to have a CI tool that applies your stacks 'constantly' (ie: every time they change), and you should be using module references (tags or a commit SHA) to ensure you have your terragrunt files correctly updated, before then committing changes to each environment one at a time and letting the CI tool roll the changes out. e: And I don't really think this proposal would really change your specific issue? It might make some shared code easier to share, I guess. |
Hello, I was rethinking the way i'm managing a whole GCP infrastructure, and was asking myself of how to use additional layers of modules, and this looks promising. I have a HCL hierarchy, which represents all the resources deployed accross all the projects and folders of my organization. Each one of the folders will host a HCL file calling for a module. These modules, for now, regroups all the resources needed for this particular folder and subsequent project. Obvisouly, continuing that way, will not be DRY compliant at all. So i was thinking of how i could manage that : And the RFC looks pretty nice, because it would bring the services composition to the first layer. Do you have any update on this ? |
It's a great idea to be able to run multiple modules from one target! I would like to request another closely related use case, the ability to use a module, and to have some "one-off" terraform code together in the same target. For example, let's say you have a bunch of ECS services. Each service has a bunch of common resources, such as I tried doing the following code example with terragrunt v0.28.7, but as soon as I add the file
resource "aws_s3_bucket" "b" {...}
include {
path = find_in_parent_folders()
}
terraform {
source = "../../../modules//ecs-service"
}
inputs = {
account-name = "prod"
service-name = "my-service"
} |
If I understand correctly the proposed approach it is anchored on the common but simple For instance it's not immediately clear to me how the flat file approach would apply to the
(inspired by terraform skelton blog post) Being application-focused (tire/stack) instead of env-focused, this organization has several advantages:
In light of the first point it seems to me that the "import" proposal would overlay better with this organization. |
Current state
The current practice for using Terragrunt is to create one folder for each module and put a
terragrunt.hcl
file in it. You also have oneterragrunt.hcl
at the root of each environment with shared configurations for that environment. The folder structure looks like this:New proposal
One thing I've been contemplating is if it makes sense to instead aim for the ability to have one
terragrunt.hcl
per environment so that the folder structure looks like this:To make this work,
terragrunt.hcl
would allow you to define the configuration for multiple modules in a single file. The code would look almost exactly like normal Terraform syntax. Here's a rough sketch of what that might look like:Note that, instead of a single (potentially massive)
.hcl
file per environment, we could support loading all.hcl
files in a folder, just like Terraform loads all.tf
files in a folder. This would allow you to break up your definition into a few smaller files:Inside of
apps.hcl
you could have all your app modules (e.g.,module.frontend_app
from the code snippet above), insidedata-stores.hcl
you could have all your data stores (e.g.,module.mysql
from the code snippet above), and so on. The key is that all the references between modules and usage oflocal
variables would work just as if everything was in one big file (as in the original code snippet above).Example usage
Deploy the VPC module:
This will check out the code for the VPC module into a temp dir, run
terraform apply
, and pass it the input variables you set.Deploy the VPC and mysql modules:
This will check out both modules into temp dirs and run
apply
in each one, but since one module depends on the other, it will do so in the right order (vpc
first, thenmysql
).Deploy all modules:
This will check out all modules into temp dirs and run
apply
on all of them, again respecting the dependency order.Advantages
backend
configuration.tf
file, you get separate state files and can have separate permissions for each module, reducing the blast radius of errorsDisadvantages
Other thoughts
If you really think about it, this is very close to defining all of the exact same infrastructure in a single
.tf
file (or several.tf
files in the same folder) with pure Terraform (no Terragrunt), and runningterraform apply -target=module.<MODULE>
? You could then apply changes to just one module at a time, with affecting any of the others, and get full code reuse, dependency management, etc from Terraform natively.However, the downsides of doing this with pure Terraform are:
-target=module.<MODULE>
, I believe Terraform applies not justMODULE
, but all of the dependencies of<MODULE>
too.plan
andapply
would be very slow.But still... It's so close!
The text was updated successfully, but these errors were encountered: