EKSのFargate Profile更新時の失敗談

2022.11.28

今回は私がEKSのFargate Profileを更新した際にやってしまった失敗談をご紹介します。

どういう失敗だったか

Fargate Profileを有効化しているのにも関わらず、Fargate上で稼働しているPodがひとつもなかった、さらにそれに気づくのにも遅れた、というものです。

やったこと

Fargate NodeとEC2 Node(マネージド型ノードグループ)、両方を使うEKSクラスターを利用していました。Terraform RegistryにあるEKS moduleを使って以下のように、使用しているNamespace毎にFargate Profileを分けてプロビジョニングしていました。

locals {
  fargate_profiles = {
    for ns in local.fargate_namespaces :
    ns => {
      name = ns
      selectors = [
        {
          namespace = ns
        }
      ]
    }
  }
  fargate_namespaces = ["kube-system", "hoge", "fuga", "piyo"]
}

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "17.24.0"

  cluster_name     = local.eks_name
  cluster_version  = "1.22"
  vpc_id           = module.vpc.vpc_id

  (略)

  node_groups = {
    (local.node_group_name) = {
      subnets          = module.vpc.private_subnets
      desired_capacity = 2
      max_capacity     = 4
      min_capacity     = 1
      instance_types   = ["m6i.large"]
      disk_size        = 80
    }
  }

  fargate_profiles = local.fargate_profiles
  fargate_subnets  = module.vpc.private_subnets
}

Namespace毎にFargate Profileを分けたことに特に理由はありませんでした。一方で、分けることのデメリットに後々気づきました。作成と削除にとても時間がかかるのです。

  • クラスターのいずれかの Fargate プロファイルが DELETING ステータスである場合は、Fargate プロファイルの削除が完了するのを待ってから、そのクラスターに他のプロファイルを作成する必要があります。
  • 一度にクラスター内の 1 つの Fargate プロファイルのみが、DELETING ステータスになることができます。そのクラスター内の他のプロファイルを削除する前に、Fargate プロファイルの削除が完了するまでお待ちください。

AWS Fargate プロファイル - Amazon EKSより引用

上記に書かれているように、Profileの削除はひとつずつ行う必要があり並列ではできません。また作成についてはドキュメントに記述がありませんでしたが、削除時と同じく複数のProfileを並列作成はできず、ひとつずつ行なう必要があります。作成中(=Status がCREATING)のProfile xxxがある状態で別のProfile yyyを作成しようとすると以下のエラーになりました。

Cannot create Fargate Profile yyy because cluster (クラスター名) currently has Fargate profile xxx in status CREATING

1Profileの作成・削除あたり数分以上かかることもあるので、これを直列でやるのは遅いです。 というわけで、namespace毎にFargate Profileを作成することは得策ではないと考え、以下のように修正してひとつのProfileに統合することにしました。

 locals {
   fargate_profiles = {
+    default = {
+      name = "default"
+      selectors = concat(
+       [for ns in local.fargate_namespaces :
+          {
+            namespace = ns
+          }
+        ]
+      )
+    }
-    for ns in local.fargate_namespaces :
-    ns => {
-      name = ns
-      selectors = [
-        {
-          namespace = ns
-        }
-      ]
-    }
   }
   fargate_namespaces = ["kube-system", "hoge", "fuga", "piyo"]
 }

(略)

この terraform applyは成功しました。が、この時からFargate Pod上で稼働しているPodがなくなりました。

原因

applyの処理順を確認すると原因がわかりました。

  1. 既存のFargate Profileを削除 → この時点で、それまでFargate Node上で起動していたPodはすべてEC2 Nodeにスケジュールし直される
  2. 新Fargate Profile作成 → Fargate Profileが働くのはPod起動時のみ。 1でEC2 Node上で起動し直したPodは対象外

まあよく考えたら分かる話なんですが、気づけなかったです…

対応方法

1. 既存Fargate Profileの削除前に新規Fargate Profileを作成する

  • Fargate プロファイルを削除すると、そのプロファイルで Fargate にスケジューリングされていた pods はすべて削除されます。これらの pods が別の Fargateプロファイルと一致する場合、それらのポッドはそのプロファイルで Fargate にスケジューリングされます
    Fargate プロファイルの削除 - AWS Fargate プロファイル - Amazon EKSより引用

今回の更新内容を2つにわけて、

  1. 新Profileのコードを追加してapply
  2. 旧Profilesのコードを削除してapply

と2回applyするようにすれば、2で「そのプロファイルで Fargate にスケジューリングされていた pods はすべて削除されます」が、「これらの pods が別の Fargateプロファイルと一致する場合、それらのポッドはそのプロファイルで Fargate にスケジューリングされます」に当てはまるので、再びFargate Node上でPodが稼働し始めます。

2. Podのrestart

1は予防策ですが、こちらは事後対応つまりもうすでにEC2 Node上でPodが稼働してしまっている場合の修正方法です。もう一度Podの作成を発生させればFargate Profileをチェックして該当PodをFargate Node上で起動する処理が走りますので、kubectl rollout restart deploymentsコマンドでPodの再作成を強制すれば良いです。