terraform collaboration with one state file - terraform

I'm struggling to solve a problem with terraform :
The problem in short is related to collaboration between teams while writing infra code using the SAME state file exemple :
Infra team : network plumbing
App team: create VMs/k8s workloads
App team obviously takes some inputs from the infra team using data sources... until here everything is alright. Both teams use different git repos but same remote STATE file.
Because both teams uses the SAME state file, ressources created by one team ( example infra team) are marked for DELETION when App team tries to deploy something and vice versa.
can we prevent this, is using separate state files the only solution ?
thanks you

The short answer is Yes.
Separate state files is the best long-term solution. The other option that you could think about is workspaces but according to terraform documentation that's not a good idea:
When Terraform is used to manage larger systems, teams should use multiple separate Terraform configurations that correspond with suitable architectural boundaries within the system so that different components can be managed separately and, if appropriate, by distinct teams. Workspaces alone are not a suitable tool for system decomposition, because each subsystem should have its own separate configuration and backend, and will thus have its own distinct set of workspaces.
https://www.terraform.io/docs/state/workspaces.html#when-to-use-multiple-workspaces

Related

Terraform azure_rm multi-region best practice

I'm using Terraform to deploy Azure resources and now want to deploy across multiple regions.
I'm finding even with Modules I'm repeating code, once for each region.
How should I be writing code for multi region? I can't find any best practices
You could create a list variable and put your regions inside.
Then you could create a for loop and create the resource for each region. This approach works only when you really want to have each resource in each region.
It really depends on your resources. Some resources are reasonably maintained as multi-region within a single module, but this is rare. This would be a case where a module specifically addresses resources in multiple regions, with some kind of unifying logic for those resources. Since regions are typically very independent by design, this is typically an anti-pattern.
Often, it is more sane to use an infrastructure module (or root module, which means the same thing) per region. Some methodologies would have you use a different directory for each region, and again per environment. Yes, you're repeating yourself, but not that much. Your root modules should usually be pretty small and opinionated, serving as a hub for modules and top-level resources to be called.
Yes, you should keep your code DRY, but don't get carried away with it. Some duplication for the sake of organizing resources is totally acceptable.
In the cases where this is truly a problem (large root modules, and/or many regions across many environments), there are tools that can handle this effectively for you. Terragrunt is a fairly effective one, and can template your root modules (including their backend configuration) via a single code location, which is then callable via fairly small files. This can help to deduplicate a codebase like the one I just described.
You may also design your infrastructure modules to be re-usable by defining variables for regional and environmental variances between deployments. Backend configuration is also configurable during Terraform runtime via CLI or environment variable settings. Between these two, you can create infrastructure modules that are capable of being applied in arbitrary environments and regions. I like this better than Terragrunt's approach, because it's much simpler.
How you call these re-usable modules is up to your orchestration implementation, be that a CI/CD system, Kubernetes, Terraform Enterprise/Cloud, whatever.
Hopefully that helps you to make a decision.

Terraform : manage specificities over each environment

I have 3 environments to manage via Terraform: dev, staging, prod.
An example of use case is below:
create a "common" service account for each environment (sa-xxx#dev + sa-xxx#staging + sa-xxx#prod)
create a "dev-specific" role for this sa-xxx#dev SA
create a "staging-specific" role for this sa-xxx#staging SA
create a "prod-specific" role for this sa-xxx#prod SA
How can I easily manage common & specific resources for each environment?
Terraform is very simple if all environments are equals, but for specificities it looks more complicated. The goal is have a structural way to manage it, and then to avoid:
code duplication in 3 distinct folders
"count" conditions in each tf resource definition
It should be possible for Terraform to look into current root folder UNION dev/staging/prod folder (depending on the environment).
The need is very simple but implementation seems so difficult.
Thanks for help ! :)
This is a pretty broad question and so it's hard to answer specifically, but one general answer to this question is to make use of shared modules as a means for sharing code between your separate configurations.
The Module Composition guide describes some different patterns that might help you in your goal. The idea would be to make each of your configurations share modules wherever it makes sense for them to do so but to also potentially use different modules -- or the same modules but with different relationships/cardinalities -- so that your configurations can represent both what is the same and what is different between each of them.
One way would be to put shared resources in a common configuration managed in a remote state. Then in other configurations, you can refer to the shared, remote state using terraform_remote_state data source.

Web application deployment approaches

