プログラマ行進曲第二章

主にソフトウェア関連の技術をネタにした記事を執筆するためのブログ

Amazon VPC CNIプラグインの設定をTerraformで行う時にENIConfigの設定で詰まった

前回の記事でAmazon EKSアドオンの設定の際のスキーマについて書きました。

takuan-osho.hatenablog.com

今回は具体的にAmazon VPC CNIプラグインの設定をする際、ENIConfigの設定で初見では中々気づきづらいエラーが出て解消するのに難儀したという話をしようと思います。

今回も前回と同じく、以下の記事の内容を理解しておくとすんなり分かるタイプの話が多くなるでしょう。

aws.amazon.com

Amazon VPC CNIプラグインでカスタムネットワークの設定をする

Amazon EKSを使っている際、たとえば「普段使っているVPC内のprivate subnetが確保しているIPv4アドレスよりも多い数が確保できるsubnetとIPv4アドレスを使用して、pod用にIPアドレスを割り振りたい」など諸々要件があってカスタムネットワークの設定が必要になったとします。

そういうときにはAmazon VPC CNIプラグインに設定を追加して対応してやる必要があります。詳しくは以下AWS公式ドキュメントを参照。

docs.aws.amazon.com

機能の概要

Amazon EKS アドオン API に新しい configurationValues パラメータが追加されました。ローンチ時点では、このパラメータは、JSON BLOB として設定を受け入れます。YAML のサポートも近日中に開始される予定です。JSON BLOB は、作成または更新しようとしているアドオンの特定バージョンごとの JSON Schema に準拠する必要があります。スキーマは、新しい API である Amazon EKS DescribeAddonConfiguration API を通じて利用可能です。以下で説明するように、 configurationValues パラメータは aws eks create-addon および aws eks update-addon AWS CLI コマンドで使用できます。

ここで書かれているように、 configurationValues というパラメータに設定を書いてやります。

Terraformでここに設定を追加したい場合、ドキュメントのこの箇所のようにaws_eks_addon リソースの configuration_values argument にjsonencode関数でエンコードしたJSON形式のObjectを入れてやればいいです。

ただ、ここでENIConfigの設定を入れようとすると結構はまりポイントがありました。

ENIConfigカスタムリソースのスキーマのはまりポイント

前回の記事にも掲載した、Amazon VPC CNIプラグインの設定のスキーマから、ENIConfigに関わる部分だけ取り出してみます。

{
  "$ref": "#/definitions/VpcCni",
  "$schema": "http://json-schema.org/draft-06/schema#",
  "definitions": {
    "Affinity": {
      "type": [
        "object",
        "null"
      ]
    },
    "EniConfig": {
      "additionalProperties": false,
      "properties": {
        "create": {
          "type": "boolean"
        },
        "region": {
          "type": "string"
        },
        "subnets": {
          "additionalProperties": {
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string"
              },
              "securityGroups": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              }
            },
            "required": [
              "id"
            ],
            "type": "object"
          },
          "minProperties": 1,
          "type": "object"
        }
      },
      "required": [
        "create",
        "region",
        "subnets"
      ],
      "type": "object"
    },
# 省略
  },
  "description": "vpc-cni"
}

これはawscliで返ってきた値をjqでパースしたjsonなので要素の並び方がjq由来なのも手伝っているのでしょうが、このスキーマをパッと見てどんな感じか分かるでしょうか?

特に $.eniConfig.subnets の箇所の定義に自信を持って設定できるでしょうか?

私はJSONスキーマに慣れていないこともあり、この定義をちゃんと見ていたはずなのですが、結果的に読み切れて無くてTerraformの設定時によく分からないエラーに遭遇して時間を溶かしてしまいました。

具体的にはterraform plan時に出た、以下の様なエラーです。

module.eks_addon.aws_eks_addon.vpc_cni: Creating...
╷
│ Error: creating EKS Add-On (dev-cluster:vpc-cni): InvalidParameterException: ConfigurationValue provided in request is not supported: Json schema validation failed with error: [$.eniConfig.subnets: array found, object expected]{
│   RespMetadata: {
│     StatusCode: 400,
│     RequestID: "my-request-id"},
│   AddonName: "vpc-cni",
│   ClusterName: "dev-cluster",
│   Message_: "ConfigurationValue provided in request is not supported: Json schema validation failed with error: [$.eniConfig.subnets: array found, object expected]"}
│
│   with module.eks_addon.aws_eks_addon.vpc_cni,
│   on ../modules/eks_addon.tf line 4, in resource "aws_eks_addon" "vpc_cni":
│    4: resource "aws_eks_addon" "vpc_cni" {
│
╵

$.eniConfig.subnets: array found, object expected というエラーが表示され、「え?ここはarrayじゃないの?」となってしまいました。

定義のほうをちゃんと見ると $.eniConfig.subnets はobjectが型として指定されているのは分かるのですが、 "type": "object" までの記述が離れていて大分見分けが付きづらい状態です。

「ではどういう風に書けばいいのか?」という問いに対する答えを書いてしまうと、eniConfigの箇所には以下の様にavailability zoneの値をkeyにし、subnetの情報をそこに紐付ければいいです。

  eniConfig = {
    create  = true
    region  = "ap-northeast-1"
    subnets = {
      "ap-northeast-1a" = {
          id = "subnet-aaaaa",
          securityGroups = ["sg-yyyyy"]
    },
  }

aws_eks_addon リソースの configuration_values 引数にjsonencode関数で適切に変換しつつ上記のeniConfig要素を入れると、以下の様なCustom Resourceを作るのと同等になります。

  apiVersion: crd.k8s.amazonaws.com/v1alpha1
  kind: ENIConfig
  metadata:
    name: ap-northeast-1a
  spec:
    securityGroups:
      - "sg-yyyyy"
    subnet: "subnet-aaaaa"

$.eniConfig.subnets に設定したobjectのkeyにあたる ap-northeast-1a がENIConfig Custom Resourceの .metadata.name に設定されています。

ここがAmazon VPC CNIプラグインの設定をTerraformで行う時に一番分かりづらかったところです。

この形に適合するように値を変更したら、 Json schema validation failed with error というエラーは消え、実際にterraform applyすると必要な設定・リソースが入ることを確認できました。