TerraformでAWSリソース1種類を複数個作成する

ここんとこTerraformづくしです。前回APIGatewayLambdaSNSS3を一気にまとめて作成するものを作ったわけですが、諸般の事情から複数のDynamoDBと複数のLambdaそして複数のAPIGateway、、はてはS3まで準備しないといけなくなったので、いろいろと試行錯誤しながら準備しました。

1つのリソースを複数個用意するとかいうサンプルがなかなかなかったので
役に立つかなと思って備忘録として残しておきます。
*なんかもっと効率いい方法あれば教えてほしい。

そしてTerraformはプログラムではないのでforとかifの使い方に癖があるし
結構な制約事項となります。けれども、1個覚えればどこのクラウドだろうが
オンプレだろうが1つの記述法で行けるというのは非常に魅力的なんですよねぇ。


◆設定

1.terraformファイル群

 (1)ルートに置くもの

# main.tf
-----------------
resource "aws_sns_topic" "this_sns_topic" {
  name = var.sns_topic_name
}

module "lambda" {
  source = "./lambda"
}

module "apigateway" {
  source        = "./apigateway"
  region        = var.region
  account_id    = var.account_id
}

module "dymano" {
  source = "./dynamodb"
}

module "s3" {
  source = "./s3"
}
-----------------
# variables.tf
-----------------
variable "access_key" {
  description = "AWS Access Key"
}
variable "secret_key" {
  description = "AWS Secret Key"
}
variable "role_arn" {
  description = "AWS Role ARN for Assume Role"
}
variable "region" {
  description = "AWS Region"
  default     = "ap-northeast-1"
}

variable "sns_topic_name" {
  default = "sns_dev_topic"
}

variable "account_id" {
  default = "XXXXXXX"
}
-----------------
# provider.tf
-----------------
provider "aws" {
  access_key = var.access_key
  secret_key = var.secret_key
  region     = var.region
}
-----------------

(2)Lambdaディレクトリ配下


# main.tf
-----------------
data "archive_file" "arc_dev_function" {
  for_each    = var.import_lambda_dirs
  type        = "zip"
  source_dir  = "${path.module}/src/${lookup(each.value, "filename")}"
  output_path = "${path.module}/upload/${lookup(each.value, "filename")}.zip"
}

resource "aws_lambda_function" "lambda_functions" {
  for_each         = var.import_lambda_dirs
  filename         = "${path.module}/upload/${lookup(each.value, "filename")}.zip"
  function_name    = lookup(each.value, "filename")
  role             = var.lambda_function_arn
  handler          = "lambda_function.lambda_handler"
  source_code_hash = base64sha256("${path.module}/upload/${lookup(each.value, "filename")}.zip")
  runtime          = var.lambda_runtime
  memory_size      = var.lambda_memory
  timeout          = var.lambda_timeout

  environment {
    variables = lookup(each.value, "environment_setting")
  }
  tags = lookup(each.value, "tag_setting")
}
-----------------
# variables.tf
-----------------
variable "import_lambda_dirs" {
  default = {
    dir1 = {
      filename = "01_sample"
      environment_setting = {
        ENV_SAMPLE = "sample1"
      }
      tag_setting = {
        "tag" = "sample1"
      }
    }
    dir2 = {
      filename = "02_sample"
      environment_setting = {
        ENV_SAMPLE = "sample2"
      }
      tag_setting = {
        "tag" = "sample2"
      }
    }
    dir3 = {
      filename = "03_sample"
      environment_setting = {
        ENV_SAMPLE = "sample3"
      }
      tag_setting = {
        "tag" = "sampl3"
      }
    }
  }
}

variable "lambda_role_arn" {
  default = "AWS Role ARN for Assume Role"
}
variable "lambda_runtime" {
  default = "python3.8"
}

variable "lambda_memory" {
  default = 128
}
variable "lambda_timeout" {
  default = 30
}

variable "lambda_function_arn" {
  default = "arn:aws:iam::XXXXX:role/LambdaRole"
}
-----------------

(3)APIGatewayディレクトリ配下


# main.tf
-----------------
data "template_file" "apigateway_template" {
  for_each = var.apigateway_param
  template = file("${path.module}/swagger_definition/${lookup(each.value, "filename")}.yml")
  vars = {
    region        = var.region
    account_id    = var.account_id
    function_name = lookup(each.value, "functionname")
    base_path     = lookup(each.value, "basepath")
  }
}

resource "aws_api_gateway_rest_api" "my_api_gateway" {
  for_each    = var.apigateway_param
  name        = lookup(each.value, "filename")
  description = "This is my API for demonstration purposes"
  body        = data.template_file.apigateway_template[each.key].rendered
}

resource "aws_api_gateway_deployment" "apiDeployment" {
  for_each    = var.apigateway_param
  rest_api_id = aws_api_gateway_rest_api.my_api_gateway[each.key].id
  stage_name  = lookup(each.value, "basepath")
}

resource "aws_lambda_permission" "lambda_permission" {
  for_each      = var.apigateway_param
  statement_id  = "AllowMyDemoAPIInvoke"
  action        = "lambda:InvokeFunction"
  function_name = lookup(each.value, "functionname")
  principal     = "apigateway.amazonaws.com"
  source_arn    = "${aws_api_gateway_rest_api.my_api_gateway[each.key].execution_arn}/*/*/*"
}
-----------------
# variables.tf
-----------------
variable "region" {}
variable "account_id" {}

