Terraform
参考ページ https://qiita.com/donkomura/items/6289bb31fecfce2cda79
環境構築(VSCode)
mauve.terraform
拡張機能を入れる。
settings.json
の設定例:
{
"terraform.indexing": {
"enabled": false,
"liveIndexing": false,
"delay": 500,
"exclude": [".terraform/**/*", "**/.terraform/**/*"]
},
"terraform.languageServer": {
"enabled": true,
"args": []
}
}
Ref: https://qiita.com/pypypyo14/items/5520f3defa55119f3a1a
概要
https://www.terraform.io/intro/index.html
リソースの定義
構文:
resource "<リソースタイプ>" "<リソース名>" {
# ここにリソースの構成を書く
}
リソースの定義には次の 2 つを指定する
- リソースタイプ - 予め決められたリソースタイプ
- リソース名 - 好きな名前を指定する。このリソース名を利用して他のリソースからリソースの値を参照できる
Ubuntu18.04 にインストール
Terraform
本体のインストール。
VERSION="0.12.20"
wget "https://releases.hashicorp.com/terraform/${VERSION}/terraform_${VERSION}_linux_amd64.zip"
unzip "terraform_${VERSION}_linux_amd64.zip"
sudo mv terraform /usr/local/bin
rm "terraform_${VERSION}_linux_amd64.zip"
Ref: https://kazuhira-r.hatenablog.com/entry/2019/04/09/231234
tflint
のインストール。
curl -L "$(curl -Ls https://api.github.com/repos/terraform-linters/tflint/releases/latest | grep -o -E "https://.+?_linux_amd64.zip")" -o tflint.zip && unzip tflint.zip && rm tflint.zip
Ref: https://github.com/terraform-linters/tflint
ベストプラティクス
ozbillwang / terraform-best-practices:AWS ユーザー向けの Terraform のベストプラクティス
Terraform の推奨プラクティス-HashiCorp による Terraform
命名規則
https://www.terraform-best-practices.com/naming
Output Values
Output Values - Configuration Language - Terraform by HashiCorp
Docker で Terraform コマンドを実行する
docker pull hashicorp/terraform:light
Cloud Build で Terraform を実行する
事前準備
Cloud Build を有効化する。
gcloud services enable cloudbuild.googleapis.com compute.googleapis.com
GCP で使う
https://www.terraform.io/docs/providers/google/index.html
terraform 用のサービスアカウントを作る
gcloud init
# アカウントの確認
gcloud config list
terraform 用のサービスアカウントを作る。
PROJECT_ID="<プロジェクトID>"
# サービスアカウントを作成する
gcloud beta iam service-accounts create terraform \
--project $PROJECT_ID \
--display-name "terraform"
# 編集者の権限を付与する
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member serviceAccount:terraform@${PROJECT_ID}.iam.gserviceaccount.com \
--role roles/editor
# プロジェクトIAM管理者権限を付与する
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member serviceAccount:terraform@${PROJECT_ID}.iam.gserviceaccount.com \
--role roles/resourcemanager.projectIamAdmin
# サービスアカウントキーを生成する
gcloud iam service-accounts keys create key_terraform.json \
--iam-account terraform@${PROJECT_ID}.iam.gserviceaccount.com
生成した鍵ファイルのパスをGOOGLE_CLOUD_KEYFILE_JSON
に設定する。
export GOOGLE_CLOUD_KEYFILE_JSON=<PATH>
Ref: https://www.terraform.io/docs/providers/google/guides/getting_started.html#adding-credentials
Terraform の状態を GCS で管理する
terraform_bucket_lifecycle.json
を作成する。
{
"lifecycle": {
"rule": [
{
"action": {
"type": "Delete"
},
"condition": {
"numNewerVersions": 5
}
}
]
}
}
PROJECT_ID="<プロジェクトID>"
# Terraform用のバケットを作成
TERRAFORM_BUCKET=gs://${PROJECT_ID}-managed-by-terraform
gsutil mb -l asia-northeast1 -p $PROJECT_ID $TERRAFORM_BUCKET
gsutil versioning set on $TERRAFORM_BUCKET
gsutil lifecycle set "terraform_bucket_lifecycle.json" $TERRAFORM_BUCKET
StackDriver
filter の指定方法
https://cloud.google.com/monitoring/api/v3/filters?hl=ja
Terraform 起動用スクリプト
#!/usr/bin/env bash
set -euxo pipefail
# サービスアカウントキーの場所(GCS)
TERRAFORM_KEY_OBJECT="gs://<my-bucket>/<my-objet>"
# Terraform状態管理用のバケット(GCS)
TERRAFORM_BUCKET="<terraform-bukcet>"
SCRIPT_DIR=$(cd $(dirname $0); pwd)
source "$SCRIPT_DIR/_config"
# サービスアカウントキーをローカルにコピー
gsutil cp gs://$TERRAFORM_KEY_OBJECT $SCRIPT_DIR/key_terraform.json
# Terraform用のバケットを作成
if ! gsutil ls -b gs://$TERRAFORM_BUCKET ; then
echo "Create new bucket..."
gsutil mb -l asia-northeast1 gs://$TERRAFORM_BUCKET
gsutil versioning set on gs://$TERRAFORM_BUCKET
gsutil lifecycle set "$SCRIPT_DIR/terraform_bucket_lifecycle.json" gs://$TERRAFORM_BUCKET
fi
# デプロイ
(cd $SCRIPT_DIR/terraform \
&& export GOOGLE_CLOUD_KEYFILE_JSON=$SCRIPT_DIR/key_terraform.json \
&& export GOOGLE_APPLICATION_CREDENTIALS=$SCRIPT_DIR/key_terraform.json \
&& terraform init -backend-config="bucket=$TERRAFORM_BUCKET" \
&& terraform plan -var-file="$SCRIPT_DIR/$VAR_FILE" \
&& terraform apply -auto-approve -parallelism=30 -var-file="$SCRIPT_DIR/$VAR_FILE")
実行
# 初回実行時のみ必要
terraform init
terraform apply
Compute Engine
Ref: https://www.terraform.io/docs/providers/google/r/compute_instance.html
resource "google_compute_instance" "vm_instance" {
name = "terraform-instance"
machine_type = "f1-micro"
boot_disk {
initialize_params {
image = "debian-cloud/debian-9"
}
}
network_interface {
# A default network is created for all GCP projects
network = "default"
access_config {
}
}
}
Tips
条件によってリソースの生成する/しないを切り替える
count
を使う。
locals {
use_my_network = true
}
resource "google_compute_network" "my_network" {
# 条件を満たすときのみ生成する
count = local.use_my_network ? 1 : 0
name = "my-network"
}
resource "google_compute_subnetwork" "subnet_my_network" {
count = local.use_my_network ? 1 : 0
name = "subnet-my-network"
ip_cidr_range = "10.0.0.0/14"
region = "asia-northeast1"
# countを使っているので`[0]`が必要
network = google_compute_network.my_network[0].self_link
}
lock を解除
terraform force-unlock <ID>
CI でデプロイ
<PROJECTの番号>@cloudbuild.gserviceaccount.com
に、編集者の権限をつけておく。
steps:
- name: "hashicorp/terraform:0.12.20"
entrypoint: "sh"
args:
- "-c"
- |
echo PROJECT_ID="$PROJECT_ID"
cd terraform
terraform init
terraform validate
terraform workspace select dev && terraform apply -auto-approve
terraform workspace select stage && terraform apply -auto-approve
timeout: 3600s
workspace の名前変更
default
ワークスペースをdev
ワークスペースに変更する場合
gsutil mv gs://<バケット>/terraform/state/{default,dev}.tfstate
Ref:
https://github.com/hashicorp/terraform/issues/16072
環境ごとに構成を切り替える
terraform workspace new
でワークスペースを作成する。
terraform workspace new dev
terraform workspace new stage
terraform workspace new prod
# workspacenの確認
terraform workspace list
リモート状態を使用している場合は、環境ごとに次のように.tfstate
ファイルが分けて管理される。
- <BUCKET_NAME>/terraform/state/default.tfstate
- <BUCKET_NAME>/terraform/state/dev.tfstate
- <BUCKET_NAME>/terraform/state/stage.tfstate
- <BUCKET_NAME>/terraform/state/prod.tfstate
環境ごとの変数の設定は次のように設定する。
locals {
env = {
default = {
instance_type = "t2.micro"
ami = "ami-0ff8a91507f77f867"
instance_count = 1
}
dev = {
instance_type = "m5.2xlarge"
ami = "ami-0130c3a072f3832ff"
}
stage = {
instance_type = "m5.2xlarge"
ami = "ami-00f0abdef923519b0"
instance_count = 3
}
prod = {
instance_type = "c5.4xlarge"
ami = "ami-0422d936d535c63b1"
instance_count = 6
}
}
environmentvars = "${contains(keys(local.env), terraform.workspace) ? terraform.workspace : "default"}
workspace = "${merge(local.env["default"], local.env[local.environmentvars])}"
}
設定値の参照は次のようになる。
instance_type = "${local.workspace["instance_type"]}"
Ref:
Terraform ワークスペースでの環境変数の処理
ダラー(dallor)をエスケープする
$${}
のように$を 2 つ書く。
resource "google_monitoring_alert_policy" "my_policy" {
display_name = "My policy"
combiner = "OR"
conditions {
display_name = "My condition"
condition_threshold {
filter = "metric.type=\"composer.googleapis.com/workflow/task/run_count\" AND resource.type=\"cloud_composer_workflow\" AND metric.label.state = \"failed\""
duration = "0s"
comparison = "COMPARISON_GT" # しきい値を超えたらアラート
threshold_value = 0
aggregations {
alignment_period = "60s"
cross_series_reducer = "REDUCE_NONE"
per_series_aligner = "ALIGN_MAX"
}
trigger {
count = 1
}
}
}
documentation {
mime_type = "text/markdown"
content = <<EOT
## My Alert
$${resource.label.workflow_name}
EOT
}
}
Ref:
Interpolation Syntax
似たようなリソースを複数定義する
count
を使う。
変数を設定する
変数定義にはvariable
を使う。
variable "project_id" {
type = string
}
provider "google" {
project = var.project_id
}
Ref: https://qiita.com/ringo/items/3af1735cd833fb80da75
StackDriver で Slack 通知する
FAQ
Error: Error inspecting states in the "gcs" backend: querying Cloud Storage failed: storage: bucket doesn't exist
.terraform
ディレクトリを削除してから再トライ。