Ask HN: Why was Terraform created?

38 points by impoppy ↗ HN
I get the idea and general use cases of Terraform - to have a unified interface with a single language for all kinds of cloud infrastructures where the machine you are deploying to can be virtually anything.

But in majority of the cases developers are very much aware of environments their code run on - they know that their containers are stored in ECR, ran in ECS, their data is stored in S3 and RDS.

It is trivial to build a container, upload it to ECR and then deploy it to ECS from a shell script. And it is a lot more readable and comprehensible for a person not familiar with the tool.

Maybe I am the problem and I just don't get the declarative style, where you only describe the wanted state, not the steps you take to achieve that state?

If we assumed by default that our cloud infrastructure provider is AWS, wouldn't it be simple to write a shell script that would call `aws-cli` few times?

I came to that question, when discussing a problem my friend, a DevOps engineer, was having - he wasn't able to get the Azure Resource Group from his `foobar.tf` files and he ended up with something like the following:

    cat << EOF
      {
        "aksvnet": "$(az resource list --resource-group $1 | grep -i \"aks-vnet- | cut -d ":" -f2 | tr -d '", ')"
      }
    EOF
And what is it? It is a shell script inside of a JSON that was created in the shell! What for are these layers of abstraction? Why does he have to wrap the Resource Group name in a JSON? Why couldn't it be just piped in plaintext format, as all the tools that try to be POSIX-compatible do?

UPD: This question is for environments where all the engineers are (to some extent) familiar with %CloudProviderSDK% and bash. And, in my opinion, it's a lot easier to pick up bash and %CloudProviderSDK%, as those are imperative therefore closer to engineers' daily routine, as opposed to Terraform's declarative style. Shell scripts, in my opinion, are just more intuitive by default.

63 comments

[ 0.26 ms ] story [ 110 ms ] thread
I can't answer "why terraform was created" because I wasn't there. Also I only recently started working with it, so by far no expert on the matter. People who don't know terraform often praise it for its platform-agnostic language, but there's an important caveat: the language is platform agnostic, not the templates one writes as they are riddled with platform-specific nouns. You can't take an Azure template and deploy it on AWS.

Having said that, I (so far) like terraform for the same reason you noted: it's more readable and there is great tooling around it. I like state management and the ability to invoke lower-level components (as the shell breakout in your example) when you really have to.

edit: > the declarative style, where you only describe the wanted state, not the steps you take to achieve that state

That is a good and useful thing. It's called "desired configuration management", Ansible works the same way. When the underlying tool works well, it decides on its own how to implement what you want. If you ever watch terraform deploy a complex (10+ dissimilar resources) infrastructure it comes close to magic how it discovers what already has been done and what still needs to be done and in which order.

>That is a good and useful thing

As long as you manage to pick it up, which I'm struggling with - you have to approach the problem from an entirely different angle with an entirely different paradigm. I'm struggling with adopting Nix on my personal machine for the same reason - I get `dnf install foo bar` but I don't get `I want foo and bar installed on my machine.` I want my machine to do the stuff only when I explicitly ask it to do stuff and only when I explicitly tell it when to do it.

UPD:

>If you ever watch terraform deploy a complex (10+ dissimilar resources) infrastructure it comes close to magic how it discovers what already has been done and what still needs to be done and in which order.

But why would you have half-ready environments you aren't even aware of state of? Isn't our job about having as little magic, mysteries and unknown variables as possible?

I'm a big opponent of magic and, probably, one of bigger fans of KISS - simple implementation, not simple usage.

> But why would you have half-ready environments you aren't even aware of state of? Isn't our job about having as little magic, mysteries and unknown variables as possible?

Abstractions are the art of revealing the right information.

With an abstraction, you don't pay attention to lower-level details that aren't related to what you're interested in. This makes it much easier to write complex systems.

When someone teaches you how to "hello world", you're able to go and write programs without needing to understand NAND gates & how a CPU works.

I think "terraform lets you work at a level of abstraction above needing to care about what is deployed in what order" is a point in terraform's favour above bash-scripts.

Terraform was made for exactly the reason you stated ("single language for all kinds of cloud infrastructures")

