Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backend examples #21

Closed
wants to merge 12 commits into from
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`.
10 changes: 10 additions & 0 deletions _docs/config/backend/examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Backend Examples
---

Here are several backend examples:

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

Here's an example with the [azurerm backend](https://www.terraform.io/language/settings/backends/azurerm).

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

Azure Resource groups help know the exact resources that belong to an app-env. IE: VMs, DBs, Firewalls, etc. It becomes easy to identify and clean up resources.

There are some resources that are more env-focused. AKS clusters are a good example. It often makes sense to share a dev cluster and deploy your applications onto that cluster. Container density and less maintenance overhead are benefits.

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

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

It does not account for app-env focused resources, though. Since Terraspace does not know what app name, you need to provide the context. One approach is to configure resource_group_name more dynamically:

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 %}

You can now provide `APP` and the resource group will account for it. Example:

APP=app1 terraspace up demo

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

Here's an example with the [gcs backend](https://www.terraform.io/language/settings/backends/gcs).

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 %}
69 changes: 69 additions & 0 deletions _docs/config/backend/examples/gitlab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: "Backend GitLab"
nav_text: "GitLab"
categories: backend-examples
order: 6
---

Here's an example with the [GitLab](https://docs.gitlab.com/ee/user/infrastructure/iac/terraform_state.html) [http backend](https://www.terraform.io/language/settings/backends/http).

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"
```
38 changes: 38 additions & 0 deletions _docs/config/backend/examples/local.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
title: "Backend Local"
nav_text: "Local"
categories: backend-examples
order: 5
---

Here's an example with the [local backend](https://www.terraform.io/language/settings/backends/local).

config/terraform/backend.tf:

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

The local statefile is stored at:

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

Note: When using a local backend, the `config/terraform/backend.tf` file is entirely optional. Terraform defaults to a local backend with the `path = "terraform.tfstate"`. The `backend.tf` is provided as an example and shows you how to change the path.

## Prefix Path

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 %})
36 changes: 36 additions & 0 deletions _docs/config/backend/examples/remote.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: "Backend Remote: TFC and TFE"
nav_text: "Remote TFC"
categories: backend-examples
order: 4
---

Here's an example with the [TFC](https://www.terraform.io/cloud) or [TFE](https://www.terraform.io/enterprise/admin/agents-on-tfe) [remote](https://www.terraform.io/language/settings/backends/remote) backend.

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 %}
43 changes: 43 additions & 0 deletions _docs/config/backend/examples/s3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: Backend S3
nav_text: S3
categories: backend-examples
order: 1
---

Here's an example with the [s3 backend](https://www.terraform.io/language/settings/backends/s3).

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
Loading