Skip to content

Commit

Permalink
backend examples
Browse files Browse the repository at this point in the history
  • Loading branch information
tongueroo committed Dec 27, 2021
1 parent fd61886 commit a225147
Show file tree
Hide file tree
Showing 12 changed files with 327 additions and 161 deletions.
15 changes: 7 additions & 8 deletions _docs/config/backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,14 @@ Running:

terraspace up demo

Builds a `.terraspace-cache/dev/stacks/demo/backend.tf` using the `config/terraform/backend.tf`. If you want to just build the files without deploying, you can also use `terraspace build`. Below are examples of backends.
Builds a `.terraspace-cache/dev/stacks/demo/backend.tf` using the `config/terraform/backend.tf`. If you want to just build the files without deploying, you can also use `terraspace build`.

{% include tabs.html %}
## Backend Examples

{% assign docs = site.docs | where: "categories","backend-examples" | sort:"order" %}
{% for doc in docs -%}
* [{{ doc.nav_text }}]({{ doc.url }})
{% endfor %}

___

Expand All @@ -50,9 +55,3 @@ Terraspace expansion will remove the trailing dashes and slashes in case the ins
Will result in:

us-west-2/dev/demo # notice there's no trailing slash

___

## Why Is Env in Bucket Name?

By default, the bucket name has the ENV at the end. This is done so we can easily see which environment the bucket stores Terraform statefiles for. This quickly helps with debugging. If you prefer not to have the ENV at the end of the bucket name, remove it after generating the project with `terraspace new project`.
8 changes: 8 additions & 0 deletions _docs/config/backend/examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: Backend Examples
---

{% assign docs = site.docs | where: "categories","backend-examples" | sort:"order" %}
{% for doc in docs -%}
* [{{ doc.nav_text }}]({{ doc.url }})
{% endfor %}
81 changes: 81 additions & 0 deletions _docs/config/backend/examples/azurerm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
title: Backend Azurerm
nav_text: Azurerm
categories: backend-examples
order: 2
---

config/terraform/backend.tf:

{% highlight sh %}
terraform
terraform {
backend "azurerm" {
resource_group_name = "<%= expansion(':ENV-:LOCATION') %>"
storage_account_name = "<%= expansion('ts:SUBSCRIPTION_HASH:LOCATION:ENV') %>"
container_name = "terraform-state"
key = "<%= expansion(':LOCATION/:ENV/:BUILD_DIR/terraform.tfstate') %>"
}
}
{% endhighlight %}

Notice the variable notation. Terraspace expands it out, substituting the values. The starter `backend.tf`
accounts for `LOCATION`, `ENV`, etc. Here's an expanded example:

{% highlight sh %}
terraform {
backend "azurerm" {
resource_group_name = "dev-eastus"
storage_account_name = "tswxyzeastusdev"
container_name = "terraform-state"
key = "eastus/dev/stacks/demo/terraform.tfstate"
}
}
{% endhighlight %}

Note, the `SUBSCRIPTION_HASH` is a short 4-char consistent hash of the longer subscription id. This is useful because azure storage account names are not allowed special characters and are limited to 24 chars.

## Resource Group Name Thoughts

The default `resource_group_name` name is env-focused. Azure Resource Groups often make more sense to be app-env scoped. For example:

app-env focused:

* app1-dev
* app1-prod
* app2-dev
* app2-prod

We then know exactly what app and env the resources within the Azure Resource Groups belong to. IE: VMs, DBs, Firewalls, etc. This makes it easy to identify resources as well as clean up resources.

There are definitely some resources that are more env-focused, though. For example, AKS clusters. It often makes sense to have a dev cluster and deploy your applications onto that cluster. You get container density as a benefit.

The default `resource_group_name` and is env-focused and accounts for the use-case of shared resources like AKS clusters nicely.

resource_group_name = "<%= expansion(':ENV-:LOCATION') %>"

It does not account for app-env focused resources, though. Since Terraspace does not know what app name, it does not include it. One approach is to more dynamically configure resource_group_name like so:

config/terraform/backend.tf:

{% highlight sh %}
<%
def resource_group_name
if ENV['APP']
expansion("#{ENV['APP']}-:ENV-:LOCATION")
else
expansion(":ENV-:LOCATION")
end
end
%>