It was also made for non-developers to be able to deploy what someone else built "anywhere"

But using Terraform with $CLOUD implies that you are familiar with $CLOUD - then if you know $CLOUD and bash why would you need to use Terraform to work with that cloud?

Also, as stated in a sibling comment, all the commands, expressions and capabilities of Terraform differ based on your $CLOUD, so in the end it's not that universal.

In fact, it's not different from bash - bash is always the same, you just type `az` instead of `aws-cli`.

Not everybody deploying to $CLOUD necessarily knows a lot of $CLOUD and bash. They might know that they need an MPI cluster with N Cores and X GB of RAM pr core, 10 Gbit interconnects and 200 GB of shared storage. Learning how to edit a Terraform template that someone else wrote to achieve this probably is a lot easier than learning how to edit an ad hoc bash script and probably a lot less error prone.
And when you don't have bash? ...

>In fact, it's not different from bash - bash is always the same, you just type `az` instead of `aws-cli`.

Terraform works on many platforms (https://developer.hashicorp.com/terraform/downloads)

Not all have (or default to) bash

Whereas Terraform is "the same" everywhere

Not arguing, just contributing with my personal non-expert experience.

I am using Terraform because using AWS directly was too cumbersome, and I'm happy with it.

> then if you know $CLOUD and bash why would you need to use Terraform to work with that cloud?

The utility of Infrastructure as Code (IAC) is not “you don’t have to understand the target cloud platform”, which is why cloud providers often have their own IAC solutions (e.g., AWS CloudFormation, and the additional abstractions–Serverless Application Model, Cloud Development Kit–built on top of CloudFormation); Terraform adds multiple cloud support on top, which is useful for people with workloads in different clouds or when working with a vendor whose in-house solution is inferior, but that’s not the whole point.

The utility of IAC is that you don’t have to write custom code based on the current and desired state for each state transition change. You write a description of the target state, and the engine handles determining the current state, what transition code is needed, and executing the transition code.

One thing that terraform does (see below) is that it diffs the desired state with current state (again: see below), and then makes the necessary changes.

So, if you have terraformed a load balancer balancing load between 2 machines, and change your terraform to declare a load balancer balancing load between 3 machines, it won’t destroy two machines, destroy the load balancer, create a new load balancer, and then create 3 machines.

Instead, it will create a new machine and change the load balancer to know about it, so that your service is uninterrupted.

Problem is that the above isn’t quite true.

Firstly, comparing with the current state is slow, so terraform has a cache of what it thinks the current state is. If they get out of sync, things can get interesting.

Secondly, all changes are done by plugins of varying quality. Your cloud provider may, for example, support reconfiguration of a load balancer, but if the plug-in doesn’t, terraform will destroy and create a new one.

Another part of Terraform's power is the fact it's all text. We can store it in version control and see changes over time, as well as have it go through CI/CD.

While there are platform specific alternatives like Cloud Formation, learning a new system for each platform would be a pain, and frankly, things like Cloud Formation just aren't as nice to work with compared to Terraform.

It's probably overkill for your use case. If you're on AWS you can stick to CloudFormation; with something this simple, you can indeed just (as you suggest) use a bash script.

But a lot of applications have infrastructure far, far more complex than a single service running in a container and S3/RDS. It may involve a large number of lambdas, networks, API gateways, firewalls, proxies, certificates, etc.

Past a certain point, you need a way of managing all that complexity, keeping things consistent across environments/regions, ensuring all infrastructure changes are tracked and audited, and making it easier to update lots of resources at once, among other things. That's where Terraform helps.

Then I guess it's a question to the startup I'm working at - why in the world did they overcomplicate so much stuff when in fact we have constant number of environments, workers, load balancers? In fact, every engineer in the company is very much aware on how our system operates and (I believe) could easily imitate whatever Terraform does with simple scripts.
Future-proofing, I assume. Better to have things in Terraform now than to have to move them all later as you grow the application. Moving things into Terraform can be quite hard, since you essentially need to figure out how to reproduce the entire infrastructure from scratch.
YAGNI.
You won't need it. But you'll probably want it, since at most start-ups complexity grows over time.
Sounds like lack of knowledge and experience to start glueing random stuff to make things over complicated.
Unless your startup is wildly successful, which everyone is incentivized into believing. What you described sounds less like a Terraform problem and more like a complex infra problem.
Your startup probably has better things for engineers to do than the job Terraform does in determining what state changes to make.

I mean, the engineers could probably convert source into machine into machine instructions, too, but I bet your company would rather leave that to a compiler so that they could work on product.

If you have the skills on hand then I think it's worth doing TF off the bat, otherwise it's probably better to wait until you have the requisite pain/motivation to learn. It's a pain in the ass to learn how to do TF _initially_ but not bad to do after you learn, and going forward you avoid a lot of "oh wtf just happened" moments during deployments/infrastructure changes.
> If you're on AWS you can stick to CloudFormation

I would caution against this, even if you solely work on AWS. CloudFormation is much, much slower and has failure modes where it can take hours before the CF service returns to a manageable state. This is slightly better now that they added the ability to ignore failures so you can delete resources manually and then restart the CF rollback process but it’s still much more prone to getting into states where someone knows exactly what needs to be done but the tool won’t let them do it.

We switched to Terraform about half a decade ago over that and it was such a great removal of friction from your development cycle. I tried a small CF project last summer and had to help multiple experienced AWS users with the same class of problems within a week.

Not an expert nor a user of terraform, but I'm currently learning about the tool, and I like to learn by reading from books and docs, rather than diving straight in and doing.

Based on what I've read, while Hashicorp tools may look like their only contribution is platform agnostic tooling, a deep dive into the docs reveals a focus on dynamically changing architecture and providing tooling to scale dynamically changing architectures in short time scales to any number of resources (i.e. not just machines / VM / containers / compute resources, but resources like users, user-generated resources, user-generated secrets etc.)

My impressions thus far is that Hashicorp is aware of the variety of alternative tools, that's why their certifications / training / professional services are only available for the tools truly core to supporting dynamic architectures : Terraform, Consul and Vault.

https://www.hashicorp.com/customer-success/professional-serv...

https://www.hashicorp.com/customer-success/enterprise-academ...

https://www.hashicorp.com/certification

To get data in Terraform you have outputs and you can display the data.

Terraform helps you to have a unified way to manage your resources, sure the bash scripts works for you, but what happens if you leave the company? Somebody else has to maintain your shell script.

What happens if somebody else is changing the infrastructure and they're not familiar with your shell script, they need time to dig in to figure things out and then update it, and in best case test it.

And you need to keep your scripts up to date, you need to build in fault tolerance, you need to think how you're going to deploy new resources. How are you going to handle destroying resources?

And on top of that you also need to learn the cloud Provider CLI tools or API to know what kind of calls to execute.

It just provides a standardised way to manage your infra.

My complaint is that there shouldn't be unknown or uncertain states in the first place. Infrastructure should be a finite state machine, not infinite. Failure in transition from state A to state B should result in rolling back to state A, not arbitrary state X.
Sometimes you cannot rollback. The peril of infrastructure is that it is an imperfect, living state machine. Terraform is a compromise between runbooks and deterministic definitions. Some operations you are committed to the change and will need to figure out exceptions on the other side of the apply.

(infra engineer in a previous life when Terraform was first released)

What I got from this thread is that Terraform was created for this exact reason - to be able to work in a mysterious state that just happened to be there. Therefore Terraform normalizes existence of unknown unpredictable environments (which is already absolutely normal in the real world, as stuff is never exclusively black or white). But, on the other hand, isn't making stuff extremely predictable part of our job? Doesn't it contradict our goals we strive for when creating software?
I very much agree! With that said, I would argue that Terraform and other IaC tools make infra more predictable but not extremely predictable. The predictably is a function of the consistency, complexity, and failure modes of an execution context. It brings order to chaos, but you will still have some annoying or white knuckle chaos at times. Understanding that is key to effectively wielding the tools. My thesis is infrastructure will likely never be as deterministic as code due to its nature, and if you mistakenly treat them as equals, you’re gonna have a bad time.
Implementations across cloud providers are going to be different, and I don't know how AWS vs GCP vs Azure is handling failure, so now it's your responsibility.

Now the problem has grown from just write a few lines of bash script to, "create a script that can handle failure and reverts it so a known state", this is a more complex problem than just creating a resource. And now multiply this for all different resources, EC2, AKS, RDS, Security Groups ... and keep up with the API.

And if somebody joins your team, and wants to contribute to the solutions, they're going to have to understand the codebase.

If you could bring that up with cloud providers that would be great ;-)

