11
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【備忘録】Terraformをv0.12にあげたときの話

Last updated at Posted at 2019-08-18

Terraform歴

直近一年くらいAWS基盤をTerraformで構築・更改するっていう感じでした。
利用バージョンの変遷としては以下な感じ。
v0.11.3 -> v0.11.5 -> v0.11.7

まあv0.11.*太郎なわけです。
環境も変わったことだし、いっちょv0.12.*するか〜とv0.12.5で書き始めたところです。
その中での備忘録です。(まだ全然途中なのでちょくちょく更新入ると思います。)

Variables

すごく見やすく && 書きやすくなりました。
反面、一部同様に書いてあげないとうまくいかないケースがありました。

以前の書き方

v0.11.7時代の書き方

v0.11.7  ec2.tf
resource "aws_instance" "bastion" {
  ami                         = "${var.ec2_ami}"
  ebs_optimized               = false
  instance_type               = "${var.ec2_type}"
  monitoring                  = false
  key_name                    = "${var.secret_key}"
  subnet_id                   = "${aws_subnet.public.id}"
  vpc_security_group_ids      = ["${aws_security_group.bastion.id}"]
  associate_public_ip_address = true
  source_dest_check           = true
  iam_instance_profile        = "${var.service_name}-bastion"

  user_data = "${data.ec2_userdata.bastion.rendered}"

  root_block_device {
    volume_type           = "gp2"
    volume_size           = 50
    delete_on_termination = false
  }

  tags {
    "Name"    = "${var.service_name}-bastion-${var.environment}"
    "Service" = "${var.service_name}"
    "Env"     = "${var.environment}"
  }

  volume_tags {
    "Name"    = "${var.service_name}-bastion-${var.environment}"
    "Service" = "${var.service_name}"
    "Env"     = "${var.environment}"
  }

  lifecycle {
    ignore_changes = [
      "user_data",
      "key_name",
      "root_block_device.0.volume_type",
      "subnet_id",
    ]
  }
}

v0.12.5での書き方

v0.12.5で書くと

v0.12.5  ec2.tf
resource "aws_instance" "bastion" {
  ami                         = var.ec2_ami
  ebs_optimized               = false
  instance_type               = var.ec2_type
  monitoring                  = false
  key_name                    = var.secret_key
  subnet_id                   = aws_subnet.public.id
  vpc_security_group_ids      = aws_security_group.bastion.id
  associate_public_ip_address = true
  source_dest_check           = true
  iam_instance_profile        = "${var.service_name}-bastion"

  user_data = data.ec2_userdata.bastion.rendered

  root_block_device {
    volume_type           = "gp2"
    volume_size           = 50
    delete_on_termination = false
  }

  tags {
    "Name"    = "${var.service_name}-bastion-${var.environment}"
    "Service" = var.service_name
    "Env"     = var.environment
  }

  volume_tags {
    "Name"    = "${var.service_name}-bastion-${var.environment}"
    "Service" = var.service_name
    "Env"     = var.environment
  }

  lifecycle {
    ignore_changes = [
      "user_data",
      "key_name",
      "root_block_device.0.volume_type",
      "subnet_id",
    ]
  }
}

とまあすごくスッキリしてますし、実際大量に書くときは楽です。
が、一部旧形式で書いている部分がありますね。
String形式でもVariable単体では無い場合、やはりこういう書き方をしてあげないとplanで怒られます。

沼にハマる

個人的にはまったのはこれ。

v0.11.7  subnet.tf
resource "aws_subnet" "private" {
  count                   = "${length(split(",", lookup(local.availability_zones, var.region)))}"
  vpc_id                  = "${aws_vpc.service-vpc.id}"
  cidr_block              = "${cidrsubnet(aws_vpc.service-vpc.cidr_block, 4, count.index + length(split(",", lookup(local.availability_zones, var.region))) * 1)}"
  availability_zone       = "${element(split(",", lookup(local.availability_zones, var.region)), count.index)}"
  map_public_ip_on_launch = false
  depends_on              = ["aws_vpc.service-vpc"]

  tags = {
    Name         = "${var.service_name}-private-${var.environment}-${count.index}"
    Env          = "${var.environment}"
    Service      = ["${var.service_name}"]
  }
}

resource "aws_db_subnet_group" "db" {
  name        = "${var.service_name}-${var.short_env}-db"
  description = "${var.service_name} subnet group for db"
  subnet_ids  = ["${aws_subnet.private.*.id}"]

  tags = {
    Name         = "${var.service_name}-${var.environment}"
    Env          = "${var.environment}"
    Service      = "${var.service_name}"
  }
}

