terramate-io / terramate

Terramate CLI is an open-source Infrastructure as Code (IaC) Orchestration and Code Generation tool for Terraform, OpenTofu and Terragrunt.
https://terramate.io
Mozilla Public License 2.0
3.23k stars 91 forks source link

[Question] Separated git repos, and using DRY in stacks #478

Closed Th0masL closed 2 years ago

Th0masL commented 2 years ago

Hey guys !

I'm currently in the process of evaluating Terramate to see if it would fit with my infrastructure needs.

I've been looking at the mineiros-io/terramate-example-code-generation example repo, and the example structure is :

├── modules
│   ├── cloud-run
│   └── service-account
└── stacks
    ├── prod                 # Repeated
    │   ├── cloud-runs
    │   │   ├── app1
    │   │   ├── app2
    │   └── service-accounts
    │       └── cloud-run
    └── staging              # Repeated
        ├── cloud-runs
        │   ├── app1
        │   ├── app2
        └── service-accounts
            └── cloud-run

In order to keep a precise versioning of each modules, I would like to store the modules in a separate Git repository instead of storing them in the same repo as the stack folder.

Since this kind of setup is supported by Terraform, I'm assuming it's also supported when using Terramate, but can someone confirm ?

Also, after reading the docs and trying to follow the DRY approach in the modules folder, I don't really see the reason why I should not follow the DRY approach also in the stacks folder too ?

I think that it could make sense to configure the CI/CD pipepline to detect the branch main or development and simply load different environment variables in order to target the different environments upon PR.

Example of CI/CD triggers on the stacks repo :

So I am wondering what it would take to build the following setup :

. # My GitHub Org
├── modules        # Separate git repo, to be able to use version/tags when calling the modules in the stacks
│   ├── cloud-run
│   └── service-account
└── stacks         # Separate git repo, also DRY. Env vars are dictating which Environment to target
    ├── cloud-runs
    │   ├── app1
    │   ├── app2
    └── service-accounts
        └── cloud-run

Is there anything specific that is preventing Terramate from being able to work in a setup where the stack are not under an environment structure, and that the environments variables are the things dictates where the changes are being deployed to ?

Thanks

Thomas

katcipis commented 2 years ago

Hey guys !

Hi @Th0masL !

I'm currently in the process of evaluating Terramate to see if it would fit with my infrastructure needs.

I've been looking at the mineiros-io/terramate-example-code-generation example repo, and the example structure is :

├── modules
│   ├── cloud-run
│   └── service-account
└── stacks
    ├── prod                 # Repeated
    │   ├── cloud-runs
    │   │   ├── app1
    │   │   ├── app2
    │   └── service-accounts
    │       └── cloud-run
    └── staging              # Repeated
        ├── cloud-runs
        │   ├── app1
        │   ├── app2
        └── service-accounts
            └── cloud-run

In order to keep a precise versioning of each modules, I would like to store the modules in a separate Git repository instead of storing them in the same repo as the stack folder.

Since this kind of setup is supported by Terraform, I'm assuming it's also supported when using Terramate, but can someone confirm ?

For Terraform modules you can separate them into a different repository and just use them as you would on any plain Terraform project.

We don't support yet importing remote files on Terramate though, so if you mean being able to have Terramate files in a separate repo and importing them like you do with Terraform modules that won't work right away, but it is on our roadmap to support importing remote files.

Also, after reading the docs and trying to follow the DRY approach in the modules folder, I don't really see the reason why I should not follow the DRY approach also in the stacks folder too ?

I think that it could make sense to configure the CI/CD pipepline to detect the branch main or development and simply load different environment variables in order to target the different environments upon PR.

Example of CI/CD triggers on the stacks repo :

  • push to development branch -> deploy to Dev environment
  • merge to main branch -> deploy to Staging environment
  • release a new version -> deploy to Prod environment

So I am wondering what it would take to build the following setup :

. # My GitHub Org
├── modules        # Separate git repo, to be able to use version/tags when calling the modules in the stacks
│   ├── cloud-run
│   └── service-account
└── stacks         # Separate git repo, also DRY. Env vars are dictating which Environment to target
    ├── cloud-runs
    │   ├── app1
    │   ├── app2
    └── service-accounts
        └── cloud-run

