summaryrefslogtreecommitdiff
path: root/doc/user/infrastructure/iac/terraform_template_recipes.md
blob: 0d1b56ae979deaf54850181164935f4ecf0a66b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
---
stage: Configure
group: Configure
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

# Terraform template recipes **(FREE)**

You can customize your Terraform integration by adding the recipes on
this page to your pipeline.

If you'd like to share your own Terraform configuration, consider
[contributing a recipe](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/user/infrastructure/iac/terraform_template_recipes.md)
to this page.

## Enable a `terraform destroy` job

Add the following snippet to your `.gitlab-ci.yml`:

```yaml
include:
  - template: Terraform.latest.gitlab-ci.yml

destroy:
  extends: .terraform:destroy
```

The `destroy` job is part of the `cleanup` stage. Like the `deploy`
job, the `destroy` job is always `manual` and is not tied to the
default branch.

## Run a custom `terraform` command in a job

To define a job that runs a custom `terraform` command, the
`gitlab-terraform` wrapper can be used in any job:

```yaml
include:
  - template: Terraform.latest.gitlab-ci.yml

state-list:
  stage: validate # you can use any stage, just make sure to define it
  script: gitlab-terraform state list
```

The `gitlab-terraform` command sets up a `terraform` command and runs
it with the given arguments.

To run this job in the Terraform state-specific [resource group](../../../ci/resource_groups/index.md),
assign the job with `resource_group`:

```yaml
include:
  - template: Terraform.latest.gitlab-ci.yml

state-list:
  stage: validate # you can use any stage, just make sure to define it
  resource_group: ${TF_STATE_NAME}
  script: gitlab-terraform state list
```

## Add custom debug tools to jobs

The default image used by Terraform template jobs contains only minimal tooling.
However, you might want to add additional tools for debugging.

To add an additional tool:

1. Install the tool in the `before_script` of a job or pipeline.
1. Use the tool in the `script` or `after_script` block.
   - If you use the `script` block, be sure to re-add the template job commands.

For example, the following snippet installs `bash` and `jq` in the `before_script` for all
jobs in the pipeline:

```yaml
include:
  - template: Terraform.latest.gitlab-ci.yml

default:
  before_script: apk add --update bash jq
```

To add it to only the `build` and `deploy` jobs, add it to those jobs directly:

```yaml
include:
  - template: Terraform.latest.gitlab-ci.yml

build:
  before_script: apk add --update bash jq

deploy:
  before_script: apk add --update bash jq
```

## Add custom container images

For debug tools and simple installations, you should
[add a custom debug tool to your job](#add-custom-debug-tools-to-jobs).
If your tool is complex or benefits from caching,
you can create a custom container image based on the
[`gitlab-terraform`](https://gitlab.com/gitlab-org/terraform-images) images.
You can use your custom image in subsequent Terraform jobs.

To define a custom container image:

1. Define a new `Dockerfile` with custom tooling. For example, install `bash` and `jq` in `.gitlab/ci/Dockerfile`:

   ```dockerfile
   FROM registry.gitlab.com/gitlab-org/terraform-images/stable:latest

   RUN apk add --update bash jq
   ```

1. In a new job, define a `prepare` stage that builds the image whenever the `Dockerfile` changes.
   - The built image is pushed to the [GitLab Container Registry](../../packages/container_registry). A tag is applied to indicate whether the image was built from a merge request or from the default branch.
1. Use your image in your Terraform jobs, such as `build` and `deploy`.
   - You can combine your image with specialized `before_script` configurations to perform setup commands, like to generate inputs for Terraform.

For example, a fully functioning pipeline configuration might look like:

```yaml
include:
  - template: Terraform.latest.gitlab-ci.yml

variables:
  IMAGE_TAG: latest

workflow:
  rules:
    - if: $CI_MERGE_REQUEST_IID
      changes:
        - .gitlab/ci/Dockerfile
      variables:
        IMAGE_TAG: ${CI_COMMIT_REF_SLUG}
    - when: always

stages:
  - prepare
  - validate
  - test
  - build
  - deploy
  - cleanup

prepare:image:
  needs: []
  stage: prepare
  image:
    name: gcr.io/kaniko-project/executor:v1.9.0-debug
    entrypoint: [""]
  rules:
    # Tag with the commit SHA if we're in an MR
    - if: $CI_MERGE_REQUEST_IID
      changes:
        - .gitlab/ci/Dockerfile
      variables:
        DOCKER_TAG: $CI_COMMIT_REF_SLUG
    # If we're on our main branch, tag with "latest"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      changes:
        - .gitlab/ci/Dockerfile
      variables:
        DOCKER_TAG: latest
  before_script:
    # Authenticate to the docker registry and dependency proxy
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json
  script:
    - /kaniko/executor
      --context "${CI_PROJECT_DIR}/.gitlab/ci"
      --cache=true
      --dockerfile "${CI_PROJECT_DIR}/.gitlab/ci/Dockerfile"
      --destination "${CI_REGISTRY_IMAGE}:${DOCKER_TAG}"

build:
  image: ${CI_REGISTRY_IMAGE}:${IMAGE_TAG}

deploy:
  image: ${CI_REGISTRY_IMAGE}:${IMAGE_TAG}
```

For an example repository, see the [GitLab Terraform template usage project](https://gitlab.com/gitlab-org/configure/examples/terraform-template-usage).

## Deploy Terraform to multiple environments

You can run pipelines in multiple environments, each with a unique Terraform state.

```yaml
stages:
  - validate
  - test
  - build
  - deploy

include:
  - template: Terraform/Base.latest.gitlab-ci.yml
  - template: Jobs/SAST-IaC.latest.gitlab-ci.yml

variables:
  # x prevents TF_STATE_NAME from beeing empty for non environment jobs like validate
  # wait for https://gitlab.com/groups/gitlab-org/-/epics/7437 to use variable defaults
  TF_STATE_NAME: x${CI_ENVIRONMENT_NAME}
  TF_CLI_ARGS_plan: "-var-file=vars/${CI_ENVIRONMENT_NAME}.tfvars"

fmt:
  extends: .terraform:fmt
validate:
  extends: .terraform:validate

plan dev:
  extends: .terraform:build
  environment:
    name: dev
plan prod:
  extends: .terraform:build
  environment:
    name: prod

apply dev:
  extends: .terraform:deploy
  environment:
    name: dev

apply prod:
  extends: .terraform:deploy
  environment:
    name: prod
```

This configuration is modified from the [base GitLab template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform/Base.gitlab-ci.yml).