📝

TerraformでECSの環境変数の値にboolや数値を使うとError decoding JSONになるので文字列にしよう

2023/02/08に公開

環境

  • Terraform v1.3.7
  • AWS Provider v4.50.0

エラーメッセージ

Terraformでaws_ecs_task_definitionを書いてplan/applyしたところ、以下のエラーになりました。

╷
│ Error: ECS Task Definition container_definitions is invalid: Error decoding JSON: json: cannot unmarshal bool into Go struct field KeyValuePair.Environment.Value of type string
│ 
│   with aws_ecs_task_definition.this,
│   on ecs.tf line 84, in resource "aws_ecs_task_definition" "this":
│   84:   container_definitions = jsonencode(
# 略

Error: ECS Task Definition container_definitions is invalid: Error decoding JSON: json: cannot unmarshal bool into Go struct field KeyValuePair.Environment.Value of type string

とあります。aws_ecs_task_definition内の、container_definitionsでboolを使っているのが問題のようです。

環境変数でboolを使ったケースとその対処

該当のcontainer_definitionsは以下です。

resource "aws_ecs_task_definition" "this" {
  # 略
    container_definitions = jsonencode(
    [
      {
        # 略
        environment = [
          {
            name  = "FOO"
            value = true
	  },
	]
	readonlyRootFilesystem = true
        # 略
      }
    ]
  )
}

環境変数FOOのvalueと、readonlyRootFilesystemでboolを使っていますね。

エラー文では、container_definitionsに対して指摘が上がっていますが、色々試したところ、environment blockの中だけが問題のようです。

以下のように環境変数のvalueだけ文字列にしましたが、これでplan/applyが通りました。

resource "aws_ecs_task_definition" "this" {
  # 略
    container_definitions = jsonencode(
    [
      {
        # 略
        environment = [
          {
            name  = "FOO"
            value = "true" # 文字列にするとplan/applyが通る
	  },
	]
	readonlyRootFilesystem = true # boolのままで問題なし
        # 略
      }
    ]
  )
}

環境変数で数値を使ったケースとその対処

同様に環境変数で数値を使ったケースもplan/applyでエラーになります。

resource "aws_ecs_task_definition" "this" {
  # 略
    container_definitions = jsonencode(
    [
      {
        # 略
	portMappings = [
          {
            hostPort      = 3000
            containerPort = 3000
            protocol      = "tcp"
          }
        ]

        environment = [
          {
            name  = "DB_PORT"
            value = 5432
	  },
	]
        # 略
      }
    ]
  )
}

hostPortなどはenvironment blockではないので問題ありませんが、
環境変数DB_PORTのvalueは数値のため、エラーになります。

Error: ECS Task Definition container_definitions is invalid: Error decoding JSON: json: cannot unmarshal number into Go struct field KeyValuePair.Environment.Value of type string

以下のように環境変数のvalueだけ文字列にしましたが、これでplan/applyが通りました。

resource "aws_ecs_task_definition" "this" {
  # 略
    container_definitions = jsonencode(
    [
      {
        # 略
	portMappings = [
          {
            hostPort      = 3000 # 数値のままで問題なし
            containerPort = 3000 # 数値のままで問題なし
            protocol      = "tcp"
          }
        ]

        environment = [
          {
            name  = "DB_PORT"
            value = "5432" # 文字列にするとplan/applyが通る
	  },
	]
        # 略
      }
    ]
  )
}

他のTerraform resourceを参照していて、それが数値の場合はtostring関数を使う

以下のように、環境変数のvalueに、他のTerraform resourceを参照しており、それが数値の場合もやはりエラーになります。

resource "aws_ecs_task_definition" "this" {
  # 略
    container_definitions = jsonencode(
    [
      {
        # 略
        environment = [
          {
            name  = "DB_PORT"
            value = aws_db_instance.this.port # 数値
	  },
	]
        # 略
      }
    ]
  )
}

Error: ECS Task Definition container_definitions is invalid: Error decoding JSON: json: cannot unmarshal number into Go struct field KeyValuePair.Environment.Value of type string

このような場合は、tostring関数を使えばplan/applyが通ります。

resource "aws_ecs_task_definition" "this" {
  # 略
    container_definitions = jsonencode(
    [
      {
        # 略
        environment = [
          {
            name  = "DB_PORT"
            value = tostring(aws_db_instance.this.port)
	  },
	]
        # 略
      }
    ]
  )
}
スマートラウンド テックブログ

Discussion