LoginSignup
1

More than 1 year has passed since last update.

posted at

updated at

Organization

Terraform の Configuration Drift を解消する

本記事は 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が発生した状態を再現してみます。

main.tf
# 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 をインクリメントしておきましょう)

main.tf
   tags = {
-    drift_example = "v1"
+    drift_example = "v2"
   }
terraform.tfstate
@@ -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 の差分を確認してみます。

.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 する

terraformerterraforming といったツールを用いて、既存のインフラストラクチャから新たに Terraform で管理する .tf .tfstate にエクスポートすることもできます。

ストレージやネットワークなどが完全にセットアップされた状態のインスタンスや、複数にわたるクラスター・ノードを、手動で編集・インポートを行うよりも、このようなツールを使用するほうが現実的な方法でしょう。

まとめ

Terraform の Configuration Drift を解消する方法として下記の3点を紹介しました。状況に応じて活用していただければ幸いです。

  • Terraform の設定と状態を手動で変更する
  • terraform import コマンドを使用する
  • ツールを使用して Reverse Terraform する

また、問題の対応方法を知っておくことは大切ですが、Terraform や Infrastructure as Code のベストプラクティスを知り、問題を未然に防ぐことも大切だと思いました。(戒め)

参考URL

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1