概要
インフラも IaC(コード)化して CIやりましょ! ってことで、GitLab CI/CDパイプライン を利用して Azure 上に ResourceGroup を作成してみました。
実行環境
macOS Monterey 12.3.1
python 3.8.12
Azure CLI 2.34.1
事前準備
-
この記事 にあるように Terraform用のサービスプリンシパルが準備されており、以下のシークレット情報を入手できていること
- ARM_TENANT_ID
- ARM_SUBSCRIPTION_ID
- ARM_CLIENT_ID
- ARM_CLIENT_SECRET
Gitlab での仕込み
Gitlab の Personal Access Token の作成
- Gitlab CI/CD の job を実行する権限を有するアクセストークンを発行します(git clone/push時に必要)
- サインインアカウントの「Edit profile」-「Access token」を選択
- 「Token name」に一意の名称を入力後、「Select scopes」で、「api」を選択する
- 「Create personal access token」ボタンを押す
- 画面上部に表示される「パーソナルアクセストークン」をどこかにコピーしておく
Gitlab リポジトリの作成
- GitlabにてTerraformのコードを管理するリポジトリ(プライベートリポジトリで可)を作成し、ローカルで git clone します
Gitlab へのシークレット登録
必要なコード
Terraformコード
今回は以下の3つのコードで構成されています(リソースグループを作成するだけなので、、、)
# プロバイダーの定義
terraform {
required_providers {
azurerm = "~> 2.33"
}
# tfstateファイルを gitlab に保存
backend "http" {
}
}
provider "azurerm" {
features {}
tenant_id = var.ARM_TENANT_ID
subscription_id = var.ARM_SUBSCRIPTION_ID
client_id = var.ARM_CLIENT_ID
client_secret = var.ARM_CLIENT_SECRET
}
# リソースグループ
resource "azurerm_resource_group" "this" {
name = var.resource_group_name
location = var.region
tags = var.tags_def
}
# 環境変数(Azureサービスプリンシパル)
variable "ARM_TENANT_ID" {}
variable "ARM_SUBSCRIPTION_ID" {}
variable "ARM_CLIENT_ID" {}
variable "ARM_CLIENT_SECRET" {}
# タグ情報
variable "tags_def" {
default = {
owner = "ituru"
period = "2022-09-16"
CostCenter = "PSG2"
Environment = "GitLab"
}
}
# 各種パラメータ
variable "region" {} // 利用リージョン
variable "resource_group_name" {} // リソースグループ名
# パラメータ値の定義
region = "japaneast" // 利用リージョン
resource_group_name = "rg_ituru_github" // リソースグループ名
Gitlab CI/CD の yaml ファイルの作成
リポジトリのルートに .gitlab-ci.yml というファイルを作成します。ここに、Gitlab CI/CDパイプライン のコードを記載していきます。記載方法は GitLab CI/CD パイプライン設定リファレンス を参照ください。
## https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Terraform/Base.gitlab-ci.yml
include:
- template: Terraform/Base.gitlab-ci.yml
variables:
TF_ADDRESS: ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/tfstate_filename
cache:
key: tfstate_filename
paths:
- .terraform
before_script:
- export TF_VAR_ARM_TENANT_ID=${ARM_TENANT_ID}
- export TF_VAR_ARM_SUBSCRIPTION_ID=${ARM_SUBSCRIPTION_ID}
- export TF_VAR_ARM_CLIENT_ID=${ARM_CLIENT_ID}
- export TF_VAR_ARM_CLIENT_SECRET=${ARM_CLIENT_SECRET}
- printenv
stages:
- prepare
- validate
- build
- deploy
- cleanup
init:
stage: prepare
script:
- gitlab-terraform init
rules:
- if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
when: always
- if: '$CI_COMMIT_BRANCH == "main"'
validate:
stage: validate
script:
- gitlab-terraform validate
rules:
- if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
when: always
- if: '$CI_COMMIT_BRANCH == "main"'
plan:
stage: build
script:
- gitlab-terraform plan
- gitlab-terraform plan-json
artifacts:
name: plan
paths:
- plan.cache
reports:
terraform: plan.json
rules:
- if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
when: always
- if: '$CI_COMMIT_BRANCH == "main"'
apply:
stage: deploy
script:
- gitlab-terraform apply
dependencies:
- plan
rules:
- if: '$CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
when: never
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
destroy:
stage: cleanup
script:
- gitlab-terraform destroy
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
.gitlab-ci.ymlの解説
include
githubで用意されているテンプレートを利用し、terraform 実行環境のコンテナを使用します。
variables
tfstateファイルをおく httpエンドポイント が作成され Jobの実行時にその場所を変数として持たせています。
cache
terraform 実行結果の成果物(tfstateファイル)を stage 間で利用できるようにするための設定です。
before_script
このリポジトリに設定された変数を読み込み、環境変数として定義します。
stages
パイプラインにおける各 stage を設定します。
Terraform なので、init > validate > plan > apply > destory という構成になっています。
init
terraform init するステージです。
mainブランチに対するマージリクエストが承認(mainブランチが更新)されると自動実行します。
validate
terraform validate するステージです。
mainブランチに対するマージリクエストが承認(mainブランチが更新)されると自動実行します。
plan
terraform plan するステージです。
mainブランチに対するマージリクエストが承認(mainブランチが更新)されると自動実行します。
terraform plan の実行結果は jsonファイルとして artifacts に保存されます。
apply
terraform apply するステージです。
手動による実行となります。
destory
terraform destory するステージです。
手動による実行となります。
git push してみる
これで、準備完了です。git push することにより、terraform plan による Azure への ResourceGroup の作成がおこなわれます。
push
git add .
git commit -m "Actions commit"
git push -u origin main
Actions
GitHub Actions のジョブを確認します。順次処理が実施され、plan までエラーもなく正常に終了しています。
※下図はすべてのジョブを実行したあとのものです、、、、
Azure リソースの作成と削除
CI/CDパイプラインのジョブ からリソースの作成(ステージ:deploy)と削除(ステージ:cleanup)を手動実行します。
リソースの作成
CI/CDパイプラインのジョブ において、terraform apply(ステージ:deploy)を実行すると ResourceGroup の作成がおこなわれます。 問題なくリソースが作成されていることを確認できます。
$ az group show --name rg_ituru_gitlab
{
"id": "/subscriptions/xxxxxxxx-1717-4343-9797-zzzzzzzzzzzz/resourceGroups/rg_ituru_gitlab",
"location": "japaneast",
"managedBy": null,
"name": "rg_ituru_gitlab",
"properties": {
"provisioningState": "Succeeded"
},
"tags": {
"CostCenter": "PSG2",
"Environment": "GitLab",
"owner": "ituru",
"period": "2022-09-16"
},
"type": "Microsoft.Resources/resourceGroups"
}
tfstateファイルは以下の場所にあります。ダウンロードして確認ください。
リソースの削除
CI/CDパイプラインのジョブ において、terraform destory(ステージ:cleanup)を実行すると ResourceGroup の削除がおこなわれます。 問題なくリソースが削除されていることを確認できます。
$ az group show --name rg_ituru_gitlab
(ResourceGroupNotFound) Resource group 'rg_ituru_gitlab' could not be found.
Code: ResourceGroupNotFound
Message: Resource group 'rg_ituru_gitlab' could not be found.
まとめ
GitLab CI/CDパイプライン を利用した Terraform による Azureリソースの作成・削除するための実装方法を簡単に理解することができました。
ちなみに、GitHub Actions でも同様なことを試しています。
- GitHub Actions から Terraform で Azure の ResourceGroup を作成してみました
- GitHub Actions から Terraform で Azure の ResourceGroup を更新(変更)してみました
- GitHub Actions から Terraform destroy してみました
参考記事
以下の記事を参考にさせていただきました。感謝申し上げます
Terraform と GitLab CI で インフラCI/CD入門
Terraform プロジェクトの .gitlab-ci.yml テンプレート
terraform の tfstate の管理に GitLab を使ってみた
GitとCI/CDに関する知識ゼロのSEが、GitLabでhttpsでクローンとプッシュを試すだけの記事
GitとCI/CDに関する知識ゼロのSEが、リポジトリにソースコードがない状態でGitLabのCI/CDパイプライン (DAG) を構成する話
Predefined variables reference