指定しているAZの数に応じてprivateサブネットを作成するようcountを利用しているのですが、そのidを参照して作成しようとしたら怒られました

Error
Error: Incorrect attribute value type

  on rds.tf line 75, in resource "aws_db_subnet_group" "db":
  75:   subnet_ids  = ["${aws_subnet.private.*.id}"]

Inappropriate value for attribute "subnet_ids": element 0: string required.

え、リストで指定せいゆーてたやん、、ドキュメントにも書いてあるやん。。

・subnet_ids - (Required) A list of VPC subnet IDs.

と思いつつ下記に変更したら通りました。。

correct.tf
resource "aws_db_subnet_group" "db" {
  name        = "${var.service_name}-${var.short_env}-db"
  description = "${var.service_name} subnet group for db"
  subnet_ids  = "${aws_subnet.private.*.id}"

  tags = {
    Name         = "${var.service_name}-${var.environment}"
    Env          = "${var.environment}"
    Service      = "${var.service_name}"
  }
}

v0.11.*にあんなに怒られたのになあ…(遠い目)と思いを馳せつつ実装を進めました。

ちなみにterraform 0.12upgradeで実施してみたら下記のように変更されてました。
※ やる前にちゃんとGithubにあげとくなりなんなりしないと戻すの大変なので注意!!!!

v0.12.5  subnet.tf
resource "aws_subnet" "private" {
  count                   = length(split(",", local.availability_zones[var.region]))
  vpc_id                  = aws_vpc.service-vpc.id
  cidr_block              = cidrsubnet(aws_vpc.service-vpc.cidr_block, 4, count.index + length(split(",", local.availability_zones[var.region])) * 1,)
  availability_zone       = element(split(",", local.availability_zones[var.region]), count.index,)
  map_public_ip_on_launch = false
  depends_on              = [aws_vpc.service-vpc]

  tags = {
    Name         = "${var.service_name}-private-${var.environment}-${count.index}"
    Env          = var.environment
    Service      = var.service_name
  }
}

resource "aws_db_subnet_group" "mysql-serverless" {
  name        = "${var.service_name}-${var.short_env}-db"
  description = "${var.service_name} subnet group for db"
  subnet_ids  = aws_subnet.private.*.id

  tags = {
    Name         = "${var.service_name}-${var.environment}"
    Env          = var.environment
    Service      = var.service_name
  }
}

余談ですがterraform 0.12upgradeで実施するとlengthとかcidrsubnetみたいなところはめちゃめちゃ改行されて出力されるんでびっくりします。

Error Message

まあこればっかりは仕方ないんですが、「こんなエラー出るかもな」でplan流したら結構長めの文で怒られます。凹みます。
いや、エラーメッセージの内容がすごく細かくなっていて、指摘通りに修正してあげると割とWeb徘徊しなくても解決しちゃうことが多いです。
助かる反面、最初はビビりました…大量に出たんでそんな変わったんか!?と
自分がショボかっただけでした。

Warining Sample

初歩的な変数設定のミスなのに、こんなやりかたもあんでという母のような優しさ。

 Warning
Warning: Value for undeclared variable

  on sandbox.tfvars line 3:
   3: service = "sandbox"

The root module does not declare a variable named "service". To use this
value, add a "variable" block to the configuration.

Using a variables file to set an undeclared variable is deprecated and will
become an error in a future release. If you wish to provide certain "global"
settings to all configurations in your organization, use TF_VAR_...
environment variables to set these instead.

Error Sample

こっちでやってみたらどうだ?という父のような頼もしさ。

 Error
Error: Missing resource instance key

  on iam.tf line 18, in resource "aws_iam_role_policy_attachment" "policy-attach":
 273:   role       = "${aws_iam_role.role.name}"

Because aws_iam_role.role has "count" set, its attributes must be
accessed on specific instances.

For example, to correlate with indices of a referring resource, use:
    aws_iam_role.role[count.index]

Terraformは僕の両親です。

おまけ

新しい記法で書くとエディタがうまく反応してくれねっす。
Pycharmを使ってるんですが、バージョンが古いからかブロックの認識がうまくいかず…可読性の問題で結局元の書き方で書いて最後にぴゃぴゃっと直す的な。。

v0.11.7
1_3.png

v0.12.5
1_2.png
なんとイケてないやり方…精進します。。

moduleも使わんとなあと思いつつ、なかなか癖が抜けず。。

参考

このページだけで十分でした…神様🙏
terraform v0.12 アップデート terraform 0.12upgrade,terraform 0.12checklistサブコマンド実行結果と、ファイルの変更例

11
7
1

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
11
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?