Currently, our product is a web application with SQL Server as DBMS, ASP.NET backend, and classic HTML/JavaScript/CSS frontend. The product is actively developed and each month we have to deploy a new version of it to production.
During this deployment, we update all the components listed above (apply some SQL scripts, update binaries, and client files) but we deploy only the delta (set of files which were changed since the last release). It has some benefits like we do not reset custom data/configs/client adjustments.
Now we are going to move inside clouds like Azure, AWS, etc. Adjust product architecture to be compliant with the Docker/Kubernetes and provide the product as SaaS.
And now the question itself: "Which approach of deployment is recommended in the clouds?" Can we keep applying the delta only? Or we have to reorganize the process to always deploy from scratch?
If there are some Internet resources I have missed, please share.
This question is extremely broad but maybe some clarification could steer you in the right direction anyway:
Source code deployments (like applying delta's) and container deployments are two very different directions in the sense that the tooling you invest in during the entire SLDC CAN differ substantially. Some testing pipelines/products focus heavily (or exclusively) on working with one or the other. There will be tools that can handle both of course.
They also differ in the problems they're attempting to solve and come with some pro's and con's:
Source Code Deployments/Apply Diffs:
Good for small teams and quick deployments as they're simple to understand and setup.
Starts to introduce risk when you need to upgrade the Host OS or application dependencies
Starts to introduce risk when the Host's in production begin to drift (have more differing files then expected) more dramatically over time
Slack has a good write up of their experience here.
Container deployments
Provides isolation from the application (developer space) and the Host OS (sysadmin/ops space). This usually means they can work with each other independently.
Gives an "artifact" that won't change between deployments, ie the container tagged v1 will always be the same unless you do something really funky. You can't really guarantee this
The practice of isolating stateless components makes autoscaling those components very easy, and you can eventually spend more time on the harder ones (usually stateful).
Introduces a new abstraction with new concerns that your team will have to mature into. Testing pipelines, dev tooling, monitoring/loggin architectures might all need to be adjusted over time and that comes with cost and risk.
Stateful containers is hardly a solved problem (ie shoving an existing database in a container can be a surprising challenge).
In order to work with Kubernetes, you need to have a containerized application. That doesn't mean you need to containerize your entire product over night. Splitting out the front end to deploy with cloudfront/s3, and containerizing a stateless app will get your feet wet.
Some books that talk about devops philosophies (in which this transition plays a part)
The Devops Handbook
Accelerate
Effective Devops
SRE book

Terraform Folder Structure - Modules vs Files

Not sure there is going to be a right or wrong answer for this one, but I am just interested how people manage Terraform in the real world? In terms of do you use modules, different environments and collaborations.
At the moment we are planning on having a production, dev and test environments. All similar.
Now at the moment I have made my terraform files in a way that define individual components of AWS, so say one for, VPC, IAM, EC2, Monitoring (CloudWatch + CloudTrail + CloudConfig) etc. And there is one variable file and .tfvars for the above, so the files are portable (all environments will be the same). So if you need to change something its all in one place. Also means if we have a specific project running I can create a tf file defining all the resource for the project and drop it in, then once its completed remove it.
Each environment has its own folder structure on our Terraform server.
Is this too simplistic? I keep looking at module.
Also does anyone have experience of collaboration with Terraform, as in different teams? I have been looking at things like Atlantis to tie into GitHub, so any changes need to be approved. But also at the sametime with the correct IAM role I can limit what Terraform can change.
Like I said may not be a wrong of right answer just interested in how people are managing terraform and their experiences.
Thanks
My answer is just an use case...
We are using terraform for an application deployed for several customers each having small specific configuration features.
We have only one CVS repository. We don't use CVS branches mechanism.
For each folder, we have remote states at least to share states between developers.
We are using one global folder having remote states also to share states between customers configurations
We are using one folder per customer and using workspaces (former environment) for each context for each customer (prod:blue/green, stage)
For common infrastructure chunks shared by all customers, we use module
We mainly use variables to reduce the number of specific files in each customer folders.
Hope this will help you...

Using Terraform as an API

I would like to use Terraform programmatically like an API/function calls to create and teardown infrastructure in multiple specific steps. e.g reserve a couple of eips, add an instance to a region and assign one of the IPs all in separate steps. Terraform will currently run locally and not on a server.
I would like to know if there is a recommended way/best practices for creating the configuration to support this? So far it seems that my options are:
Properly define input/output, heavily rely on resource separation, modules, the count parameter and interpolation.
Generate the configuration files as JSON which appears to be less common
Thanks!
Instead of using Terraform directly, I would recommend a 3rd party build/deploy tool such as Jenkins, Bamboo, Travis CI, etc. to manage the release of your infrastructure managed by Terraform. Reason being is that you should treat your Terraform code in the exact same manner as you would application code (i.e. have a proper build/release pipeline). As an added bonus, these tools come integrated with a standard api that can be used to execute your build and deploy processes.
If you choose not to create a build/deploy pipeline, your other options are to use a tool such as RunDeck which allows you to execute arbitrary commands on a server. It also has the added bonus of having a excellent privilege control system to only allow specified users to execute commands. Your other option could be to upgrade from the Open Source version of Terraform to the Pro/Premium version. This version includes an integrated GUI and extensive API.
As for best practices for using an API to automate creation/teardown of your infrastructure with Terraform, the best practices are the same regardless of what tools you are using. You mentioned some good practices such as clearly defining input/output and creating a separation of concerns which are excellent practices! Some others I can recommend are:
Create all of your infrastructure code with idempotency in mind.
Use modules to separate the common shared portions of your code. This reduces the number of places that you will have to update code and therefore the number of points of error when pushing an update.
Write your code with scalability in mind from the beginning. It is much simpler to start with this than to adjust later on when it is too late.

Resources