【Terraform】for_eachでAmazon DynamoDBの項目をまとめて管理する


概要

  • DynamoDBにてアプリケーションで使用する設定値を管理したい
  • DynamoDB TableはTerraformで管理
  • DynamoDB Tableに追加する項目(ここでは設定値)をTerraformで管理
    • Terraformのfor_eachファンクションを利用して、複数項目を追加

動機

以下のjsonファイルの内容でDynamoDBに登録される項目が存在する。
登録するデータはマスターデータであるため、基本的に変更しない。
可能であれば、Terraformで管理したい。(Resource: aws_dynamodb_table_item

sample.json
{
    "device_code": {
        "S": "3"
    },
    "parameter": {
        "M": {
            "input_key": {
                "S": "path/to/directory"
            },
            "output_location": {
                "S": "path/to/directory"
            },
            "instance_type": {
                "S": "ml.m5.2xlarge"
            }
        }
    }
}

対応方法

for_eachを活用することで、少ない定義で複数の項目を管理することが可能となる。

dynamodb.tf
resource "aws_dynamodb_table" "device_config" {
  name                   = "sample_table"
  billing_mode           = "PROVISIONED"
  hash_key               = "device_code"

  attribute {
    name = "device_code"
    type = "S"
  }
}

locals {
  json_data = file("./config.json")         # jsonファイルの読み込み
  config    = jsondecode(local.json_data)   # デコード
}

resource "aws_dynamodb_table_item" "device_config" {
  for_each = local.config                   # for_eachにより、要素ごとに分割

  table_name = aws_dynamodb_table.device_config.name
  hash_key   = aws_dynamodb_table.device_config.hash_key

  item = jsonencode(each.value)             # 各要素のバリューをエンコードしitemに挿入
}

例として以下のようなconfig.jsonにすることにより、画像のようにまとめて項目を追加することができる。

config.json
{
    "device_3": {
        "device_code": {
            "S": "3"
        },
        "parameter": {
            "M": {
                "input_key": {
                    "S": "path/to/directory/3"
                },
                "output_location": {
                    "S": "path/to/directory/3"
                },
                "instance_type": {
                    "S": "ml.m5.2xlarge"
                }
            }
        }
    },
    "device_4": {
        "device_code": {
            "S": "4"
        },
        "parameter": {
            "M": {
                "input_key": {
                    "S": "path/to/directory/4"
                },
                "output_location": {
                    "S": "path/to/directory/4"
                },
                "instance_type": {
                    "S": "ml.m5.2xlarge"
                }
            }
        }
    },
    "device_5": {
        "device_code": {
            "S": "5"
        },
        "parameter": {
            "M": {
                "input_key": {
                    "S": "path/to/directory/5"
                },
                "output_location": {
                    "S": "path/to/directory/5"
                },
                "instance_type": {
                    "S": "ml.m5.2xlarge"
                }
            }
        }
    }
}

項目を変更する際

Terraformで項目を管理できることにより、マスターに変更が加わった場合でもコードで変更点などを把握することが可能となる。

仮に上記例のdevice4を削除した場合、Terraformを実行すると以下のように出力され、applyするとその項目のみが削除される。

$ terraform apply

aws_dynamodb_table.device_config: Refreshing state... [id=sample_table]
aws_dynamodb_table_item.device_config["device_5"]: Refreshing state... [id=sample_table|device_code||5|]
aws_dynamodb_table_item.device_config["device_3"]: Refreshing state... [id=sample_table|device_code||3|]
aws_dynamodb_table_item.device_config["device_4"]: Refreshing state... [id=sample_table|device_code||4|]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_dynamodb_table_item.device_config["device_4"] will be destroyed
  - resource "aws_dynamodb_table_item" "device_config" {
      - hash_key   = "device_code" -> null
      - id         = "sample_table|device_code||4|" -> null
      - item       = jsonencode(
            {
              - device_code = {
                  - S = "4"
                }
              - parameter   = {
                  - M = {
                      - input_key       = {
                          - S = "path/to/directory/4"
                        }
                      - instance_type   = {
                          - S = "ml.m5.2xlarge"
                        }
                      - output_location = {
                          - S = "path/to/directory/4"
                        }
                    }
                }
            }
        ) -> null
      - table_name = "sample_table" -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_dynamodb_table_item.device_config["device_4"]: Destroying... [id=sample_table|device_code||4|]
aws_dynamodb_table_item.device_config["device_4"]: Destruction complete after 0s

Apply complete! Resources: 0 added, 0 changed, 1 destroyed.

まとめ

  • for_eachを利用することによりDynamoDBの項目管理が容易に実現できた
  • IaCすごい

参考