LoginSignup
19
16

More than 3 years have passed since last update.

tfstate の手動編集 (s3 backend 編)

Last updated at Posted at 2019-12-20

terraform apply の状態管理は tfstate ファイルで行われ、こちらにサーバーリソースに対して行った変更内容と結果が state ファイルとして保存されます。tfstate の状態と tf ファイルの内容が異なる状態で terraform plan を実施すると terraform コマンドが状態の差分を表示してくれます。

基本的に tfstate ファイルは手動で変更することは無いですが、既存のサーバーリソースの設定内容を後付けで terraform 管理下に置こうとした時などに、どうしても手動で変更せざるを得ないケースもあります。

(例: IAM Group、Policy などの情報は、tfstate に保存されていない内容はすべて新規扱いになる。既存のリソースと同じ設定を tf ファイルに書いた状態で terraform apply をすると 409 エラーが発生してしまう)

このドキュメントでは、tfstate の手動編集を行う手順について書きます。

tfstate format - general (version 4)

概論として、tfstate がどのようなデータフォーマットなのか、簡単に書きます。

tfstate は JSON 形式で表現されています。

公式ドキュメントにはあまり記述がないですが… 0.12.x でのフォーマット(version 4)は以下のようになっています。

terraform のバージョンによって tfstate のバージョンも異なり、それらにより微妙に記述すべき内容は異なります。

{
  "version": 4,
  "terraform_version": "0.12.18",
  "serial": 679,
  "lineage": "617d8489-6973-bac0-2750-3457992f99db",
  "outputs": {
    "security_groups": {
      "value": {
        "sada": [
          "sg-xxxxxxxx",
          "sg-xxxxxxxx"
        ],
      },
      "type": [
        "object",
        {
          "sada": [
            "tuple",
            [
              "string",
              "string"
            ]
          ]
        }
      ]
    }
  },
  "resources": [
    {
      "mode": "managed",
      "type": "aws_security_group",
      "name": "sada",
      "provider": "provider.aws",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
            "arn": "arn:aws:ec2:ap-northeast-1:xxxxxx.....",
(snip.)
        }
      ]
    }
  ]
}

state は tfstate ファイル自体のフォーマット番号、terraform_version は動作させている terraform のバージョン、serial は tfstate の変更回数(terraform apply するごとにインクリメントされていく)、lineage は terraform init した際の払い出される UUID です。

outputs には terraform apply した結果の output の結果が、そして resources には実際に設定を適用したリソースの状態が保存されます。

その他、どのようなデータ定義になっているかについては、go で書かれたソースコードを読むのが手っ取り早いと思います。

手で tfstate を編集する際は、基本的にこの resources の内容の追記、変更、削除を行うことになります。

tfstate format - resources (version 4)

resources のフォーマットは以下のようになっており、個々のリソースの配列として表現されています。

  "resources": [
    {
      "mode": "managed",
      "type": "aws_security_group",
      "name": "sada",
      "provider": "provider.aws",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
            "arn": "arn:aws:ec2:ap-northeast-1:xxxxxx.....",
(snip.)
        }
      ]
    }
  ]

mode は基本 managed (サーバーリソース)か data、type は対象リソースの名前、name はリソースに付与した名前、provider は対象となるリソースプロバイダー(aws, azurerm 等)です。

そして、instances.attributes の中の内容が個々のリソースの設定情報を表現するため、基本的にはここの編集を行います。

たとえば aws_security_group の場合、attributes に設定すべき項目は以下のようなものになります。

  • arn
  • id
  • name
  • vpc-id
  • ingress
  • egress
  • etc…

このドキュメントでは、各リソースの attribute に何を設定すべきかは詳述しません。

以下では、S3 を backend に指定している際の tfstate 編集作業の手順を記載します。

S3 backend の tfstate の編集手順

S3上のファイルを直接書き換える方法も無いわけではないと思いますが、ダイレクトに変えすぎるとリスクがあります。ということで、ここでは以下のような手順を記載します。

1.backend を一時的に local に切り替える

terraform {
#  backend "s3" {
#    bucket                  = "sada-terraform-state"
#    key                     = "tfstate.json"
#    region                  = "ap-northeast-1"
(snip.)
#  }
  backend "local" {
    path = "terraform.tfstate"
  }
}

2.terraform init

backend を切り替えた後に terraform init コマンドを実行すると、切り替え先の backend に現在の tfstate をコピーするか否かを尋ねるメッセージが表示されます。

Terraform detected that the backend type changed from "s3" to "local".
Do you want to copy existing state to the new backend?
(snip.)

こちらに対して yes とタイプすると、切り替え先の backend に tfstate ファイルがコピーされます。

ここでは local に backend を切り替えましたので、terraform.tfstate にファイルが保存されます。

3.tfstate 、tf ファイルの変更

ローカルに保存された tfstate に変更を加えます。

変更する手段として、 terraform import を使った手順を以下に記載します。

3.1.terraform import

既存のリソースの情報を取得して tfstate に反映するコマンドです。

このコマンドを実行して、最新のリソース状況を tfstate に取り込む事ができます。

terraform import -state=terraform.tfstate aws_security_group.sada sg-xxxxxxxx

必ずしも最新のリソース状況の取り込みだけが tfstate を手動で編集する際の動機では無いと思いますが、リソース状況の取得の際は terraform import を使うと便利です。

3.2.terraform state show

tfstate に何が設定されているかは、 terraform state show コマンドを使用することで確認できます。

こちらを使って、tfstate が意図した状態になっているかを確認します。

terraform state show -state=terraform.tfstate aws_security_group.sada
# aws_security_group.sada:
resource "aws_security_group" "sada" {
    arn                    = "arn:aws:ec2:ap-northeast-1:xxxxxx....."
(snip.)

}

3.3.tfファイルの修正、作成、削除

上記等をふまえ、tf ファイルに、設定したい情報を定義します。

4.terraform plan 、applyで意図した差分状態になるかを確認

一通り変更を加えたら、 terraform plan を実行し、意図した変更内容が反映されているかを確認します。

反映が必要な場合は、 terraform apply を実行します。

5.backend を S3 に戻す

問題がなければ、再度 backend を s3 に戻します。

terraform {
  backend "s3" {
    bucket                  = "sada-terraform-state"
    key                     = "tfstate.json"
    region                  = "ap-northeast-1"
(snip.)
  }
#  backend "local" {
#    path = "terraform.tfstate"
#  }
}

6.terraform init

S3 に backend を戻した上で terraform init を実行すると、S3 にローカルの tfstate ファイルをコピーするかどうか尋ねられますので、yes を入力します。

Terraform detected that the backend type changed from "local" to "s3".
Do you want to copy existing state to the new backend?
(snip.)

7.terraform plan

念の為、backend を S3 に戻した後も意図した差分になっているか、 terraform plan で確認します。

これで、一通りの作業は完了です。

19
16
0

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
  3. You can use dark theme
What you can do with signing up
19
16