variable "apigateway_param" {
  default = {
    param1 = {
      index        = 0
      filename     = "sample1"
      functionname = "01_sample"
      basepath     = "test"
    }
    param2 = {
      index        = 1
      filename     = "sample2"
      functionname = "02_sample"
      basepath     = "test"
    }
    param3 = {
      index        = 2
      filename     = "sample3"
      functionname = "03_sample"
      basepath     = "test"
    }
  }
}
-----------------

(4)DynamoDBディレクトリ配下


# main.tf
-----------------
resource "aws_dynamodb_table" "basic-dynamodb-table1" {
  for_each     = var.hash_range_param
  name         = lookup(each.value, "table_name")
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = lookup(each.value, "table_hashkey")
  range_key    = lookup(each.value, "table_rangekey")

  attribute {
    name = lookup(each.value, "table_hashkey")
    type = lookup(each.value, "hash_type")
  }

  attribute {
    name = lookup(each.value, "table_rangekey")
    type = lookup(each.value, "hash_type")
  }

  tags = lookup(each.value, "tags")
}

resource "aws_dynamodb_table" "basic-dynamodb-table2" {
  for_each     = var.hash_only_param
  name         = lookup(each.value, "table_name")
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = lookup(each.value, "table_hashkey")

  attribute {
    name = lookup(each.value, "table_hashkey")
    type = lookup(each.value, "type")
  }

  tags = lookup(each.value, "tags")
}
-----------------
# variables.tf
-----------------
variable "hash_range_param" {
  default = {
    param1 = {
      index          = 0
      table_name     = "hash_range_sample1"
      table_hashkey  = "hash_key"
      table_rangekey = "range_key"
      hash_type      = "S"
      range_type     = "S"
      tags = {
        tag = "sample1"
      }
    }
    param2 = {
      index          = 1
      table_name     = "hash_range_sample2"
      table_hashkey  = "hash_key"
      table_rangekey = "range_key"
      hash_type      = "S"
      range_type     = "S"
      tags = {
        tag = "sample2"
      }
    }
  }
}

variable "hash_only_param" {
  default = {
    param1 = {
      index         = 0
      table_name    = "hash_only_sample1"
      table_hashkey = "key_id"
      type          = "S"
      tags = {
        tag = "sample1"
      }
    }
    param2 = {
      index         = 1
      table_name    = "hash_only_sample2"
      table_hashkey = "key_id"
      type          = "S"
      tags = {
        tag = "sample2"
      }
    }
  }
}
-----------------

(5)S3ディレクトリ配下


# main.tf
-----------------
resource "aws_s3_bucket" "bucket" {
  for_each = var.buckets
  bucket   = lookup(each.value, "bucket_name")
  acl      = lookup(each.value, "acl")
  tags     = lookup(each.value, "tags")
}
-----------------
# variables.tf
-----------------
variable "buckets" {
  default = {
    param1 = {
      index       = 0
      bucket_name = "sample-bucket-20200517-1"
      acl         = "private"
      tags = {
        tag = "sample1"
      }
    }
    param2 = {
      index       = 1
      bucket_name = "sample-bucket-20200517-2"
      acl         = "private"
      tags = {
        tag = "sample2"
      }
    }
  }
}
-----------------

2.ディレクトリ構造


|-- apigateway
|   |-- main.tf
|   |-- swagger_definition
|   |   |-- sample1.yml
|   |   |-- sample2.yml
|   |   `-- sample3.yml
|   `-- variables.tf
|-- dynamodb
|   |-- main.tf
|   `-- variables.tf
|-- lambda
|   |-- main.tf
|   |-- src
|   |   |-- 01_sample
|   |   |   `-- lambda_function.py
|   |   |-- 02_sample
|   |   |   `-- lambda_function.py
|   |   `-- 03_sample
|   |       `-- lambda_function.py
|   |-- upload
|   `-- variables.tf
|-- main.tf
|-- provider.tf
|-- s3
|   |-- main.tf
|   `-- variables.tf
|-- terraform.tfstate
|-- terraform.tfstate.backup
`-- variables.tf

3.実行コマンド

$ terraform init
$ terraform plan
$ terraform apply
$ terraform destroy


◆参考

・複数リソース作り方

https://qiita.com/ringo/items/875f08ec550f0826f0dc
https://dev.classmethod.jp/articles/terraform-network-variable/
https://cloudfish.hatenablog.com/entry/2020/02/19/183548
https://dev.classmethod.jp/articles/terraform_count_delete/
https://qiita.com/keiichi-hikita/items/9fd20e8ad6afe4e5ef72
https://febc-yamamoto.hatenablog.jp/entry/2018/02/02/120207

・環境変数関連

https://qiita.com/tksugimoto/items/c1dd29a587e5689a1f6a

・APIGateway

https://medium.com/@jmarhee/using-for-each-in-terraform-in-modules-7fb5a240a0d9

・DynamoDB

https://www.terraform.io/docs/providers/aws/r/dynamodb_table.html
https://github.com/terraform-providers/terraform-provider-aws/issues/3176

コメント

このブログの人気の投稿

証券外務員1種勉強(計算式暗記用メモ)

GASでGoogleDriveのサブフォルダとファイル一覧を出力する

マクロ経済学(IS-LM分析)