The reality is infrastructure is commonly in unknown states, whether we like it or not.

Just because you clicked in some webui to do something doesn't mean it's save.

You still need to write how to do it, how to bootstrap it and why you do things.

We have a basic tf layer, which does make it well documented, easily extendable and repeatable.

Yes we do destroy the whole setup and recreate it. Often no but still.

After the tf layer, there is only k8s which is also 100% IaC.

Also sry to say but we are experts, learning something like tf should not be a big hurdle.

What I saw in old sysadmin setups: tons of snow flake VMS no one knows why they exist, random setups different security versions on it.

If you don't have any tool to automate things you will not do it.

Feel free to create a small infra setup manually if you prefer, I prefer to codify it once and can recreate it instead of documenting it in some word doc.

Tf is not perfect btw.

Bash is ~okay for small and simple enough tasks. But, above a certain complexity, I think probably anything else is going to be easier to maintain & have fewer footguns.
Go down the path of rolling your own shell scripts and if you do a world class job you'll end up reimplementing the functionality and architecture of Terraform. Also, as a commercial open source project, you have the benefit of an entire community using and extending the tool in their own use cases. Read through Terraform release notes, you will see the amount of work & experimentation writing and maintaining a provider can be.
Username checks out.
Ok here's a less friendly version: "The way AWS is implemented doesn't work for me" is a nightmare attitude for everyone on your team and an affront to your productivity. Look at the early (mid 2000s) AWS customer success stories and think about what it did for those companies. Accept the model and get your undifferentiated systems work done quickly.
I failed to express my take against Terraform: instead of fighting indeterministic nature of infrastructure, it was created to work around it. Why far more experienced engineers than I am came to the conclusion that playing along is better than actively fighting?
Infrastructure by it's nature won't be deterministic. Fighting it to me sounds like wanting to use "assume a frictionless plane" in a real world physics solution
I feel like your question is like "Why are there flathead screwdrivers? Shouldn't craftsmen only accept phillips head screwdrivers, since they're superior?" The reality being there are a lot of flathead screws out there.