terraform {
backend "azurerm" {
resource_group_name = "<%= resource_group_name %>"
storage_account_name = "<%= expansion('ts:SUBSCRIPTION_HASH:LOCATION:ENV') %>"
container_name = "terraform-state"
key = "<%= expansion(':LOCATION/:ENV/:BUILD_DIR/terraform.tfstate') %>"
}
{% endhighlight %}

If the infrastructure components for the app is really unique, then it may also make sense to have an entirely different terraspace project.
32 changes: 32 additions & 0 deletions _docs/config/backend/examples/gcs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
title: Backend GCS
nav_text: GCS
categories: backend-examples
order: 3
---

config/terraform/backend.tf:

{% highlight sh %}
terraform
terraform {
backend "gcs" {
bucket = "<%= expansion('terraform-state-:PROJECT-:REGION-:ENV') %>"
prefix = "<%= expansion(':REGION/:ENV/:BUILD_DIR') %>"
}
}
{% endhighlight %}

Notice the variable notation. Terraspace expands it out, substituting the values. The starter `backend.tf` accounts for `PROJECT`, `ENV`, etc. Here's an expanded example:

{% highlight sh %}
terraform
terraform {
backend "gcs" {
bucket = "terraform-state-google-project-id-us-central1-dev"
prefix = "us-central1/dev/stacks/demo"
}
}
{% endhighlight %}

{% include config/backend/env-in-bucket-name.md %}
67 changes: 67 additions & 0 deletions _docs/config/backend/examples/gitlab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
title: "Backend GitLab"
nav_text: "GitLab"
categories: backend-examples
order: 6
---

config/terraform/backend.tf:

```
terraform {
backend "http" {
address = "<%= ENV['GITLAB_PROJECT_URL'] %>/<%= expansion(":ENV-:TYPE_DIR-:MOD_NAME") %>"
lock_address = "<%= ENV['GITLAB_PROJECT_URL'] %>/<%= expansion(":ENV-:TYPE_DIR-:MOD_NAME") %>/lock"
unlock_address = "<%= ENV['GITLAB_PROJECT_URL'] %>/<%= expansion(":ENV-:TYPE_DIR-:MOD_NAME") %>/lock"
username = "<%= ENV['GITLAB_USER'] %>"
password = "<%= ENV['GITLAB_ACCESS_TOKEN'] %>"
lock_method = "POST"
unlock_method = "DELETE"
retry_wait_min = 5
}
}
```

You can set the env var defaults with the [config/boot.rb]({% link _docs/config/boot.md %}) hook.

config/boot.rb:

```ruby
ENV['GITLAB_PROJECT_ID'] ||= 'your project id'
ENV['GITLAB_USER'] ||= 'gitlab-user'
ENV['GITLAB_ACCESS_TOKEN'] ||= 'gitlab-api-access-token'
ENV['GITLAB_PROJECT_URL'] = "https://gitlab.com/api/v4/projects/#{ENV['GITLAB_PROJECT_ID']}/terraform/state"
```

## Including Region

When a http backend is used, a generic expander is used and `:REGION` is not expanded. This is because you can use the http backend without any `terraspace_plugin_*` at all . If you want to include `:REGION` in the expansion helper, here's one way to do that:

config/terraform/backend.tf:

```
terraform {
backend "http" {
address = "<%= ENV['GITLAB_PROJECT_URL'] %>/<%= expansion("#{ENV['AWS_REGION']}-:ENV-:TYPE_DIR-:MOD_NAME") %>"
lock_address = "<%= ENV['GITLAB_PROJECT_URL'] %>/<%= expansion("#{ENV['AWS_REGION']}-:ENV-:TYPE_DIR-:MOD_NAME") %>/lock"
unlock_address = "<%= ENV['GITLAB_PROJECT_URL'] %>/<%= expansion("#{ENV['AWS_REGION']}-:ENV-:TYPE_DIR-:MOD_NAME") %>/lock"
username = "<%= ENV['GITLAB_USER'] %>"
password = "<%= ENV['GITLAB_ACCESS_TOKEN'] %>"
lock_method = "POST"
unlock_method = "DELETE"
retry_wait_min = 5
}
}
```

You can set the env var defaults with the [config/boot.rb]({% link _docs/config/boot.md %}) hook.

config/boot.rb:

```ruby
ENV['GITLAB_PROJECT_ID'] ||= 'your project id'
ENV['GITLAB_USER'] ||= 'gitlab-user'
ENV['GITLAB_ACCESS_TOKEN'] ||= 'gitlab-api-access-token'
ENV['GITLAB_PROJECT_URL'] = "https://gitlab.com/api/v4/projects/#{ENV['GITLAB_PROJECT_ID']}/terraform/state"
ENV['AWS_REGION'] ||= "us-east-1"
```
42 changes: 42 additions & 0 deletions _docs/config/backend/examples/local.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
title: "Backend Local"
nav_text: "Local"
categories: backend-examples
order: 5
---

config/terraform/backend.tf:

{% highlight sh %}
terraform {
backend "local" {
path = "<%= expansion('.terraform/state.tfstate') %>"
}
}
{% endhighlight %}

Here's an expanded example:

{% highlight sh %}
terraform {
backend "local" {
path = ".terraform/state.tfstate"
}
}
{% endhighlight %}

The local statefile is stored at:

ls .terraspace-cache/dev/stacks/demo/.terraform/state.tfstate

If you're wondering how the prefix path `.terraspace-cache/dev/stacks/demo` was determined. It's controlled by

config/app.rb:

```ruby
Terraspace.configure do |config|
config.build.cache_dir = ":CACHE_ROOT/:REGION/:ENV/:BUILD_DIR"
end
```

For defaults, see: [config/reference]({% link _docs/config/reference.md %})
34 changes: 34 additions & 0 deletions _docs/config/backend/examples/remote.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
title: "Backend Remote: TFC and TFE"
nav_text: "Remote TFC"
categories: backend-examples
order: 4
---

config/terraform/backend.tf:

{% highlight sh %}
terraform
terraform {
backend "remote" {
organization = "ORG"
workspaces {
name = "<%= expansion(':MOD_NAME-:ENV-:REGION-:INSTANCE') %>"
}
}
}
{% endhighlight %}

Here's an expanded example:

{% highlight sh %}
terraform
terraform {
backend "remote" {
organization = "boltops"
workspaces {
name = "demo-dev-us-west-2"
}
}
}
{% endhighlight %}
41 changes: 41 additions & 0 deletions _docs/config/backend/examples/s3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
title: Backend S3
nav_text: S3
categories: backend-examples
order: 1
---

config/terraform/backend.tf:

{% highlight sh %}
terraform {
backend "s3" {
bucket = "<%= expansion('terraform-state-:ACCOUNT-:REGION-:ENV') %>"
key = "<%= expansion(':REGION/:ENV/:BUILD_DIR/terraform.tfstate') %>"
region = "<%= expansion(':REGION') %>"
encrypt = true
dynamodb_table = "terraform_locks"
}
}
{% endhighlight %}

Notice the variable notation. Terraspace expands it out, substituting the values. The starter `backend.tf`
accounts for `REGION`, `ENV`, etc. Here's an expanded example:

{% highlight sh %}
terraform
terraform {
backend "s3" {
bucket = "terraform-state-111111111111-us-west-2-dev"
key = "us-west-2/dev/stacks/demo/terraform.tfstate"
region = "us-west-2"
encrypt = true
dynamodb_table = "terraform_locks"
}
}
{% endhighlight %}

You can fully control the state file path by adjusting this. The string substitution also makes it clear what
the state path looks like.

{% include config/backend/env-in-bucket-name.md %}
2 changes: 2 additions & 0 deletions _docs/config/cache-dir.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ The `build.cache_dir` can take:

When setting it as a **String**, Terraspace uses it as a pattern and substitute values. For example,

config/app.rb:

```ruby
Terraspace.configure do |config|
config.build.cache_dir = ":CACHE_ROOT/:REGION/:ENV/:BUILD_DIR"
Expand Down
5 changes: 5 additions & 0 deletions _includes/config/backend/env-in-bucket-name.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
___

## Why Is Env in Bucket Name?

By default, the bucket name has the ENV at the end. This is done so we can easily see which environment the bucket stores Terraform statefiles for. This quickly helps with debugging. If you prefer not to have the ENV at the end of the bucket name, remove it after generating the project with `terraspace new project`.
8 changes: 8 additions & 0 deletions _includes/sidebar.html
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@
<li><a href="{% link _docs/config/app.md %}">App</a></li>
<li><a href="{% link _docs/config/backend.md %}">Backend</a>
<ul>
<li><a href="{% link _docs/config/backend/examples.md %}">Examples</a>
<ul>
{% assign docs = site.docs | where: "categories","backend-examples" | sort:"order" %}
{% for doc in docs -%}
<li><a href="{{ doc.url }}">{{ doc.nav_text }}</a></li>
{% endfor %}
</ul>
</li>
<li><a href="{% link _docs/config/backend/variables.md %}">Variables</a></li>
<li><a href="{% link _docs/config/backend/dsl.md %}">DSL</a></li>
</ul>
Expand Down
Loading

0 comments on commit a225147

Please sign in to comment.