- どうも
- Backends
— ドキュメント
— 状態の管理
— メリット
— 設定諸々
— Backend Types
—– 二種類の Backend Type
—– Enhanced Backends
—– Standard Backends - State Locking
— ドキュメント
— State Locking とは
— 例えば… - Doctor Providor + Backend Type S3
— せっかくなので
— 簡単な main.tf
— コンテナ作成
— Backend を S3 に変える - 現場から以上です
どうも
独り Terraform 研究所, 所長兼研究員のかっぱです.
以下のような Terraform に関する記事を書いてから, 2 年以上が経過して, すごく久しぶりに Terraform を触る機会を得たので 2 年のブランクを少しでも埋めるべく Terraform について, 自分が気になる部分を掻い摘んで研究していきたいと思います.
inokara.hateblo.jp
尚, 本記事で利用している環境は以下の通りとなります.
$ sw_vers ProductName: Mac OS X ProductVersion: 10.13.6 BuildVersion: 17G65 $ terraform --version Terraform v0.11.8
また, 英文の翻訳には Google 翻訳を利用しておりますが, 一部には自分による意訳が含まれている為, 実際の内容とは異なる可能性がある旨, 何卒ご了承の程よろしくお願い致します.
Backends
ドキュメント
www.terraform.io
状態の管理
- Terraform で構築したインフラの状態 (State) を管理する
- Backend 自体は抽象レイヤーで, 実際にはリモートのオブジェクトストレージ等を選択して状態を保存することが出来る
- デフォルトの設定は
local
Backend で状態はローカル PC に保存される
メリット
Backend のメリットについては, ドキュメントのおいては以下のように言及されています.
- リモートに状態を保存した上で, その状態をロックすることで, 状態の破損を防ぐことが出来る
- リモートストレージを利用することで, 機密情報をローカルディスクに保存する必要がなくなる
- いくつかの Backend については, 遠隔操作が可能となる為,
apply
して放置ということが出来る (リモートストレージとロックを組み合わせる)
特にチームで Terraform を触る際にこれらのメリットの恩恵を受けることが出来ると思いますが, 個人だけで触る場合でも, Backend をうまく使いこなすことができれば, どこでも, いつでも同じ状態を簡単に構築, 再現することが出来ると思います.
設定諸々
terraform init
を実行して, Backend を初期化する必要がある (init
は Terraform を始めるにあたり, 必ず実行する必要がある)- 設定自体は Terraform ファイルの
terraform
セクションに記述するか,init
コマンドのオプションとして, コマンドラインからも指定することが出来る
以下は Amazon S3 を Backend として利用する場合の設定例です.
teraform { backend "s3" { bucket = "oreno-terraform-state" key = "terraform.tfstate.docker" region = "ap-northeast-1" } }
- Backend を変更する (例えば,
local
からs3
に変更する) 場合にもinit
コマンドを使う
以下は init
コマンドの実行例です.
$ terraform init Terraform has detected you're unconfiguring your previously set "s3" backend. Do you want to copy existing state to the new backend? Pre-existing state was found while migrating the previous "s3" backend to the newly configured "local" backend. No existing state was found in the newly configured "local" backend. Do you want to copy this state to the new "local" backend? Enter "yes" to copy and "no" to start with an empty state. Enter a value: yes Successfully unset the backend "s3". Terraform will now operate locally. ...
上記の例では, 従来は S3 Backend の利用を定義していたものを削除し, terraform init
を実行しています.
workspace
を利用している場合, 各 workspace 毎に状態 (tfstate) が作成される
以下は local Backend を用いて, test1
及び test2
という workspace を作成して plan
や apply
を行った結果です.
$ tree . . ├── main.tf ├── terraform.tfstate └── terraform.tfstate.d ├── test1 │ └── terraform.tfstate └── test2 └── terraform.tfstate 3 directories, 4 files
terraform.tfstate.d
ディレクトリが作成され, その直下に各 workspace 名のディレクトリが作成され, その直下にそれぞれの tfstate ファイルが作成されています.
Backend Types
二種類の Backend Type
Backend Type は大きく, 提供する機能によって以下の二種類に分けられる.
- Standard
- 状態の管理, 状態保存とロック機能を提供
- Enhanced
- Standard の機能に合わせて, リモート操作を提供
「リモート操作」については, ここでは大きくは触れないが, ドキュメントによると…
Some backends support the ability to run operations (refresh, plan, apply, etc.) remotely. Terraform will continue to look and behave as if they’re running locally while they in fact run on a remote machine.
と書かれており, Enhanced タイプの Backend を利用することで, Terraform の実行をリモートで行いつつ, あたかもローカル環境で実行されているかのように振る舞う機能が利用出来るようだ.
Enhanced Backends
Enhanced Backends には以下の二種類があります.
- local
- remote
local はデフォルトの Backend で明示的に path
を指定しない場合にはカレントディレクトリに tfstate ファイルは保存されるようです. 以下は, 明示的に path
の設定を行った例です.
terraform { backend "local" { path = "relative/path/to/terraform.tfstate" } }
Standard Backends
Standard Backends の中でも単体で locking をサポートするものとしないもので分けられているようです. (locking についてはこの後で触れる予定.)
タイプ | locking サポート | メモ |
---|---|---|
artifactory | no | artifactory なんて初めて聞いたサービス. |
azurerm | yes | Azure Storage のネイティブ機能を使用した状態ロックと整合性チェックもサポートする. |
consul | yes | Consul のキー・バリューストアを利用, 状態ロックもサポートする |
etcd | no | etcd v2.x のパスを利用する. |
etcdv3 | yes | etcd v3 のキー・バリューストアを利用, 状態ロックもサポートする. |
gcs | yes | Google Cloud Storage を利用, 状態ロックもサポートする. |
http | optional | REST クライアントを利用して状態を保存する. |
manta | yes | manta というオブジェクトストレージを利用する. manta 内で状態ロックも行う. |
s3 | DynamoDB を利用 | Amazon S3 を利用, バージョニングを有効にすることを推奨, DynamoDB を利用して状態ロックと整合性チェックもサポートする. |
swift | no | オブジェクトストレージの swift を利用する. s3 同様にバージョニングを有効にすることを推奨. |
terraform enterprise | no | 旧 Atlas を利用, locking サポートしているかと思いきや… |
State Locking
ドキュメント
www.terraform.io
www.terraform.io
State Locking とは
- Backend でサポートされている場合, Terraformは状態を書き込む可能性があるすべての操作について状態をロックする
- 状態をロックすることにより, それぞれ別の変更を加えようとした際に tfstate が破壊されることを防ぐ
- 状態のロックは, tfstate に書き込みが発生する可能性のあるすべての操作で自動的に行われる
- 状態のロック自体が失敗すると, Terraform は処理を中断する
例えば…
Backend Type で Amazon S3 を選んだ場合には, S3 自体には状態をロックし, 整合性をチェックするような機能は提供されていない為, DynamoDB テーブルを利用してこれらの機能を提供することになります.
また, ロックの際に保存される情報は, 以下のコードで確認することが出来ます.
github.com
info := &LockInfo{ ID: id, Who: fmt.Sprintf("%s@%s", userName, host), Version: version.Version, Created: time.Now().UTC(), }
フムフム.
Docker Providor + Backend Type S3
せっかくなので
Docker Provider を使ってコンテナを作りつつ, Backend の挙動等について確認 (という名のチュートリアル) をしてみたい.
簡単な main.tf
基本となる Terraform ファイルは以下の通りです.
resource "docker_container" "hoge" { image = "${docker_image.centos.latest}" name = "hoge-${terraform.workspace}" hostname = "hoge-${terraform.workspace}" command = ["/bin/sh", "-c", "while true ; do sleep 1; hostname -s ; done"] } resource "docker_container" "fuga" { image = "${docker_image.centos.latest}" name = "fuga-${terraform.workspace}" hostname = "fuga-${terraform.workspace}" command = ["/bin/sh", "-c", "while true ; do sleep 1; hostname -s ; done"] } resource "docker_container" "popo" { image = "${docker_image.centos.latest}" name = "popo-${terraform.workspace}" hostname = "popo-${terraform.workspace}" command = ["/bin/sh", "-c", "while true ; do sleep 1; hostname -s ; done"] } resource "docker_image" "centos" { name = "centos:6" }
コンテナ作成
workspace を事前にいくつか作ってしまっていたので, 今回は default
に戻した状態でコンテナを作成します.
$ terraform workspace select default $ terraform plan $ terraform apply ... docker_container.popo: Creation complete after 0s (ID: 69c652297dd3a7cfd30c91a428f0ae026ec8611090914bf8e6a0ba0eb937c796) docker_container.fuga: Creation complete after 0s (ID: f203969cd96e0de6e1eec8dee1dc866b87d0eeab2c3b0609304d9f575f63b0d2) docker_container.hoge: Creation complete after 0s (ID: f4a7331dd4e436920a28fcb9c98372c453f95f21d5e7718bf68170266a8bdff2) Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
サクッと, コンテナが起動します.
$ docker ps | grep 'default' f4a7331dd4e4 b5e5ffb5cdea "/bin/sh -c 'while t…" About a minute ago Up About a minute hoge-default f203969cd96e b5e5ffb5cdea "/bin/sh -c 'while t…" About a minute ago Up About a minute fuga-default 69c652297dd3 b5e5ffb5cdea "/bin/sh -c 'while t…" About a minute ago Up About a minute popo-default
この時に tfstate ファイルは, main.tf が保存されているディレクトリと同じディレクトリに作成されています.
$ ls main.tf terraform.tfstate main.tf terraform.tfstate
Backend を S3 に変える
この状態から Backend を Amazon S3 (以後, S3) に変更してみたいので main.cf に以下を追記します.
terraform { backend "s3" { bucket = "oreno-terraform-state" key = "terraform.tfstate.docker" region = "ap-northeast-1" } }
順番はどちらでも良いけど, S3 バケットを作成します. この S3 バケット自体も terraform で作ることが出来るようですが, 今回は AWS CLI で作成します.
# バケットを作成 $ aws s3 mb s3://oreno-terraform-state # バケットバージョニングを有効 $ aws s3api put-bucket-versioning \ --bucket=oreno-terraform-state \ --versioning-configuration Status=Enabled # バケットを暗号化する $ aws s3api put-bucket-encryption --bucket=oreno-terraform-state \ --server-side-encryption-configuration '{ "Rules": [ { "ApplyServerSideEncryptionByDefault": { "SSEAlgorithm": "AES256" } } ] }'
作成したら, terraform init
コマンドを --reconfigure
オプションをつけて実行します.
$ terraform init --reconfigure Initializing the backend... Do you want to migrate all workspaces to "s3"? Both the existing "local" backend and the newly configured "s3" backend support workspaces. When migrating between backends, Terraform will copy all workspaces (with the same names). THIS WILL OVERWRITE any conflicting states in the destination. Terraform initialization doesn't currently migrate only select workspaces. If you want to migrate a select number of workspaces, you must manually pull and push those states. If you answer "yes", Terraform will migrate all states. If you answer "no", Terraform will abort. Enter a value: yes Successfully configured the backend "s3"! Terraform will automatically use this backend unless the backend configuration changes. ...
上記のように, tfstate ファイルは S3 にコピーする旨の確認メッセージが出力され, yes
を入力すると S3 にコピーが完了します. 念の為, 確認してみると以下のように S3 にアップロードされていることが判ります.
# S3 上の tfstate ファイルを確認 $ aws s3 ls s3://oreno-terraform-state/ PRE env:/ 2018-09-08 14:51:53 5662 terraform.tfstate.docker # オブジェクト (tfstate ファイル) がバージョニングされていることを確認 $ aws s3api list-object-versions --bucket=oreno-terraform-state { "Versions": [ { "ETag": "\"64b530af2d748c77a5d68b5448ac76de\"", "Size": 5649, "StorageClass": "STANDARD", "Key": "env:/test1/terraform.tfstate.docker", "VersionId": "2.eNdgnznHlbxkc_hMJ6NEz9AIcibcwO", "IsLatest": true, "LastModified": "2018-09-08T05:51:57.000Z", "Owner": { "DisplayName": "kappaahoaho", "ID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" } } ... # オブジェクト (tfstate ファイル) が暗号化されていることを確認 $ aws s3api head-object --bucket=oreno-terraform-state --key=terraform.tfstate.docker { "AcceptRanges": "bytes", "LastModified": "Sat, 08 Sep 2018 05:51:53 GMT", "ContentLength": 5662, "ETag": "\"355017b22a2af13dff9581b638461897\"", "VersionId": "tAciP72ATbpem.sDjNueU3sw7iJswg0p", "ContentType": "application/json", "ServerSideEncryption": "AES256", "Metadata": {} }
そして, ローカルの tfstate ファイルを見てみると…
$ ls -l terraform.tfstate -rw-r--r-- 1 user group 0 9 8 14:51 terraform.tfstate
空になっていることが判ります.
この状態で terraform plan
を実行すると, 以下のように出力されます.
$ terraform plan Refreshing Terraform state in-memory prior to plan... The refreshed state will be used to calculate this plan, but will not be persisted to local or remote state storage. docker_image.centos: Refreshing state... (ID: sha256:b5e5ffb5cdea24c637511e05e1bbe2c92207ae954559d4c7b32e36433035c368centos:6) docker_container.hoge: Refreshing state... (ID: f4a7331dd4e436920a28fcb9c98372c453f95f21d5e7718bf68170266a8bdff2) docker_container.popo: Refreshing state... (ID: 69c652297dd3a7cfd30c91a428f0ae026ec8611090914bf8e6a0ba0eb937c796) docker_container.fuga: Refreshing state... (ID: f203969cd96e0de6e1eec8dee1dc866b87d0eeab2c3b0609304d9f575f63b0d2) ------------------------------------------------------------------------ No changes. Infrastructure is up-to-date. This means that Terraform did not detect any differences between your configuration and real physical resources that exist. As a result, no actions need to be performed.
いい感じです.
現場から以上です
超駆け足ですが, Terraform の Backends について研究しつつ, 簡単なチュートリアルをやってみました. 状態ロックを併用することでチーム内で Terraform をいじる際に強力にサポートしてくれるものであることが解りました. また, Backend の実装にも興味が出てきましたので, HTTP のバックエンドサーバーを実装してみたいと考えています.
元記事はこちら
「独り Terraform 研究所 (1) 〜 Backend についてドキュメントを読んだり, チュートリアルしたり 〜」