An engineers job is to get stuff done and not fight an ideological battleground. The world is impure, and requires impure solutions. Terraform is a tool to get things done, and given the realities of managing stateful infrastructure it does a pretty good job of addressing the failure states of it.

Exactly. Explain me why do flathead screwdrivers exist, if there are phillips head screwdrivers. I don't have a problem with mastering a new tool, but I do have a problem with mastering a tool purpose and idea of which I do not fully understand.
> but I do have a problem with mastering a tool purpose and idea of which I do not fully understand

I would suggest that the onus of learning this isn't on other people though. You can start with a baseline assumption that there is a reason these decisions are made. Assume other people are smart, rational actors, and that certain pressures and tradeoffs lead to the belief that the current strategies are the best we have for the state of things overall.

The reason I say this, in particular, is that you questions and answers in this topic have felt close minded and defensive. I say this not as an insult, but highlighting that this is often how I approached things when I was early on in my career. I felt overwhelmed by all the things I needed to know, and wasn't even close to having a mental model of how all the things in a fully working piece of production software fit together. That imposter syndrome led to me discounting things I didn't understand because it was emotionally safer to feel like I knew better than to accept I was barely floating along. Was this thread about a good faith effort to understand why terraform is needed, or is it a rant for why you're mad you have to learn it?

I dunno, I have this problem all the time. I feel powerless being presented to all those enormous pieces of software I have no idea how do they work. I guess it’s a form of procrastination, as the moment I stop thinking, investigating and learning beforehand and start actually working with the input I have — the actual progress starts.

Edit: Phrasing.

