[AWS Batch]Terraformでコンピューティング環境のインスタンスタイプを後から変更する苦肉の策

March 13, 2019

はじめに

表題の通り、コンピューティング環境のインスタンスタイプを変更しようとしてちょっと手こずりましたので対応を共有します。
賢明な方はお気づきかと思いますが、インスタンスタイプは後から変更できないので、厳密には再作成してサッと切り替えるという話になります。
なお記事の最後に注意点も書きましたので、重要な環境で実行する前によければご確認ください。

TL;DR

雰囲気でやるとどうなるか

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
resource "aws_iam_role" "ecs_instance_role" {
  name = "ecs_instance_role"

  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
    {
        "Action": "sts:AssumeRole",
        "Effect": "Allow",
        "Principal": {
          "Service": "ec2.amazonaws.com"
        }
    }
    ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "ecs_instance_role" {
  role       = "${aws_iam_role.ecs_instance_role.name}"
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
}

resource "aws_iam_instance_profile" "ecs_instance_role" {
  name = "ecs_instance_role"
  role = "${aws_iam_role.ecs_instance_role.name}"
}

resource "aws_iam_role" "aws_batch_service_role" {
  name = "aws_batch_service_role"

  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
    {
        "Action": "sts:AssumeRole",
        "Effect": "Allow",
        "Principal": {
        "Service": "batch.amazonaws.com"
        }
    }
    ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "aws_batch_service_role" {
  role       = "${aws_iam_role.aws_batch_service_role.name}"
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBatchServiceRole"
}

resource "aws_security_group" "sample" {
  name = "aws_batch_compute_environment_security_group"
}

resource "aws_vpc" "sample" {
  cidr_block = "10.1.0.0/16"
}

resource "aws_subnet" "sample" {
  vpc_id = "${aws_vpc.sample.id}"

  cidr_block = "10.1.1.0/24"
}

resource "aws_batch_compute_environment" "sample" {
  compute_environment_name = "sample"

  compute_resources {
    instance_role = "${aws_iam_instance_profile.ecs_instance_role.arn}"

    instance_type = [
      "c5",
    ]

    max_vcpus = 4
    min_vcpus = 0

    security_group_ids = [
      "${aws_security_group.sample.id}",
    ]

    subnets = [
      "${aws_subnet.sample.id}",
    ]

    type = "EC2"
  }

  service_role = "${aws_iam_role.aws_batch_service_role.arn}"
  type         = "MANAGED"
  depends_on   = ["aws_iam_role_policy_attachment.aws_batch_service_role"]
}

resource "aws_batch_job_queue" "test_queue" {
  name                 = "test_queue"
  state                = "ENABLED"
  priority             = 1
  compute_environments = ["${aws_batch_compute_environment.sample.arn}"]
}
-/+ aws_batch_compute_environment.sample (new resource required)
      id:                                               "sample" => <computed> (forces new resource)
                               ...
      compute_resources.0.instance_type.2800388089:     "c5" => "" (forces new resource)
      compute_resources.0.instance_type.2893327091:     "" => "m5" (forces new resource)
                               ...

  ~ aws_batch_job_queue.test_queue
      compute_environments.#:                           "1" => <computed>
aws_batch_compute_environment.sample: Destroying... (ID: sample)

Error: Error applying plan:

1 error(s) occurred:

* aws_batch_compute_environment.sample (destroy): 1 error(s) occurred:

* aws_batch_compute_environment.sample: error deleting Batch Compute Environment (sample): : Cannot delete, found existing JobQueue relationship

対策

Error: Error applying plan:

1 error(s) occurred:

* aws_batch_compute_environment.sample (destroy): 1 error(s) occurred:

* aws_batch_compute_environment.sample: error deleting Batch Compute Environment (sample): : Cannot delete, found existing JobQueue relationship
resource "aws_batch_compute_environment" "sample" {
  compute_environment_name = "sample-v2"
                     ...
    instance_type = [
      "m5",
    ]
                     ...
  lifecycle {
    create_before_destroy = true
  }
}

まとめと注意

以上の方法でコンピューティング環境名が変わることは不本意ながら、意図した結果になります。
これは Update requires: Replacement なパラメータ全般に言える話で、他にはBidPercentageあたり変更したいケースがあるかなと思いました。
ここで取り上げたインスタンスタイプはコストを予測するためにある程度固定したい場合が多いと思いますが、optimal(ジョブキューの需要に見合ったインスタンスタイプをオンザフライで使用する)を選択できる場合はそうしたほうが楽かもしれません。

最後にここまで書いておいてそれかい!という注意です。
今回書いたように一撃でコンピューティング環境を切り替えるためには、元のコンピューティング環境でジョブが実行されていない状態にする必要があります。
CloudWatch等から定期的にsubmitJobするようなケースではタイミングを見計らって一時的にルールを無効にする等で対応可能ですが、アプリケーションから任意のタイミングでsubmitJobするような場合、そういう状況を作るのはなかなか難しいでしょう。
ですので実際には、

みたいな段取りを踏むことになる場合が多いかなと。
そうなると、じゃあそういうのどこまで Infrastructure as Code みたいな枠組みでやったほうがいいの、的な議論に発展する機運が高まりますがそれはそれとして、今回のお話は限定的な状況でやってみたことの共有ということで、ここまでとさせていただきます。

@j_untanaka on Twitter

AWSAWSBatchTerraform