公式
https://www.terraform.io/docs/index.html
導入
https://www.terraform.io/guides/core-workflow.html
推奨方法
https://www.terraform.io/docs/cloud/guides/recommended-practices/index.html
https://www.terraform.io/docs/cloud/guides/recommended-practices/part1.html
https://www.terraform.io/docs/cloud/guides/recommended-practices/part2.html
https://www.terraform.io/docs/cloud/guides/recommended-practices/part3.html
https://www.terraform.io/docs/cloud/guides/recommended-practices/part3.1.html
https://www.terraform.io/docs/cloud/guides/recommended-practices/part3.2.html
https://www.terraform.io/docs/cloud/guides/recommended-practices/part3.3.html
https://www.terraform.io/docs/cloud/guides/recommended-practices/part3.4.html
チュートリアル
https://learn.hashicorp.com/collections/terraform/gcp-get-started
HCL
https://www.terraform.io/docs/language/index.html
CLI aka cmd(アルファベットリストから使う)
https://www.terraform.io/docs/cli/auth/index.html
GCP用リファレンス
https://registry.terraform.io/providers/hashicorp/google/latest/docs
お便強
https://qiita.com/minamijoyo/items/1f57c62bed781ab8f4d7
https://qiita.com/donko_/items/6289bb31fecfce2cda79
https://www.apps-gcp.com/infra-automation-01/
https://colsis.jp/blog/gcpterraform/
Infra as codeとしてインフラの構築や設定をコード化できる
特にクラウドだと構築の自動化や構成管理等でのレバレッジが強力
■段階
Terraformとは?基本知識とTerraformのメリット4つを紹介 | テックマガジン from FEnetインフラ必要なリソースをTerraform化>workspaceの活用>main.tfの共通部分をmodule化
moduleは構成に合わないようなリファクタリングが必要になった時にterraform state mv が必要になってとたんにつらい、moduleを細分化しすぎるとvariable と output が大量に必要になって書きづらい、moduleは再利用できる複数のリソースの単位(プログラミング言語でいうところの関数みたいなもの)で作るのがしっくり
リソースの差分を無視するlifecycleブロックを使う
resource "aws_autoscaling_group" "app_1" {
name = "app-asg-1"
lifecycle {
ignore_changes = ["load_balancers"]
create_before_destroy = true//新しいのを作ってから古いのを削除
}
}
外部ファイルを文字列として読み込む
resource "aws_iam_role" "ec2_role" {
name = "ec2-role"
assume_role_policy = "${file("./ec2_assume_role_policy.json")}"
}
1つのディレクトリで複数のStateを扱うWorkspaceという機能もあるのですが、
個人的には普通にディレクトリを分けて管理する方が楽
production/stagingが完全に同じリソース構成で、設定のパラメータの差分がちょっとだけあるという理想的な世界ではWorkspaceでも運用できるかもしれませんが、現実的にはstagingだけリリース前の検証用の一時的なリソースが立ってたりとか、完全に同じ構成にならないことも多いので、モジュールの読み込みの有無や一部の環境だけ存在するリソースなどの差分を吸収できる場所があったほうが都合がよい
Terraform職人再入門2020 - Qiitaモジュールが公式から提供されている
Browse Modules | Terraform RegistryTerraform の terraform.tfvars とは | 30歳未経験からのITエンジニア (se-from30.com)環境情報は外部ファイルが基本
prd/stg/dev環境はprd.tfvars, stg.tfvars, dev.tfvarsを用意
.tfvars 各環境の設定
aws_access_key = "XXXXXXXXXXXXXXXXXXXX"
aws_secret_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
aws_region = "eu-west-1"
main.tf
terraform {
required_version = "= 0.12.26"
}
provider "aws" {
version = "2.66.0"
access_key = var.aws_access_key
secret_key = var.aws_secret_key
region = var.aws_region
}
var.tf 空の受け皿
variable aws_access_key {}
variable aws_secret_key {}
variable aws_region {}
Terraform で変数を使う - Qiita実行時に-var-fileで値ファイルを指定して環境などを切り替えると良いかもしれない
terrafrom plan -var-file=dev.tfvars
terrafrom plan -var-file=prod.tfvars
変数ファイル指定がないときは変数でdefaultに入れておく、descriptionで変数の説明もかける
variable "foo" {
type = "string"
default = "default-var"
description = "Sample Variable"
}
変数ファイルを異なるバックエンド(フォルダ構成)で共有したいときはシンボリックリンクを貼る
ln -s ../common/shared_var.tf shared_var.tf
credentials等の秘匿したい変数を外部のファイルやコマンドライン引数から読み込む
variable "credentials_file" {} @var.tf 変数を定義し空にしておく
credentials = file(var.credentials_file) @main.tf ファイルを読むがファイル名は変数
terraform plan -var 'project=
' -var 'credentials_file=.json' @cmd プロジェクトとクレデンをコマンド時に指定
他にもvars.tfvars設定ファイル(行頭variableが不要)、TF_VAR_環境変数による指定-var-fileで変数ファイルを明示してcmd、ファイル名は.tfvars/.tfvars.json
-varで変数を明示してcmd
順序があり後の読込でオーバーライド
↓
HCLの変数は基本2種類のlocalとvariable
variableはグローバル変数、ファイル外やコマンドラインから使える
その他の変数参照方法としては(上から優先に適応)
コマンド引数 一時的に使用
変数ファイル terraform.tfvars git管理等で外部ファイルで?
環境変数 TF_VAR_ 実行ログに残らない鍵情報等
workspaceは使わない、moduleを限定的に使う
設定をコード化>Gitレポジトリに置く>設定内容、作業履歴の明確化、チームでの運用性向上
■特性
TFの影響を反映するのはterraform applyの時だけ、tfファイルとtfstateの差分を実際にリソース作成する
tfファイルで変更した場合、TFはリソースの再作成を行うので一度消えることになる(大体は単位が権限だったりで影響がないだけでplanで要注意)
terraform planはtfとtfstateと実体の差なので、実体があってもtfstateになければwill be createdでplan時は表示される
terraform importはtfファイルからtfstateへ記載だけを行う(実体からも情報を取得しtfstateに入れる)
カレントdirの全.tfファイルor.tf.jsonを評価するのでtfファイルの名は何でもいい
各リソースに対してTF化するかは選択ができるが、TFする場合はそのリソースに必要な全記載をTFファイルに行う
terraform import tfResourceID.yourResourceName gcpIdentifier のコマンド
terrafrom import google_bigquery_dataset.tf-1 bangboo-prj/test-dataset
tfResourceID(リソースIDというようタイプ:リソース種別)はTF指定のもの、yourResourceName (リソース名)は任意のもの
構成ファイル.tfはローカルのものが使われる、importするとtfstateに反映
GCP identifierはTF公式サイトの各サービスの一番下import項目を見ると指定内容が分かるのでGCPを見て拾ってくる
terraform state list TF化されているリソースを見る
terrarorm apply時にもtfstateは更新される(オプション-refresh=falseで無効可)
またapply時に-target=xxxでデプロイするリソースを特定できる(TFファイルだけでなくTFステートもターゲットになる)
resource "google_sql_database_instance" "instance" {
provider = google-beta
name = "my-database-instance"
}
resource "google_sql_database" "db" {
instance = google_sql_database_instance.instance.name
name = "db"
}
ToSetは値設定をするが順不同で重複を省く
resource "xxx" "aaa" {
for_each = toset(["foo", "bar", "bar"]) でbar, foo
name = each.key
}
for_each/eachのループ
locals {
sg = {
foo = "FOO"
bar = "BAR"
}
}
resource "xxx" "aaa" {
for_each = local.sg
name = each.key
description = each.value
}
mapをリストしたものをfor_each
locals {
images = [
{ name = "foo", image = "alpine" },
{ name = "bar", image = "debian" },
]
}
resource "docker_container" "this" {
for_each = { for i in local.images : i.name => i } # こう書くのが正しい
name = each.value.name
image = each.value.image
}
terraform importはリソース単位、更新はできず削除してから追加 terraform state rm google_bigquery_dataset.tf-1
実設定とimportの内容が違う場合は実設定の情報でtfstate化されるようだ(importは項目を入れ込む感じ?)
なので実環境に変更を加えるにはterrafrom apply、tfstate化もされtfファイル/tfstate/実設定の3者で同じになる
apply時にtfstateと実設定が違う場合、例えば既存設定がある場合は重複エラーになりapplyできず、importしtfstateと実設定を同じにしてから、tfファイルの内容をapplyすることが必要
terraform importで対象プロジェクトを間違えるとハマる
通常のterraform applyではproviderの情報を使用してプロジェクトを決めるが、importはハードコードするのでimportを間違えばなぜ変な変更がでるのかわからなくなる(プロジェクトが変なものはstateを調べ、terraform state rmするしか)
■セットアップ
作業ディレクトリの作成(プロジェクトに対するローカルのフォルダ)
プロバイダを指定したtfファイルの作成(gcsにstateを置く設定が良い
provider "google" {
project = "bangboo-kuso"
}
terraform {
backend "gcs" {
bucket = "bangboo-kuso-terraform"
}
}
terraform init ローカルに対して初期化
プロジェクトレベルownerのサービスアカウントを持っておく
セットアップする際にtfsateのbackend保存場所のbucket部分をコメントアウト
bucketを作るterraformを実施しbucketを作成しつつlocalにtfstateファイルを作成
再度terraformをするとtfstateファイルがbucketにコピーされる
bucket部分のコメントアウトを外すと次回tfからはバケットにtfstate更新する
このときローカルtfstateの内容をバケットに写すか聞かれるが写す
(写さないと差分しかバケットに行かないのでimport等が必要になる)
■既存リソースのTF化のおおよその作業
リソースタイプと名前を定義したtfファイルを作成する(任意のリソース名、基本ユニーク、纏められるものは重複してもいい)
resource "google_cloudfunctions_function" "fuckin" { ... をtfファイルに記載
tfResourceID(リソースIDというようタイプ:リソース種別)とyourResourceName (リソース名) だけで
リソースタイプや個別パラメータは公式ドキュメントを参照しながら定義
https://registry.terraform.io/providers/hashicorp/google/latest/docs
(簡単)tfファイル内で1行目以外は空で、terraform planをするとエラーで必要なものが分かるので、それを埋める
planが通ると自動的に値をサーバから拾ってくる(importすればtfstate.tfに入っている or コピーしてTFに入れる)
planでダメならterraform state show tfResourceID.yourResourceName でstateを見てtfファイルにパラメータを定義していく
暫定に空でリソースをTFファイルに記載しterraform import、次にtfstateを調査する
terraform state list tfstateファイルにあるアセットを一覧
terraform import google_bigquery_table.xxx project/dataset/table インポート
terraform state show google_bigquery_table.xxx tfstateの該当部を表示
terraform state rm google_bigquery_table.xxx インポート取り消し
TF定義は複数の方法がある、最終GCP公式のRestAPIで確認するしか
terraform importする(公式ドキュメントの一番下にimportコマンドの指定がある)
terraform planして差分がなくなるまでtfファイルを修正する
import(tfstate)の修正は一度stateから削除する terraform state rm google_bigquery_dataset.tf-1
(既存リソースがあってもあくまでtfファイルとtfstateの差分なのでinitした状態でplanしてもup-to-dateと表示されるだけ)
tfstateファイルにおかしなものが無いか確認、keyとか含まれないか
■個別
リファレンスでoptionalとなっていてもtfファイルでは必要な場合もある
tfstateファイルからは必要ないとして自動的に削除されるが
スプシをBQでみれるFederatedQueryはテーブルだけ定義しimportしstate show調査
urlをTFファイルに記載する
シャーディング(日付別)テーブルは定義できないのでは
生成するクエリの方をTF化したい
Authorized viewはモジュールがあるがconflictがあり全消えする場合がありTF化にまだ向かない
google_bigquery_dataset_iam_memberでもAuthorized viewをはがしてしまう。
Authorized viewを使っている個所は google_bigquery_dataset_access あるいは google_bigquery_dataset の access フィールドを使う。
google_bigquer_dataset_iam_policy と google_bigquery_iam_binding は Authoritative で権限追加でなく権限強制設定でコンソール付与分を引き剝がすので、使わない方が安全。
なお、Authorized view と Routines はTerraform化できない事が分かっている(2022/4時点)
ScheduledQuery は Terraform化できるが実行者の設定ができない(Terraform実行者がSQ実行者?誰?)
BQ関連ではデータセット定義、テーブル定義、ビュー定義、フェデレテッドクエリ定義、ScheduledQuery定義をTerraformで行い
BQ権限定義、AuthorizedView定義、Routines定義は行わない
BQ権限を定義するならデータセットレベルはgoogle_bigquery_dataset_access
プロジェクトレベルはgoogle_project_iam_memberで実施すると別なので安全らしい?
■TF公式ドキュメント
google_organization_iam_custom_role | Resources | hashicorp/google | Terraform Registrygoogle_organization_iam | Resources | hashicorp/google | Terraform Registryカスタムロールを設定して、組織レベルのIAMでそれを使いたい
TFのorg_iamページのArgument referenceのrole項目を見ると
Note that custom roles must be of the format organizations/{{org_id}}/roles/{{role_id}}
TFのorg_iam_custom_roleページのAttributes referenceのrole項目を見ると
id - an identifier for the resource with the format organizations/{{org_id}}/roles/{{role_id}}
で下記と分かる、使用側と被使用側のTFマニュアルを両方確認する
resource "google_organization_iam_custom_role" "my-custom-role" {
role_id = "myCustomRole"
org_id = "123456789"
title = "My Custom Role"
description = "A description"
permissions = ["iam.roles.list", "iam.roles.create", "iam.roles.delete"]
}
resource "google_organization_iam_member" "my-organization" {
org_id = "123456789"
role = google_organization_iam_custom_role.my-custom-role.id
#あるいは通常"roles/bigquery.dataEditor"のようにいれるがorganizations/0123456789/roles/chinkoといれる
member = "user:jane@example.com"
}
↑
resourceの2番目リソース名を定義しますが任意の名前を指定します
ここが同じ項目はユニーク制限がない場合は追加としてまとめられます
通常はユニークにしterraformで管理するリソース名(yourResourceName)を宣言します
※1番目のリソースタイプ内でユニークにするのが基本(全体でもユニークの方が分かり易い)
TFファイルに定義をしたい →定義したいリソースのArgument referenceの項目を設定
TFファイルに定義した内容を変数で使いたい →使いたいリソースのAttributes referenceを見る
terraform importしたい →インポしたいリソースのページ一番下のimportコマンドの指定を見る
■他に一般的なTF(既存がimportされると以下で変更をapplyして運用)
terraform -v 稼働確認
terraform fmt ファイルの記述フォーマットを整える
terraform validate ファイルの検証
terraform plan アクションを計画
terraform apply 最後に変更を適応
terraform show ステータスを確認、一覧
terraform destroy で簡単にインフラの吐き、initができないとき必要そう
■特定のリソースだけ適応したい
terraform plan -target="tfResourceID.yourResourceName"
terraform apply -target="tfResourceID.yourResourceName"
TFファイルだけでなくTFステートもターゲットに含まれる
これでTFファイルにコードがなくTFステートだけにあるものを指定して削除等もできる
■terraformのバージョン管理
.terraform.lock.hclファイルでGCP provider等のライブラリのバージョン管理をしている、pyenvのPipfile.lockみたいなHash差分が記載されている、terraform init等で生成されapply時の設定が担保される、通常tfファイルでproviderのバージョンを記載すればよいので不要と思われる
.terraform-versionファイルでterraform自体の要求バージョンを担保できる
通常はtfenvを使えばよい、tfファイルでrequired_versionを記載すればよいので不要と思われる
■tfenvを使う場合
tfenv install 1.0.0
tfenv list
tfenv use 1.0.0
terraform init
terraform workspace list
terraform workspace select ore_space
main.tf作成し記載
terraform fmt tfファイルのフォーマット(書式は適当で書けばいい)
gcloud auth login ローカル操作のための認証
gcloud auth application-default login SDKを実行のための認証
API&Servicesでクレデンシャルは取得できそう、key=xxxx
既存のリソースを調査
terrafrom import google_storage_bucket.pri-bucket project-abc123/asia-northeast1/pri-bucket でimportとか
terraform refresh tfstateの最新化、どのタイミングで使う?
■既存のリソースを調査
terraformer import google --resources=instances,forwardingRules --regions=us-west1 --projects=xxxx-123 とか
既存リソースimport
https://www.apps-gcp.com/terraformit-gcp/
ダメなら terraform state rm で不要分を削る
新環境用にtfファイルを準備
新環境で下記を実行
terraform init
terraform state push xxx.tfstate
terraform planで差分がないことを確認
■GCP権限(メールの変名時)
GCPはGWS gmailメールの変名に追従して権限も付与状態も変化がない
しかしterraformは追従しないためtfファイルで使っている場合は変更する
■gcloud cmd
https://www.devsamurai.com/ja/gcp-terraform-101/
gcloud projects list 権限あるプロジェクトを表示
gcloud config set project [prjID] ワーキングプロジェクトの設定
gcloud services enable iam.googleapis.com サービスの有効化
gcloud iam service-accounts create terraform-serviceaccount \
--display-name "Account for Terraform" サービスアカウント作成
gcloud projects add-iam-policy-binding [PROJECT_ID]
--member serviceAccount:terraform-serviceaccount@[PROJECT_ID].iam.gserviceaccount.com --role roles/editor 権限付与
gcloud iam service-accounts keys create path_to_save/account.json
--iam-account terraform-serviceaccount@[PROJECT_ID].iam.gserviceaccount.com クレデン発行