It makes sense, and the biggest ways to understand are to do what you're talking about and try and "do it better." As other commenters pointed out, as you make the bash script more and more complicated, you'll see why terraform is the way it is. You may even find ways to do it better, and then you can make your own project/competitor, or submit a change back to the open source project.

However, in the mean time, it's always worth coming at these things with the generosity of mind to assume that smart people made tradeoffs for real reasons, and for your "day job" work in the frameworks adopted until you understand the problemspace well enough to give truly informed feedback on why to do something differently.

You could code a set of scripts to create a set of resources from scratch. Then another set to tear them down. And maintain and rub those as the resources change. And make sure they have options so that you can only tear down and re-set up the resources necessary when you have isolated changes abd don’t want to destroy the whole stack. And do ad hoc one time scripts every time you you want to make a change that doesn’t require tearing resources down, but also make sure the changes are reflected in the build (and, if necessary, take down) scripts.

Or you could just describe and maintain the desired state in cloudformation, terraform, etc. and let the associated runtime handle termining the changes to apply.

I know which I prefer, but you do you.

One killer feature of Infrastructure as Code, be it terraform or any other is idempotence.

You have to be careful not to run your bash script twice or you get another instance/vpc/loadbalancer or whatever.

You run "terraform apply" twice and it does nothing on the second run.

If you start implementing that in your shell scripts you start implementing terraform in bash.

another killer features is creating modules so you dont repeat yourself
I wound up at a shop where one of the original people involved and left clearly did not know about modules. It's all copy-paste.
> But in majority of the cases developers are very much aware of environments their code run on - they know that their containers are stored in ECR, ran in ECS, their data is stored in S3 and RDS.

This has absolutely not been my experience. I've worked with a few devs who might be curious to know how everything worked. Most devs I've worked with focus solely on the code they write.

I've also inherited many systems over the years and I'd take the ones managed with tf over bash every single time.

A non exhaustive list of what tf helps with.

1. Being able to know what has changed and what needs to change before you run

2. Managing infra outside of the large cloud providers and being able to combine the two

3. Quickly being able to add a new environment or region to an existing cluster

4. Some requirement has changed and some new policy/tool needs to be stitched in across all your environments

I second the value that is added by having a history of changes and the ability to project changes with tf. Not all deployments need this but for mid to large setups this is very convenient. It is not that a simple bash-script couldn't do this however it is often not done in my experience, ymmv. Mostly due to the added complexity while writing such a script.
> to have a unified interface with a single language for all kinds of cloud infrastructures where the machine you are deploying to can be virtually anything

I don't think having a unified interface is the motivation behind Terraform. You still need to understand the underlying resources you are dealing with, Terraform doesn't abstract that at all. The big idea behind Terraform is procedural vs declarative. You can write scripts to bring up all of your infrastructure but what if one of your scripts fails in the middle? What parts of it actually went into effect and which didn't? Can you just re-run it or will the first part now fail because the infrastructure already exists? What if you have several engineers working on the same environment applying scripts that may interfere with one another? What if there was an incident and you made some manual changes and now production is out of sync with what is represented in the script? What if you made some complicated infrastructure changes and you broke something and want to bring everything back to exactly how it was before?

Declarative infrastructure answers all of those questions. It lets you keep track of what the current state of your infrastructure is, and what you want it to be. It automatically identifies areas where the two don't match up and serves as a forcing function for documenting changes to your infrastructure. Declarative infrastructure is more complicated than procedural because bringing up infrastructure is a procedural process so you need a tool to make it into a declarative one and that is not always easy. But if your team's needs get complex enough the tradeoff is well worth it. I honestly can't even imagine life without it.

As a bonus it makes it easy to ship complete infrastructure solutions as re-usable modules that you can compose.

Great answer! One minor point, I agree it’s not the motivation but it _does_ provide a unified workflow across service providers, which is valuable!
> One minor point, I agree it’s not the motivation but it _does_ provide a unified workflow across service providers, which is valuable!

IIRC, it is part of the motivation for Terraform specifically, though not for the broader class of Infrastructure as Code tools, some of which are provider-specific (but also likely quicker to support new platform features.)

