AWS
Terraform

TerraformでAWS環境の構築する時に良く使う書き方

AWSを使う設定

provider.tf
provider "aws" {}

AWSのregionとaccount idを取得する

data.tf
data "aws_region" "current" {
  current = true
}

data "aws_caller_identity" "current" {}

regionの取得

data.aws_region.current.name

account idの取得

data.aws_caller_identity.current.account_id

アプリ名を変数にしておく

variable.tf
variable "kptboard" {
  default = "kptboard"
}

変数にして、基本的に名前を設定する部分はその変数を使うことでkptboard-stg,kptboard-prodのように書き換えるだけで他の環境を作りやすくなる。

aws_ecs_cluster.tf
resource "aws_ecs_cluster" "kptboard" {
  name = "${var.kptboard}"
}

最新のEC2のAMIを使うようにする

aws_instance.tf
data "aws_ami" "ecs_optimized" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "architecture"
    values = ["x86_64"]
  }

  filter {
    name   = "root-device-type"
    values = ["ebs"]
  }

  filter {
    name   = "name"
    values = ["amzn-ami-*-amazon-ecs-optimized"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  filter {
    name   = "block-device-mapping.volume-type"
    values = ["gp2"]
  }
}

resource "aws_instance" "kptboard" {
  ami = "${data.aws_ami.ecs_optimized.id}"
  instance_type = "${var.aws_instance_kptboard_instance_type}"
  iam_instance_profile = "${aws_iam_instance_profile.kptboard_ec2.name}"
  vpc_security_group_ids = ["${aws_security_group.kptboard_ec2.id}"]
  user_data       = "${data.template_file.aws_instance_kptboard_user_data.rendered}"
  key_name        = "${var.aws_instance_kptboard_key_name}"
  subnet_id       = "${aws_subnet.kptboard_public_a.id}"
  associate_public_ip_address = true
  tags {
    Name = "${var.kptboard}"
  }
}

自動的に最新のECS-optimized AMIが取得できる

IAMのポリシーを別ファイルでjsonのテンプレートに切り出す

kptboard_ssm_policy.json.tpl
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ssm:GetParameters"
      ],
      "Resource": "arn:aws:ssm:${region}:${account_id}:parameter/${kptboard}.*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt"
      ],
      "Resource": "arn:aws:kms:us-east-1:${account_id}:key/alias/aws/ssm"
    }
  ]
}

aws_iam_policy.tf
data "template_file" "kptboard_ssm_policy" {
  template = "${file("policies/kptboard_ssm_policy.json.tpl")}"

  vars {
    account_id = "${data.aws_caller_identity.current.account_id}"
    region = "${data.aws_region.current.name}"
    kptboard = "${var.kptboard}"
  }
}

resource "aws_iam_policy" "kptboard_ssm" {
  name = "${var.kptboard}-ssm"
  policy = "${data.template_file.kptboard_ssm_policy.rendered}"
}

と書くことでIAM Policyのjsonを別ファイルとして切り離せる

一時的にECRリポジトリを作らない

variable.tf
variable "aws_ecr_repository_create" {
  default = "true"
}
aws_ecr_repository.tf
resource "aws_ecr_repository" "kptboard" {
  count = "${var.aws_ecr_repository_create ? 1 : 0}"
  name = "${var.kptboard}"
}

リポジトリ以外の部分をterraform destroyしてterraform applyした時に構築できるかを確認するのに、ECRリポジトリが消えてしまうとDocker Imageを再アップロードしないといけなくなって手間になる。
countを0にすることで実行されないで済む。

サンプル

kptboardというrailsアプリケーションをECSで動かす用のterrafromのソースを置きました。

https://github.com/f96q/kptboard-terraform