Skip to content

Commit

Permalink
feat: Incorporating user feedback on the Getting Started guide (#3648)
Browse files Browse the repository at this point in the history
* wip: Incorporating user feedback on the Getting Started guide

* feat: Cleaning up Getting Started guide leveraging user feedback

* feat: Improving `tfpath` docs

* fix: Markdown linting

* fix: Make sure the VPCs are unique

* fix: Switching to serial subtests for docs test instead of parallel tests

* fix: Seeing if this lets me provision the test examples faster

* fix: Update docs to not provision nat gateway to save time
  • Loading branch information
yhakbar authored Dec 12, 2024
1 parent 521d95f commit 0ad541b
Show file tree
Hide file tree
Showing 61 changed files with 1,098 additions and 26 deletions.
129 changes: 113 additions & 16 deletions docs/_docs/01_getting-started/overview.md

Large diffs are not rendered by default.

19 changes: 13 additions & 6 deletions docs/_docs/01_getting-started/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,18 @@ Depending on why you're looking to adopt Terragrunt, this may be all you need to

With just this empty file, you've already made it so that you no longer need to run `tofu init` or `terraform init` before running `tofu apply` or `terraform apply`. Terragrunt will automatically run `init` for you if necessary. This is a feature called [Auto-init](/docs/features/auto-init/).

This might not be very impressive so far, so you may be wondering _why_ one might want to start using Terragrunt to manage their OpenTofu/Terraform projects. A quick overview of the main benefits of using Terragrunt are covered in the [Quick start](/docs/getting-started/quick-start/), and there is a comprehensive list of features in the [Features](/docs#features) section.
This might not be very impressive so far, so you may be wondering _why_ one might want to start using Terragrunt to manage their OpenTofu/Terraform projects. The next section will give you a very gentle introduction to using Terragrunt, and show you how you can start to leverage Terragrunt to manage your OpenTofu/Terraform projects more effectively.

## Tutorial

What follows is a gentle step-by-step guide to integrating Terragrunt to an existing OpenTofu/Terraform project.
What follows is a gentle step-by-step guide to integrating Terragrunt into a new (or existing) OpenTofu/Terraform project.

For the sake of this tutorial, a minimal set of OpenTofu configurations will be used so that you can follow along. Following these steps will give you an idea of how to integrate Terragrunt into an existing project, even if yours is more complex.

This tutorial will assume the following:

1. You have OpenTofu [installed](https://opentofu.org/docs/intro/install/).
2. You have a basic understanding of OpenTofu or Terraform.
1. You have [OpenTofu](https://opentofu.org/docs/intro/install/) or [Terraform](https://developer.hashicorp.com/terraform/install) installed\*.
2. You have a basic understanding of what OpenTofu/Terraform do.
3. You are using a Unix-like operating system.

This tutorial will not assume the following:
Expand All @@ -47,10 +47,17 @@ This tutorial will not assume the following:
2. You have any experience with Terragrunt.
3. You have any existing Terragrunt, OpenTofu or Terraform projects.

If you would like a less gentle introduction geared towards with an active AWS account, familiarity with OpenTofu/Terraform, and potentially a team actively using Terragrunt, consider starting with the [Overview](/docs/getting-started/overview/).
\* Note that if you have _both_ OpenTofu and Terraform installed, you'll want to read the [terragrunt-tfpath](/docs/reference/cli-options/#terragrunt-tfpath) docs to understand how Terragrunt determines which binary to use.

If you would like a less gentle introduction geared towards users with an active AWS account, familiarity with OpenTofu/Terraform, and potentially a team actively using Terragrunt, consider starting with the [Overview](/docs/getting-started/overview/).

If you start to feel lost, or don't understand a concept, consider reading the [Terminology](/docs/getting-started/terminology/) page before continuing with this tutorial. It has a brief overview of most of the common terms used when discussing Terragrunt.

Finally, note that all of the files created in this tutorial can be copied directly from the code block, none of them are partial files, so you don't have to worry about figuring out where to put the code. Just copy and paste!

You can also see what to expect in your filesystem at each step [here](https://github.com/gruntwork-io/terragrunt/tree/main/test/fixtures/docs/01-quick-start).
<!-- Maintainer's Note: we also test this continuously in `tests/integration_docs_test.go` -->

### Step 1: Create a new Terragrunt project

Let's say you have the following `main.tf` in directory `foo`:
Expand Down Expand Up @@ -154,7 +161,7 @@ resource "local_file" "file" {
Now, just like when using `tofu` alone, you can pass in the value for the `content` variable using the `-var` flag:

```bash
terragrunt apply -auto-approve -var 'content=Hello, Terragrunt!'
terragrunt apply -auto-approve -var content='Hello, Terragrunt!'
```

This is a common pattern when working with Infrastructure as Code (IaC). You typically create IaC that is relatively static, and then as you need to make configurations dynamic, you add variables to your configuration files to introduce dynamicity.
Expand Down
26 changes: 24 additions & 2 deletions docs/_docs/01_getting-started/terminology.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,28 @@ This is still true even when working with multiple units in a stack. Terragrunt

Note that DAGs are _Acyclic_, meaning that there are no loops in the graph. This is because loops would create circular dependencies, which would make it impossible to determine the correct order to resolve resources.

### Don't Repeat Yourself (DRY)

The [Don't Repeat Yourself (DRY)](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) principle is a software development principle that states that duplication in code should be avoided.

Early on, a lot of Terragrunt functionality was designed to make it easier to follow the DRY principle. This was because Terraform users at the time found that they were often repeating the same, or very similar code across multiple configurations. Examples of this included the limitation that remote state and provider configurations needed to be repeated in every root module, and that there were limitations in the dynamicity of these configurations.

Over time, Terragrunt has evolved to provide more features that make it easier to manage infrastructure at scale, and the focus has shifted to offering more tooling for _orchestrating_ infrastructure, rather than simply making it easier to avoid repeating yourself. Many of the features still serve to make it easier to follow the DRY principle, but this is no longer the primary focus of the tool.

Much of the marketing around Terragrunt still emphasizes the DRY principle, as it is a useful way to explain the value of Terragrunt to new users. However, you might miss the forest for the trees if you focus too much on the DRY principle when evaluating Terragrunt. Terragrunt is a powerful tool that can be used to manage infrastructure at scale, and it is worth evaluating it based on its capabilities to do so.

### Blast Radius

[Blast Radius](https://en.wikipedia.org/wiki/Blast_radius) is a term used in software development to describe the potential impact of a change, derived from the term used to describe the potential impact of an explosion.

In the context of infrastructure management, blast radius is used to describe the potential impact (negative or positive) of a change to infrastructure. The larger the blast radius, the more potential impact a change has.

Terragrunt was born out of a need to reduce the blast radii of infrastructure changes. By making it easier to segment state in infrastructure, and to manage dependencies between units, Terragrunt makes it easier to reason about the impact of changes to infrastructure, and to ensure that changes can be made safely.

When using Terragrunt, there is very frequently a mapping between your filesystem and the infrastructure you have provisioned with OpenTofu/Terraform. As such, when changing your current working directory in a Terragrunt project, you end up implicitly changing the blast radius of Terragrunt commands. The more units you have as children of your current working directory (the units in your stack), the more infrastructure you are likely to impact with a Terragrunt command.

As an adage, you can generally think of this property as: "Your current working directory is your blast radius".

### Run

A run is a single invocation of OpenTofu/Terraform by Terragrunt.
Expand Down Expand Up @@ -200,9 +222,9 @@ Like all good feature flags, you are encouraged to use them with good judgement

### IaC Engine

[IaC Engines](/docs/features/engine/) (typically appreviated "Engine") are a way to extend the capabilities of Terragrunt by allowing users to control exactly how Terragrunt performs runs.
[IaC Engines](/docs/features/engine/) (typically abbreviated "Engines") are a way to extend the capabilities of Terragrunt by allowing users to control exactly how Terragrunt performs runs.

Engines allow Terragrunt users to define custom logic for how runs are to be executed, including defining exactly how OpenTofu/Terraform is to be invoked, where OpenTofu/Terraform is to be invoked, etc.
Engines allow Terragrunt users to author custom logic for how runs are to be executed in plugins, including defining exactly how OpenTofu/Terraform is to be invoked, where OpenTofu/Terraform is to be invoked, etc.

### Infrastructure Estate

Expand Down
11 changes: 9 additions & 2 deletions docs/_docs/04_reference/cli-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -839,9 +839,16 @@ explanation). This argument is not used with the `run-all` commands.

**CLI Arg**: `--terragrunt-tfpath`<br/>
**Environment Variable**: `TERRAGRUNT_TFPATH`<br/>
**Requires an argument**: `--terragrunt-tfpath /path/to/terraform-binary`<br/>
**Requires an argument**: `--terragrunt-tfpath /path/to/tofu-or-terraform-binary`<br/>
**Default**: `tofu`<br/>

A custom path to the OpenTofu/Terraform binary. The default is `tofu` in a directory on your PATH.
An explicit path to the `tofu` or `terraform` binary you wish to have Terragrunt use.

Note that if you _only_ have `terraform` installed, and available in your PATH, Terragrunt will automatically use that binary.

If you have _both_ `terraform` and `tofu` installed, and you want to use `terraform`, you can set the `TERRAGRUNT_TFPATH` to `terraform`.

If you have _multiple_ versions of `tofu` and/or `terraform` available, or you have a custom wrapper for `tofu` or `terraform`, you can set the `TERRAGRUNT_TFPATH` to the absolute path of the executable you want to use.

**NOTE**: This will override the `terraform` binary that is used by `terragrunt` in all instances, including
`dependency` lookups. This setting will also override any [terraform_binary]({{site.baseurl}}/docs/reference/config-blocks-and-attributes/#terraform_binary)
Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/docs/01-quick-start/step-01.1/foo/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
variable "content" {}

resource "local_file" "file" {
content = var.content
filename = "${path.module}/hi.txt"
}
Empty file.
4 changes: 4 additions & 0 deletions test/fixtures/docs/01-quick-start/step-01/foo/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resource "local_file" "file" {
content = "Hello, World!"
filename = "${path.module}/hi.txt"
}
Empty file.
6 changes: 6 additions & 0 deletions test/fixtures/docs/01-quick-start/step-02/bar/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
variable "content" {}

resource "local_file" "file" {
content = var.content
filename = "${path.module}/hi.txt"
}
Empty file.
6 changes: 6 additions & 0 deletions test/fixtures/docs/01-quick-start/step-02/foo/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
variable "content" {}

resource "local_file" "file" {
content = var.content
filename = "${path.module}/hi.txt"
}
Empty file.
7 changes: 7 additions & 0 deletions test/fixtures/docs/01-quick-start/step-03/bar/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
variable "content" {}

module "shared" {
source = "../shared"

content = var.content
}
Empty file.
7 changes: 7 additions & 0 deletions test/fixtures/docs/01-quick-start/step-03/foo/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
variable "content" {}

module "shared" {
source = "../shared"

content = var.content
}
Empty file.
6 changes: 6 additions & 0 deletions test/fixtures/docs/01-quick-start/step-03/shared/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
variable "content" {}

resource "local_file" "file" {
content = var.content
filename = "${path.module}/hi.txt"
}
1 change: 1 addition & 0 deletions test/fixtures/docs/01-quick-start/step-04/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.terragrunt-cache
7 changes: 7 additions & 0 deletions test/fixtures/docs/01-quick-start/step-04/bar/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
terraform {
source = "../shared"
}

inputs = {
content = "Hello from bar, Terragrunt!"
}
7 changes: 7 additions & 0 deletions test/fixtures/docs/01-quick-start/step-04/foo/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
terraform {
source = "../shared"
}

inputs = {
content = "Hello from foo, Terragrunt!"
}
6 changes: 6 additions & 0 deletions test/fixtures/docs/01-quick-start/step-04/shared/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
variable "content" {}

resource "local_file" "file" {
content = var.content
filename = "${path.module}/hi.txt"
}
1 change: 1 addition & 0 deletions test/fixtures/docs/01-quick-start/step-05/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.terragrunt-cache
1 change: 1 addition & 0 deletions test/fixtures/docs/01-quick-start/step-05/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Note that this step is the same as the previous step.
7 changes: 7 additions & 0 deletions test/fixtures/docs/01-quick-start/step-05/bar/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
terraform {
source = "../shared"
}

inputs = {
content = "Hello from bar, Terragrunt!"
}
7 changes: 7 additions & 0 deletions test/fixtures/docs/01-quick-start/step-05/foo/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
terraform {
source = "../shared"
}

inputs = {
content = "Hello from foo, Terragrunt!"
}
6 changes: 6 additions & 0 deletions test/fixtures/docs/01-quick-start/step-05/shared/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
variable "content" {}

resource "local_file" "file" {
content = var.content
filename = "${path.module}/hi.txt"
}
1 change: 1 addition & 0 deletions test/fixtures/docs/01-quick-start/step-06/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.terragrunt-cache
11 changes: 11 additions & 0 deletions test/fixtures/docs/01-quick-start/step-06/bar/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
terraform {
source = "../shared"
}

dependency "foo" {
config_path = "../foo"
}

inputs = {
content = "Foo content: ${dependency.foo.outputs.content}"
}
7 changes: 7 additions & 0 deletions test/fixtures/docs/01-quick-start/step-06/foo/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
terraform {
source = "../shared"
}

inputs = {
content = "Hello from foo, Terragrunt!"
}
6 changes: 6 additions & 0 deletions test/fixtures/docs/01-quick-start/step-06/shared/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
variable "content" {}

resource "local_file" "file" {
content = var.content
filename = "${path.module}/hi.txt"
}
3 changes: 3 additions & 0 deletions test/fixtures/docs/01-quick-start/step-06/shared/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "content" {
value = local_file.file.content
}
1 change: 1 addition & 0 deletions test/fixtures/docs/01-quick-start/step-07.1/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.terragrunt-cache
17 changes: 17 additions & 0 deletions test/fixtures/docs/01-quick-start/step-07.1/bar/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
terraform {
source = "../shared"
}

dependency "foo" {
config_path = "../foo"

mock_outputs = {
content = "Mocked content from foo"
}

mock_outputs_allowed_terraform_commands = ["plan"]
}

inputs = {
content = "Foo content: ${dependency.foo.outputs.content}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
terraform {
source = "../shared"
}

inputs = {
content = "Hello from foo, Terragrunt!"
}
6 changes: 6 additions & 0 deletions test/fixtures/docs/01-quick-start/step-07.1/shared/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
variable "content" {}

resource "local_file" "file" {
content = var.content
filename = "${path.module}/hi.txt"
}
3 changes: 3 additions & 0 deletions test/fixtures/docs/01-quick-start/step-07.1/shared/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "content" {
value = local_file.file.content
}
1 change: 1 addition & 0 deletions test/fixtures/docs/01-quick-start/step-07/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.terragrunt-cache
15 changes: 15 additions & 0 deletions test/fixtures/docs/01-quick-start/step-07/bar/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
terraform {
source = "../shared"
}

dependency "foo" {
config_path = "../foo"

mock_outputs = {
content = "Mocked content from foo"
}
}

inputs = {
content = "Foo content: ${dependency.foo.outputs.content}"
}
7 changes: 7 additions & 0 deletions test/fixtures/docs/01-quick-start/step-07/foo/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
terraform {
source = "../shared"
}

inputs = {
content = "Hello from foo, Terragrunt!"
}
6 changes: 6 additions & 0 deletions test/fixtures/docs/01-quick-start/step-07/shared/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
variable "content" {}

resource "local_file" "file" {
content = var.content
filename = "${path.module}/hi.txt"
}
3 changes: 3 additions & 0 deletions test/fixtures/docs/01-quick-start/step-07/shared/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "content" {
value = local_file.file.content
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Configure the remote backend
remote_state {
backend = "s3"

generate = {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
}

config = {
bucket = "__FILL_IN_BUCKET_NAME__"

key = "tofu.tfstate"
region = "__FILL_IN_REGION__"
encrypt = true
dynamodb_table = "__FILL_IN_LOCK_TABLE_NAME__"
}
}

# Configure the AWS provider
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
region = "__FILL_IN_REGION__"
}
EOF
}

# Configure the module
#
# The URL used here is a shorthand for
# "tfr://registry.terraform.io/terraform-aws-modules/vpc/aws?version=5.16.0".
#
# You can find the module at:
# https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest
#
# Note the extra `/` after the `tfr` protocol is required for the shorthand
# notation.
terraform {
source = "tfr:///terraform-aws-modules/vpc/aws?version=5.16.0"
}

# Configure the inputs for the module
inputs = {
name = "step-one-vpc"
cidr = "10.0.0.0/16"

azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

enable_nat_gateway = false
enable_vpn_gateway = false

tags = {
IaC = "true"
Environment = "dev"
}
}

Loading

0 comments on commit 0ad541b

Please sign in to comment.