Is there anything specific that is preventing Terramate from being able to work in a setup where the stack are not under an environment structure, and that the environments variables are the things dictates where the changes are being deployed to ?

The example we provided reflects how we usually organize our projects but Terramate does not impose any particular way to organize your code (or how to run it), so the structure you are proposing should be possible.

Hope I was able to help.

Thanks

Thomas

mariux commented 2 years ago

Hi

let me add some more details..

TL;DR: ALL the proposed topics and architectures should be doable with Terramate.

I'm currently in the process of evaluating Terramate to see if it would fit with my infrastructure needs.

thanks for sharing this ;)

I've been looking at the mineiros-io/terramate-example-code-generation example repo, and the example structure is :

└── stacks
    ├── prod                 # Repeated
    └── staging              # Repeated

In order to keep a precise versioning of each modules, I would like to store the modules in a separate Git repository instead of storing them in the same repo as the stack folder. Since this kind of setup is supported by Terraform, I'm assuming it's also supported when using Terramate, but can someone confirm ?

Yes, we can confirm this is possible as you can use normal terraform with pointing the source attribute to whatever repository or file you want.

Also, after reading the docs and trying to follow the DRY approach in the modules folder, I don't really see the reason why I should not follow the DRY approach also in the stacks folder too ?

in reality dev, staging and prod are not always identical. You will have different access patterns that you also handle in code. E.g. different people have different access on staging vs production environments. You will also have a different scale and you will have different settings for debugging purposes and altering.

So no environment is the same. This can ofc be managed by feature flags inside of a single module. But the more things you add to this module, the bigger the state will be and the less maintainable it will get.

In addition you want to try out things on staging first, so every other day staging will have changes not yet promoted to production. Depending on priorities this can be the case for quiet a while.

I think that it could make sense to configure the CI/CD pipepline to detect the branch main or development and simply load different environment variables in order to target the different environments upon PR.

Example of CI/CD triggers on the stacks repo :

  • push to development branch -> deploy to Dev environment
  • merge to main branch -> deploy to Staging environment
  • release a new version -> deploy to Prod environment

Personally i am not a fan of this approach as experience showed branches will diverge and you need to follow a very strict flow. for example the development branch is maybe shared between a bunch of teams and you need to implement social guardrails to not undeploy changes. You will need to revert changes not yet ready for production to promote other changes. This is hard to get right and difficult to scale.

Having directories instead of branches turned out to be very scalable ever over hundreds of stacks where teams can work in parallel o feature branches being merged to main.

Triggering a release to deploy to production comes with the hustle of having a clean review step. Not all CIs support manual approval within a workflow on every pricing level.

It is for sure a valid approach but from a very personal point of view i havn't seen it working on scale.

Terramate does not stop you doing so but manual effort is needed to get the change detection right when using Terramate as orchestrator. e.g. finding the last release instead of the last merge. But again terramate can set a base for change detection using --git-change-base=BASE which can be populated by scripts in CI hat detect the last release.

So I am wondering what it would take to build the following setup :

. # My GitHub Org
├── modules        # Separate git repo, to be able to use version/tags when calling the modules in the stacks
└── stacks         # Separate git repo, also DRY. Env vars are dictating which Environment to target

This is actually a very common and recommended set up that we also use. It has a lot of advantages as it allows you to promote versioned changes from staging to production.

It comes with some overhead of managing versions when developing as modules need to be released or tagged with a specific SHA before they can be tested, which is sometimes a lot back and forth. For this reason we also support local modules for the time of development that can be migrated to a second repository once ready for a release.

Is there anything specific that is preventing Terramate from being able to work in a setup where the stack are not under an environment structure, and that the environments variables are the things dictates where the changes are being deployed to ?

No.. how you set up things in the end is very flexible. Even Terraform workspaces are supported and we did not detect any issues in combining them with Terramate so far.

We designed Terramate to be as little intrusive for existing setups as possible. It can be used only for orchestration or only for code generation. We use it to generate tests in our Terraform Google Modules but do not se it for orchestration there. We also solved some problems for clients where we generate code only in a subset of stacks within a repository.

summary: yes, all setups you mentioned should be supported depending on the workflows and architecture you want to build around it.

hope this bring some light ;) thanks for trying it ;)

Th0masL commented 2 years ago

Thanks for your clear answers, I got all the information I needed !