The example you gave is of a wrong way to write Terraform; you should be able to query the cloud API using using data sources. In your case (getting a VNet) that would be this: https://registry.terraform.io/providers/hashicorp/azurerm/la...

In case you need to get the metadata of a resource group you can use this: https://registry.terraform.io/providers/hashicorp/azurerm/la...

I am a very happy Terraform user, here are the benefits for me:

* Very simple workflow that helps prevent unintended consequences - first you write your code, generate a plan, inspect it carefully and only then apply. It is easy to work in a team setting where you can have one person write modules and others supply variables to them.

* I personally don't want to burden myself with Azure Resource Manager, CloudFormation or any other vendor specific IAC tool.

* I don't like other people's bash; there are tools like shell check, but usually a larger infra codebase becomes an awful ad-hoc mess of ENV variables and clever hacks. And infrastructure code is nasty to test and refactor.

Try to keep it simple as possible; anytime you are fighting Terraform it usually means there is a much simpler way to do it. And if there is inherent complexity it could be the wrong thing to do.

In case you need very dynamic behaviour (basically a part of an application) I advise the following - put in terraform the things that are not likely to change often or where the cost of breakage is higher - your virtual networks, DNS configuration, Load Balancers, VPNs, Autoscaling groups, important alerts, etc. Manage more ephemeral workloads in a more general purpose language if there is no straightforward way to do it in the official APIs. I am also very happy user of the AWS CLI in some cases + the cognitect aws libraries for Clojure. However if you need to do something very dynamic it is also likely to be wrong.

> first you write your code, generate a plan, inspect it carefully and only then apply

Be aware that this experience differs wildly by terraform provider. I can very easily demonstrate that `terraform plan` for AWS consults absolutely zero of the AWS infrastructure, relying solely upon terraform.tfstate. So, great if everyone in the entire organization is entirely disciplined, but in a less disciplined environment terraform's aws provider does nothing to help warn the user of the demonstrably false plan. I don't know what the situation is with the other cloud providers in order to know if that's just "the terraform way" or what

