本記事は Ateam Finergy Inc. Advent Calendar 2020 4日目の記事です。
はじめに
本記事を書くにあたり、動作検証に使用した Terraform のバージョンは下記の通りです。
% terraform -v
Terraform v0.13.2
また、想定読者は Terraform を使用していて、Drift の解決に困っている方、および、忘れがちな自分のためのメモです。
Configuration Drift
Terraform を使用していると、何らかの理由により、 Terraform が管理しているインフラストラクチャの状態ファイル .tfstate
の内容と、実際のインフラストラクチャの乖離(Configration Drift)が発生する場合があります。
Drift が発生してしまった場合、対応方針としてはいくつか考えられると思いますが、今回は稼働しているインフラ側を正しい状態とし、Terraform で管理する状態の乖離を解消する方法を記載します。
Drift を解消する
下記のリソースを使用し、Driftが発生した状態を再現してみます。
# AWS EC2 VM with AMI and tags
resource "aws_instance" "example" {
ami = "ami-0289fbf73734505e2"
instance_type = "t3.micro"
tags = {
drift_example = "v1"
}
}
terraform apply
を実行し、インスタンスを作成します。
% terraform apply
...省略...
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
次に、AWSコンソールを使用してインスタンスのタグを手動で v2
に更新した後、terraform plan
で実行計画を出力し、Drift を確認します。
% 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.
aws_instance.example: Refreshing state... [id=i-**********]
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# aws_instance.example will be updated in-place
~ resource "aws_instance" "example" {
~ tags = {
~ "drift_example" = "v2" -> "v1"
}
}
Plan: 0 to add, 1 to change, 0 to destroy.
------------------------------------------------------------------------
Terraform がタグの値を v2 から v1 に更新することがわかります。 Terraform は Drift を修正し、設定の値と一致するようにタグを修正しようとしています。この状態で terraform apply
を実行すると、実際のインフラストラクチャ側のタグは v1 に戻されてしまいます。
Terraform の設定と状態を手動で変更する
このように乖離が少ないケースであれば、設定ファイルを手動編集することにより解決することができます。
.tf
.tfstate
ファイルを以下のように編集します。
(.tfstate
を手動更新する場合、serial をインクリメントしておきましょう)
tags = {
- drift_example = "v1"
+ drift_example = "v2"
}
@@ -1,7 +1,7 @@
- "serial": 1,
+ "serial": 2,
@@ -76,7 +76,7 @@
"tags": {
- "drift_example": "v1"
+ "drift_example": "v2"
},
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.
aws_instance.example: Refreshing state... [id=i-**********]
------------------------------------------------------------------------
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 側からの変更が無くなりました。
terraform import
コマンドを使用する
より大きな乖離が発生したケースを想定してみます。例えば、管理するリソースを後から追加したい場合などです。
例として、AWSコンソールからブロックストレージを作成し、先程のインスタンスに紐付けました。
terraform import
コマンドを使用し、既存のインフラストラクチャの情報を .tfstate
ファイルに取り込む手順を以下に記載します。
# import コマンドによる状態の上書きができないので、まず古い情報を削除します
# state rm コマンドは実行時、状態の削除とともに .backup ファイルを作成します
% terraform state rm aws_instance.example
Removed aws_instance.example
Successfully removed 1 resource instance(s).
# import を実行します
% terraform import aws_instance.example i-**********
aws_instance.example: Importing from ID "i-**********"...
aws_instance.example: Import prepared!
Prepared aws_instance for import
aws_instance.example: Refreshing state... [id=i-**********]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
うまく取り込めたようなので、.tfstate
の差分を確認してみます。
@@ -1,7 +1,7 @@
- "serial": 2,
+ "serial": 3,
@@ -26,7 +26,19 @@
- "ebs_block_device": [],
+ "ebs_block_device": [
+ {
+ "delete_on_termination": false,
+ "device_name": "/dev/sdf",
+ "encrypted": false,
+ "iops": 100,
+ "kms_key_id": "",
+ "snapshot_id": "",
+ "volume_id": "vol-**********",
+ "volume_size": 1,
+ "volume_type": "gp2"
+ }
+ ],
先程追加したブロックストレージの情報が無事追加されていました。
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.
aws_instance.example: Refreshing state... [id=i-**********]
------------------------------------------------------------------------
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 側からの変更は行われないので問題なさそうです。
ツールを使用して Reverse Terraform する
terraformer や terraforming といったツールを用いて、既存のインフラストラクチャから新たに Terraform で管理する .tf
.tfstate
にエクスポートすることもできます。
ストレージやネットワークなどが完全にセットアップされた状態のインスタンスや、複数にわたるクラスター・ノードを、手動で編集・インポートを行うよりも、このようなツールを使用するほうが現実的な方法でしょう。
まとめ
Terraform の Configuration Drift を解消する方法として下記の3点を紹介しました。状況に応じて活用していただければ幸いです。
- Terraform の設定と状態を手動で変更する
-
terraform import
コマンドを使用する - ツールを使用して Reverse Terraform する
また、問題の対応方法を知っておくことは大切ですが、Terraform や Infrastructure as Code のベストプラクティスを知り、問題を未然に防ぐことも大切だと思いました。(戒め)