- モチベーション
- GitLabが管理するTerraformの状態
- 現地開発者の利用開始
- GitLab CIを使い始めましょう。
- バックエンドの設定
- プロジェクト例
- Terraform Planの情報をマージリクエストに出力します。
TerraformとGitLabによるコードとしてのインフラストラクチャ
モチベーション
GitLab内のTerraformインテグレーション機能は、GitOps / Infrastructure-as-Code (IaC)ワークフローをGitLabの認証と作成者に連携させることができます。 これらの機能は、チームがTerraformを導入するための参入障壁を下げ、GitLab内で効果的にコラボレーションし、Terraformのベストプラクティスをサポートすることに重点を置いています。
GitLabが管理するTerraformの状態
GitLab 13.0から導入されました。
GitLabはTerraform HTTPバックエンドを使用して、ステートファイルをローカルストレージ(デフォルト)または選択したリモートストアに安全に保存します。
GitLabが管理するTerraformのステートバックエンドは、Terraformのステートを簡単かつセキュアに保存することができ、Amazon S3やGoogle Cloud Storageのような追加のリモートリソースを設定する必要がありません。 その機能は以下の通りです:
- 転送中および停止中のステートファイルの暗号化をサポートします。
- ロックとアンロックの状態。
- リモートTerraformプランと適用実行。
GitLabが管理するTerraform Stateを始めるには、2つの異なるオプションがあります:
- ローカルマシンを使用してください。
- GitLab CIを使いましょう。
現地開発者の利用開始
terraform plan
とterraform apply
のコマンドだけをローカルマシンから実行するつもりであれば、これは簡単な方法です:
- GitLab インスタンスにプロジェクトを作成します。
- settings} 設定>一般に移動し、プロジェクト名とプロジェクトIDをメモしてください。
-
TerraformプロジェクトのTerraformバックエンドを次のように定義します:
terraform { backend "http" { } }
-
api
スコープでパーソナルアクセストークンを作成します。 Terraform バックエンドはリポジトリへのメンテナーのアクセス権を持つユーザーに制限されます。 -
ローカルマシンで、
terraform init
を実行します。<YOUR-PROJECT-NAME>
、<YOUR-PROJECT-ID>
、<YOUR-USERNAME>
、<YOUR-ACCESS-TOKEN>
を該当する値に置き換えて、以下のオプションを渡します。 このコマンドはTerraformの状態を初期化し、その状態をGitLabプロジェクト内に保存します。この例では、gitlab.com
を使っています:terraform init \ -backend-config="address=https://gitlab.com/api/v4/projects/<YOUR-PROJECT-ID>/terraform/state/<YOUR-PROJECT-NAME>" \ -backend-config="lock_address=https://gitlab.com/api/v4/projects/<YOUR-PROJECT-ID>/terraform/state/<YOUR-PROJECT-NAME>/lock" \ -backend-config="unlock_address=https://gitlab.com/api/v4/projects/<YOUR-PROJECT-ID>/terraform/state/<YOUR-PROJECT-NAME>/lock" \ -backend-config="username=<YOUR-USERNAME>" \ -backend-config="password=<YOUR-ACCESS-TOKEN>" \ -backend-config="lock_method=POST" \ -backend-config="unlock_method=DELETE" \ -backend-config="retry_wait_min=5"
次に、バックエンドを設定します。
GitLab CIを使い始めましょう。
ローカル開発から始めたくない場合は、GitLab CIを使ってterraform plan
、terraform apply
コマンドを実行することもできます。
次に、バックエンドを設定します。
バックエンドの設定
terraform init
コマンドを実行した後、Terraform バックエンドと CI YAML ファイルを設定する必要があります:
-
Terraformプロジェクトで、
.tf
ファイル (backend.tf
など) に以下のコードブロックを追加してHTTPバックエンドを定義し、リモートバックエンドを定義します:terraform { backend "http" { } }
-
プロジェクトリポジトリのルートディレクトリで、
.gitlab-ci.yaml
ファイルを設定します。この例では、gitlab-terraform
ヘルパーを含むビルド済みイメージを使用します。サポートされている Terraform のバージョンについては、GitLab Terraform Images プロジェクトを参照してください。image: registry.gitlab.com/gitlab-org/terraform-images/stable:latest
-
.gitlab-ci.yaml
ファイルでは、開発を容易にするためにいくつかの環境変数を定義します。 このインスタンスでは、TF_STATE
は Terraform のステートの名前(プロジェクトは複数のステートを持つことができます)、TF_ADDRESS
はこのパイプラインを実行する GitLab インスタンス上のステートの URL、TF_ROOT
は Terraform コマンドを実行するディレクトリです:variables: TF_STATE: ${CI_PROJECT_NAME} TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${TF_STATE} TF_ROOT: ${CI_PROJECT_DIR}/environments/cloudflare/production cache: key: ${TF_STATE} paths: - ${TF_ROOT}/.terraform
-
before_script
で、TF_ROOT
:before_script: - cd ${TF_ROOT} stages: - prepare - validate - build - deploy init: stage: prepare script: - gitlab-terraform init validate: stage: validate script: - gitlab-terraform validate plan: stage: build script: - 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: - gitlab-terraform apply dependencies: - plan when: manual only: - master
-
プロジェクトを GitLab にプッシュすると、CI ジョブパイプラインが起動します。 このパイプラインは
gitlab-terraform init
,gitlab-terraform validate
,gitlab-terraform plan
コマンドを実行します。
上記のterraform
コマンドの出力は、ジョブ・ログで見ることができるはずです。
プロジェクト例
GitLabとTerraformを使ってカスタムVPC内に基本的なAWS EC2をデプロイするリファレンスプロジェクトをご覧ください。
Terraform Planの情報をマージリクエストに出力します。
GitLab Terraform Reportアーティファクトを使うことで、terraform plan
の実行の詳細をマージリクエストウィジェットに直接公開することができ、Terraformが作成、変更、破棄するリソースに関する統計を見ることができます。
GitLab Terraform Report のアーティファクトを設定する方法を探ってみましょう。gitlab-terraform plan-json
が必要なアーティファクトを出力する、上記のようなgitlab-terraform
ヘルパーを含むビルド済みイメージを使うか、以下のように手動で設定することができます:
-
簡単にするために、これらのファイルを複数回参照できるように、再利用可能な変数をいくつか定義しましょう:
variables: PLAN: plan.cache PLAN_JSON: plan.json
-
軽量で柔軟なコマンドライン JSON プロセッサ
jq
をインストールします。 -
terraform plan
出力から抽出したい情報を解析する、特定のjq
コマンドのエイリアスを作成します: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)}'"
注意: Bash を使用するディストリビューション (Ubuntu など) では、alias
ステートメントは非インタラクティブモードでは展開されません。convert_report: command not found
というエラーでパイプラインが失敗する場合は、shopt
コマンドをスクリプトに追加することで、エイリアスの展開を明示的に有効にできます: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)}'"
-
terraform plan
とterraform show
を実行するscript
を定義します。これらのコマンドは出力をパイプし、関連するビットをストア変数PLAN_JSON
に変換します。この JSON はGitLab Terraform Report アーティファクトを作成するために使われます。 Terraform レポートは Terraformtfplan.json
ファイルを取得します。収集された Terraform プランレポートはアーティファクトとして GitLab にアップロードされ、マージリクエストに表示されます。plan: stage: build script: - terraform plan -out=$PLAN - terraform show --json $PLAN | convert_report > $PLAN_JSON artifacts: reports: terraform: $PLAN_JSON
ビルド済みイメージを使った完全な例については、例
.gitlab-ci.yaml
ファイルをご覧ください。複数のレポーターを表示する例については、
.gitlab-ci.yaml
複数レポートファイルをご覧ください。 -
パイプラインを実行すると、マージリクエストのウィジェットがこのように表示されます:
-
ウィジェットの[フルログを表示]ボタンをクリックすると、パイプラインログにあるプラン出力に直接アクセスできます:
例.gitlab-ci.yaml
ファイル
image: registry.gitlab.com/gitlab-org/terraform-images/stable:latest
variables:
TF_STATE: ${CI_PROJECT_NAME}
TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${TF_STATE}
TF_ROOT: ${CI_PROJECT_DIR}/environments/cloudflare/production
cache:
key: ${TF_STATE}
paths:
- ${TF_ROOT}/.terraform
before_script:
- cd ${TF_ROOT}
stages:
- prepare
- validate
- build
- deploy
init:
stage: prepare
script:
- gitlab-terraform init
validate:
stage: validate
script:
- gitlab-terraform validate
plan:
stage: build
script:
- 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:
- gitlab-terraform apply
dependencies:
- plan
when: manual
only:
- master
複数のTerraformプランレポーター
13.2以降、マージリクエストページに複数のレポートを表示することができます。 レポートにはartifact: name:
も表示されます。 推奨される設定については、以下の例を参照してください。
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