It is not a good idea to have several tools managing the same resources, I don't and for relying on the state file hasn't caused me any issues.
The complexity of cloud deployments tends to grow wildly over time. What starts as an ECR repo with a single ECS deployment turns into Route 53 zones, S3 buckets, ELBs, multiple deployments of ECS, security policies, the odd EC2 instance (there's always one somehwere), etc, etc.

Terraform gives you a commmon language to make sense of it all that can grow as your cloud infra does.

When combined with git and CI/CD it's also an amazing self-service experince. For example you can put the Terraform code that describes your environment in a git repo, and allow any employee to open pull requests, and deploy changes on merge automaically, and require IT approval to merge. Now any engineer can self-service request access to a prod environment (by modifying IAM in Terraform), or configure a production deployment without ever needing actual access to prod. IT gets an audit log, they get a control gate (the code review), and engineers get to self-service changes which reduces the load on IT.

Is self-service Terraform as you describe actually successful? I use Terraform frequently and I have zero confidence that this process works except for the simplest changes.

For one, building out anything of complexity in Terraform often involves some trial and error to make sure all the resources are wired together correctly.

For two, there are some Terraform changes that can incur downtime if you just let Terraform destroy and create resources. The solution I employ for this is what I not-so-affectionately call "Terraform surgery". It usually entails standing up the new resource(s), cutting over to them, and then destroying the old ones. Sometimes I will manually remove some stuff from the state file and delete it once Terraform has performed the cutover.

That stuff is possible to do in CI, but it would be inefficient and painful.

To me, the biggest benefit of Terraform is managing changes to cloud resources. You know what resources are added when, why, and by whom. You have a mechanism for promoting changes between environments confidently. And if your infra ever blew up, you would be able to put stuff back.

I've seen it work best with an embedded plan.

So engineers open a PR with terraform changes, the CI runs `terraform plan`, and comments on the PR with that diff. So you can see if your terraform is valid, if you're going to be destroying things you shouldn't, etc.

Larger, more complex testing is generally done by locally invoking your terraform on a testing environment. How this is setup kind of depends, but I've seen this work well for testing out complex changes before going to the PR & Plan stage.

> For one, building out anything of complexity in Terraform often involves some trial and error to make sure all the resources are wired together correctly.

This seems like misattribution: you do that everywhere when you’re doing something new - the problem is the underlying gap between the understanding of the problem which you started with and what the underlying services actually require. You can avoid most of that by using modules to reduce the amount of new structure you need to develop and static linters (tflint, tfsec, etc.) to flag things in advance.

> For two, there are some Terraform changes that can incur downtime if you just let Terraform destroy and create resources.

This should never be necessary due to Terraform - that’s one of the major advantages over older tools like AWS CloudFormation. If you’re seeing this as a problem where it’s not imposed by the platform (e.g. many AWS resources won’t allow you to change the name after creation) you can use lifecycle rules to avoid forcing re-creation where that makes sense or to create the replacement first & switch over before deleting the old resource. If you relocated the definitions in your code, you can tell Terraform how to migrate old state non-destructively.

"Random shell script is more readable than terraform". Yeah, no. Not if you mean bash, and certainly frickin not if theres a modicum of reliability/retries/recreaet logic in them. I dont think you have a good view of the landscape.
Terraform creates a virtual infrastructure against which diffs can be performed.
It's much more about standardising the approach within a team, and not needing to know your target infrastructure state. Especially at the stage of a scale up, you'll get a lot of differing views as where to write your scripts - Terraform provides tooling for a specific use case where you don't need to reinvent everything.

At Nimbus[1], we have been trialling using Terraform for template definitions as users are mostly familiar with it, and it allows them to integrate more easily with existing CI/CD processes. They can easily just add a new Nimbus Workspace to their Terraform and have it spin up a new development environment when their CI requires it.

[1]: https://usenimbus.com - Easy remote development infra for teams

Terraform isn't for deploying infrastructure, it's for _converging_ infrastructure onto a desired state. Good luck writing a bash script that can deploy hundreds of different, dependent IaaS resources and deal with any or all of the resources initially being misconfigured or missing.
> [why not write shell scripts to do what we need]

The shell script needs to determine, for each resource, whether it exists; if it does exist, what changes to make and how to translate those into API calls, or if it doesn't exist, how to create it, and to clean up any resources no longer in the desired state.

Attributes of some resource that might exist only after creation need to be fed into other resources…

For even a single resource, over the lifetime of the many changes and adjustments to the resource, that is extremely complicated to do correctly in shell alone.

The declarative "desired state" style is more useful since the steps required to be undertaken often depend on the state of the infrastructure that exists, or doesn't exist.

(additionally, you'll also need to notate state about what infra exists and what doesn't, and store that somewhere, and transmit that state to coworkers … and TF handles that, too. While "its obvious" for some infra — i.e., the resource has a natural key — not all resources do, and often you have to deal with unmanaged resources and not decide to delete them simply because they're not part of your desired state.)

Lastly, you have to handle bugs and design flaws in the APIs. I've worked with a number of platforms where two, valid calls to the API in a shell script are a race condition because the API doesn't support read-your-writes.

All this reinvents the wheel that is TF.

There's also "why does this infra exist?": I can comment TF, I get a commit history and rationales for why infra exists. Shell scripts really push people towards "I'll just #yolo this small change to the infra" … and now, I don't know why the infra is the way it is. Often, I find dev/prd have drifted, or two prod instances of the "same" thing are really different. Comments cut down on this, TF modules really cut down on it, etc.

> And what is it? It is a shell script inside of a JSON that was created in the shell! What for are these layers of abstraction? Why does he have to wrap the Resource Group name in a JSON? Why couldn't it be just piped in plaintext format, as all the tools that try to be POSIX-compatible do?

JSON is a text format. Your shell scripter has piped that into what amounts to a buggy, broken, 5% reimplementation of a JSON parser. Pipe that to `jq`, instead. (You can also use --query on az to reduce the output to something that will be more easily handled by `jq`, but anything --query can do, jq can too, pretty much, and it might be better to have all the code in one language.)

Or just request that data from terraform, by accessing the appropriate attribute of the that resource.