Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'doc/user/infrastructure/index.md')
-rw-r--r--doc/user/infrastructure/index.md211
1 files changed, 150 insertions, 61 deletions
diff --git a/doc/user/infrastructure/index.md b/doc/user/infrastructure/index.md
index c17d1831b50..e24e669d994 100644
--- a/doc/user/infrastructure/index.md
+++ b/doc/user/infrastructure/index.md
@@ -6,8 +6,17 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Infrastructure as code with Terraform and GitLab
+## Motivation
+
+The Terraform integration features within GitLab enable your GitOps / Infrastructure-as-Code (IaC)
+workflows to tie into GitLab's authentication and authorization. These features focus on
+lowering the barrier to entry for teams to adopt Terraform, collaborate effectively within
+GitLab, and support Terraform best practices.
+
## GitLab managed Terraform State
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2673) in GitLab 13.0.
+
[Terraform remote backends](https://www.terraform.io/docs/backends/index.html)
enable you to store the state file in a remote, shared store. GitLab uses the
[Terraform HTTP backend](https://www.terraform.io/docs/backends/types/http.html)
@@ -27,6 +36,14 @@ To get started with a GitLab-managed Terraform State, there are two different op
- [Use a local machine](#get-started-using-local-development).
- [Use GitLab CI](#get-started-using-gitlab-ci).
+## Permissions for using Terraform
+
+In GitLab version 13.1, [Maintainer access](../permissions.md) was required to use a
+GitLab managed Terraform state backend. In GitLab versions 13.2 and greater,
+[Maintainer access](../permissions.md) is required to lock, unlock and write to the state
+(using `terraform apply`), while [Developer access](../permissions.md) is required to read
+the state (using `terraform plan -lock=false`).
+
## Get started using local development
If you plan to only run `terraform plan` and `terraform apply` commands from your
@@ -45,8 +62,7 @@ local machine, this is a simple way to get started:
```
1. Create a [Personal Access Token](../profile/personal_access_tokens.md) with
- the `api` scope. The Terraform backend is restricted to users with
- [Maintainer access](../permissions.md) to the repository.
+ the `api` scope.
1. On your local machine, run `terraform init`, passing in the following options,
replacing `<YOUR-PROJECT-NAME>`, `<YOUR-PROJECT-ID>`, `<YOUR-USERNAME>` and
@@ -80,10 +96,6 @@ Next, [configure the backend](#configure-the-backend).
After executing the `terraform init` command, you must configure the Terraform backend
and the CI YAML file:
-CAUTION: **Important:**
-The Terraform backend is restricted to users with [Maintainer access](../permissions.md)
-to the repository.
-
1. In your Terraform project, define the [HTTP backend](https://www.terraform.io/docs/backends/types/http.html)
by adding the following code block in a `.tf` file (such as `backend.tf`) to
define the remote backend:
@@ -95,64 +107,75 @@ to the repository.
}
```
-1. In the root directory of your project repository, configure a `.gitlab-ci.yaml` file.
- This example uses a pre-built image:
+1. In the root directory of your project repository, configure a
+ `.gitlab-ci.yaml` file. This example uses a pre-built image which includes a
+ `gitlab-terraform` helper. For supported Terraform versions, see the [GitLab
+ Terraform Images project](https://gitlab.com/gitlab-org/terraform-images).
```yaml
- image:
- name: hashicorp/terraform:light
- entrypoint:
- - '/usr/bin/env'
- - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
+ image: registry.gitlab.com/gitlab-org/terraform-images/stable:latest
```
-1. In the `.gitlab-ci.yaml` file, define some environment variables to ease development. In this
- example, `GITLAB_TF_ADDRESS` is the URL of the GitLab instance where this pipeline
- runs, and `TF_ROOT` is the directory where the Terraform commands must be executed:
+1. In the `.gitlab-ci.yaml` file, define some environment variables to ease
+ development. In this example, `TF_ROOT` is the directory where the Terraform
+ commands must be executed, `TF_ADDRESS` is the URL to the state on the GitLab
+ instance where this pipeline runs, and the final path segment in `TF_ADDRESS`
+ is the name of the Terraform state. Projects may have multiple states, and
+ this name is arbitrary, so in this example we will set it to the name of the
+ project, and we will ensure that the `.terraform` directory is cached between
+ jobs in the pipeline using a cache key based on the state name:
```yaml
variables:
- GITLAB_TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${CI_PROJECT_NAME}
TF_ROOT: ${CI_PROJECT_DIR}/environments/cloudflare/production
+ TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${CI_PROJECT_NAME}
cache:
+ key: ${CI_PROJECT_NAME}
paths:
- - .terraform
+ - ${TF_ROOT}/.terraform
```
-1. In a `before_script`, pass a `terraform init` call containing configuration parameters
- corresponding to variables required by the
- [HTTP backend](https://www.terraform.io/docs/backends/types/http.html):
+1. In a `before_script`, change to your `TF_ROOT`:
```yaml
before_script:
- cd ${TF_ROOT}
- - terraform --version
- - terraform init -backend-config="address=${GITLAB_TF_ADDRESS}" -backend-config="lock_address=${GITLAB_TF_ADDRESS}/lock" -backend-config="unlock_address=${GITLAB_TF_ADDRESS}/lock" -backend-config="username=gitlab-ci-token" -backend-config="password=${CI_JOB_TOKEN}" -backend-config="lock_method=POST" -backend-config="unlock_method=DELETE" -backend-config="retry_wait_min=5"
stages:
+ - prepare
- validate
- build
- - test
- deploy
+ init:
+ stage: prepare
+ script:
+ - gitlab-terraform init
+
validate:
stage: validate
script:
- - terraform validate
+ - gitlab-terraform validate
plan:
stage: build
script:
- - terraform plan
- - terraform show
+ - gitlab-terraform plan
+ - gitlab-terraform plan-json
+ artifacts:
+ name: plan
+ paths:
+ - ${TF_ROOT}/plan.cache
+ reports:
+ terraform: ${TF_ROOT}/plan.json
apply:
stage: deploy
environment:
name: production
script:
- - terraform apply
+ - gitlab-terraform apply
dependencies:
- plan
when: manual
@@ -160,8 +183,9 @@ to the repository.
- master
```
-1. Push your project to GitLab, which triggers a CI job pipeline. This pipeline runs
- the `terraform init`, `terraform validate`, and `terraform plan` commands.
+1. Push your project to GitLab, which triggers a CI job pipeline. This pipeline
+ runs the `gitlab-terraform init`, `gitlab-terraform validate`, and
+ `gitlab-terraform plan` commands.
The output from the above `terraform` commands should be viewable in the job logs.
@@ -176,15 +200,18 @@ you can expose details from `terraform plan` runs directly into a merge request
enabling you to see statistics about the resources that Terraform will create,
modify, or destroy.
-Let's explore how to configure a GitLab Terraform Report artifact:
+Let's explore how to configure a GitLab Terraform Report artifact. You can
+either use a pre-built image which includes a `gitlab-terraform` helper as
+above, where `gitlab-terraform plan-json` outputs the required artifact, or you
+can configure this manually as follows:
1. For simplicity, let's define a few reusable variables to allow us to
refer to these files multiple times:
```yaml
variables:
- PLAN: plan.tfplan
- PLAN_JSON: tfplan.json
+ PLAN: plan.cache
+ PLAN_JSON: plan.json
```
1. Install `jq`, a
@@ -198,6 +225,18 @@ Let's explore how to configure a GitLab Terraform Report artifact:
- alias convert_report="jq -r '([.resource_changes[]?.change.actions?]|flatten)|{\"create\":(map(select(.==\"create\"))|length),\"update\":(map(select(.==\"update\"))|length),\"delete\":(map(select(.==\"delete\"))|length)}'"
```
+ NOTE: **Note:**
+ In distributions that use Bash (for example, Ubuntu), `alias` statements are not
+ expanded in non-interactive mode. If your pipelines fail with the error
+ `convert_report: command not found`, alias expansion can be activated explicitly
+ by adding a `shopt` command to your script:
+
+ ```yaml
+ before_script:
+ - shopt -s expand_aliases
+ - alias convert_report="jq -r '([.resource_changes[]?.change.actions?]|flatten)|{\"create\":(map(select(.==\"create\"))|length),\"update\":(map(select(.==\"update\"))|length),\"delete\":(map(select(.==\"delete\"))|length)}'"
+ ```
+
1. Define a `script` that runs `terraform plan` and `terraform show`. These commands
pipe the output and convert the relevant bits into a store variable `PLAN_JSON`.
This JSON is used to create a
@@ -212,18 +251,18 @@ Let's explore how to configure a GitLab Terraform Report artifact:
- terraform plan -out=$PLAN
- terraform show --json $PLAN | convert_report > $PLAN_JSON
artifacts:
- name: plan
- paths:
- - $PLAN
reports:
terraform: $PLAN_JSON
```
- For a full example, see [Example `.gitlab-ci.yaml` file](#example-gitlab-ciyaml-file).
+ For a full example using the pre-built image, see [Example `.gitlab-ci.yaml`
+ file](#example-gitlab-ciyaml-file).
+
+ For an example displaying multiple reports, see [`.gitlab-ci.yaml` multiple reports file](#multiple-terraform-plan-reports).
1. Running the pipeline displays the widget in the merge request, like this:
- ![MR Terraform widget](img/terraform_plan_widget_v13_0.png)
+ ![Merge Request Terraform widget](img/terraform_plan_widget_v13_2.png)
1. Clicking the **View Full Log** button in the widget takes you directly to the
plan output present in the pipeline logs:
@@ -233,64 +272,114 @@ Let's explore how to configure a GitLab Terraform Report artifact:
### Example `.gitlab-ci.yaml` file
```yaml
-image:
- name: hashicorp/terraform:light
- entrypoint:
- - '/usr/bin/env'
- - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
+image: registry.gitlab.com/gitlab-org/terraform-images/stable:latest
-# Default output file for Terraform plan
variables:
- GITLAB_TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${CI_PROJECT_NAME}
- PLAN: plan.tfplan
- PLAN_JSON: tfplan.json
- TF_ROOT: ${CI_PROJECT_DIR}
+ TF_ROOT: ${CI_PROJECT_DIR}/environments/cloudflare/production
+ TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${CI_PROJECT_NAME}
cache:
+ key: ${CI_PROJECT_NAME}
paths:
- - .terraform
+ - ${TF_ROOT}/.terraform
before_script:
- - apk --no-cache add jq
- - alias convert_report="jq -r '([.resource_changes[]?.change.actions?]|flatten)|{\"create\":(map(select(.==\"create\"))|length),\"update\":(map(select(.==\"update\"))|length),\"delete\":(map(select(.==\"delete\"))|length)}'"
- cd ${TF_ROOT}
- - terraform --version
- - terraform init -backend-config="address=${GITLAB_TF_ADDRESS}" -backend-config="lock_address=${GITLAB_TF_ADDRESS}/lock" -backend-config="unlock_address=${GITLAB_TF_ADDRESS}/lock" -backend-config="username=${GITLAB_USER_LOGIN}" -backend-config="password=${GITLAB_TF_PASSWORD}" -backend-config="lock_method=POST" -backend-config="unlock_method=DELETE" -backend-config="retry_wait_min=5"
stages:
+ - prepare
- validate
- build
- deploy
+init:
+ stage: prepare
+ script:
+ - gitlab-terraform init
+
validate:
stage: validate
script:
- - terraform validate
+ - gitlab-terraform validate
plan:
stage: build
script:
- - terraform plan -out=$PLAN
- - terraform show --json $PLAN | convert_report > $PLAN_JSON
+ - gitlab-terraform plan
+ - gitlab-terraform plan-json
artifacts:
name: plan
paths:
- - ${TF_ROOT}/plan.tfplan
+ - ${TF_ROOT}/plan.cache
reports:
- terraform: ${TF_ROOT}/tfplan.json
+ terraform: ${TF_ROOT}/plan.json
-# Separate apply job for manual launching Terraform as it can be destructive
-# action.
apply:
stage: deploy
environment:
name: production
script:
- - terraform apply -input=false $PLAN
+ - gitlab-terraform apply
dependencies:
- plan
when: manual
only:
- master
+```
+
+### Multiple Terraform Plan reports
+
+Starting with 13.2, you can display mutiple reports on the Merge Request page. The reports will also display the `artifact: name:`. See example below for a suggested setup.
+
+```yaml
+image:
+ name: registry.gitlab.com/gitlab-org/gitlab-build-images:terraform
+ entrypoint:
+ - '/usr/bin/env'
+ - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
+
+cache:
+ paths:
+ - .terraform
+stages:
+ - build
+
+.terraform-plan-generation:
+ stage: build
+ variables:
+ PLAN: plan.tfplan
+ JSON_PLAN_FILE: tfplan.json
+ before_script:
+ - cd ${TERRAFORM_DIRECTORY}
+ - terraform --version
+ - terraform init
+ - apk --no-cache add jq
+ script:
+ - terraform validate
+ - terraform plan -out=${PLAN}
+ - terraform show --json ${PLAN} | jq -r '([.resource_changes[]?.change.actions?]|flatten)|{"create":(map(select(.=="create"))|length),"update":(map(select(.=="update"))|length),"delete":(map(select(.=="delete"))|length)}' > ${JSON_PLAN_FILE}
+ artifacts:
+ reports:
+ terraform: ${TERRAFORM_DIRECTORY}/${JSON_PLAN_FILE}
+
+review_plan:
+ extends: .terraform-plan-generation
+ variables:
+ TERRAFORM_DIRECTORY: "review/"
+ # Review will not include an artifact name
+
+staging_plan:
+ extends: .terraform-plan-generation
+ variables:
+ TERRAFORM_DIRECTORY: "staging/"
+ artifacts:
+ name: Staging
+
+production_plan:
+ extends: .terraform-plan-generation
+ variables:
+ TERRAFORM_DIRECTORY: "production/"
+ artifacts:
+ name: Production
```