AWS Step Functions と Amazon EKS の連携でハマったこと
AWS Step Functions のステートマシンから Amazon EKS クラスターで Job を実行しようとしたときにハマったことをメモしておきます。
最初は、次の AWS Blog の記事がキッカケでした。
AWS Step FunctionsとAmazon EKSの統合のご紹介
この記事では、AWS Step Functions と Amazon EKS の統合について記載されてます。
これを、自分なりに試してみようと思ったわけです。
ただシンプルに試したかったので、EKS クラスターで Job の実行を行うだけのステートマシンを作成することにしました。
まず、自分が既に用意している EKS クラスターのエンドポイントや CertificateAuthority の情報を用意しておきます。
これは AWS マネジメントコンソール で EKSのクラスターの情報を表示すれば参照できますが、今回は AWS CLI で取得しています。
次のコマンドは dev-cluster というクラスターのエンドポイントを取得する例です。
aws eks describe-cluster --name dev-cluster | jq '.cluster.endpoint'
結果の例
"https://xxxxxxxxxxxxxxx.yz5.ap-northeast-1.eks.amazonaws.com"
次は CertificateAuthority を取得する例です。
aws eks describe-cluster --name dev-cluster | jq '.cluster.certificateAuthority.data'
結果の例 (実際は長い文字列ですが、省略しています。)
"LS0t6UFBwS29jU ... 0tCg=="
次に、AWS Step Functions で 標準タイプのステートマシンを作成していきます。
WorkFlow Builderで、次の図のように作成します。③ の APIパラメータに、EKS クラスター名やエンドポイント、CertificateAuthority を設定します。
③ の APIパラメータで、実行する Job のマニフェストを指定できます。デフォルトのままでもいいのですが、Job の実行時間を短縮したかったので、print bpi(2000) の個所を print bpi(20) に変更しました。
次の例は、APIパラメータで、Job のマニフェスト部分を抜粋したものです。
"Job": { "apiVersion": "batch/v1", "kind": "Job", "metadata": { "name": "my-example-job20" }, "spec": { "template": { "metadata": { "name": "my-example-job" }, "spec": { "containers": [ { "name": "my-function-name", "image": "perl", "command": [ "perl" ], "args": [ "-Mbignum=bpi", "-wle", "print bpi(20)" ] } ], "restartPolicy": "Never" } } } } },
次に、[ステートマシン設定を指定] のページの [アクセス許可] のセクションで、ステートマシンに設定するIAM ロールを指定します。 今回は、新しい IAM ロールを作成するように指定します。
そしてステートマシンの作成を完了させると、自動作成された IAM ロールの ARN が表示されるので、それをコピーします。
この IAM ロールは、 EKS クラスターで Job を実行する許可を与える必要があるため、EKS クラスターに接続できる環境から eksctl コマンドを使って次を実行します。
なお、AWSアカウント ID や IAM ロール名、EKS クラスター名は環境に応じて変更する必要があります。
実はこれがハマるポイントなのですが、説明は後にして、ひとまずこのまま実行します。
eksctl create iamidentitymapping --cluster dev-cluster --arn arn:aws:iam::000000000000:role/service-role/StepFunctions-EKS-RunJob-StateMachine-role-4b53263d --group system:masters --username my-statemachine
このコマンドは、あくまで例の一つですが、ステートマシンの IAM ロールと Kubernetes の system:masters グループをマッピングすることで、ステートマシンが EKS クラスターで Job を実行することを許可しています。
これで、ステートマシンから EKS クラスターに対して Job を実行する準備が整いました。
しかし、ステートマシンを実行すると、次のようなエラーが出てしまいます。
エラー EKS.401 原因 { "ResponseBody": { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "Unauthorized", "reason": "Unauthorized", "code": 401 }, "StatusCode": 401, "StatusText": "Unauthorized" }
さきほどの ekstctl コマンドで、IAM ロールを system:masters グループにマッピングしたはずなのに、なぜ Unauthorized になるのか理解できず、しばらく悩みました。
しかし、次の Step Functions のドキュメントをみると、この原因がわかりました。
Permissions | Call Amazon EKS with Step Functions
このドキュメントには、Note として次のような記載があります。
Note You may see the ARN for an IAM role displayed in a format that includes the path /service-role/, such as arn:aws:iam::123456789012:role/service-role/my-role. This service-role path token should not be included when listing the role in aws-auth.
つまり、ekstctl コマンドで、IAM ロールを system:masters グループにマッピングするときに、IAM ロールのARNに /service-role/ というパスを含めてはいけない! ということなんですね。
では、修正していきます。
まず、さきほどのマッピングを削除します。
eksctl delete iamidentitymapping --cluster dev-cluster --arn arn:aws:iam::000000000000:role/service-role/StepFunctions-EKS-RunJob-StateMachine-role-4b53263d
次に、/service-role/ を含まない ARN を指定して、マッピングを作成します。
eksctl create iamidentitymapping --cluster dev-cluster --arn arn:aws:iam::000000000000:role/StepFunctions-EKS-RunJob-StateMachine-role-4b53263d --group system:masters --username my-statemachine
このあと、ステートマシンを実行すると問題なく Job を起動することができました。
また、EKS クラスター側でも Job が完了したことを確認できました。
$ kubectl get jobs NAME COMPLETIONS DURATION AGE my-example-job 1/1 4s 4m21s $ kubectl describe job my-example-job Name: my-example-job Namespace: default Selector: controller-uid=cc291e67-8d12-4f64-b6c3-01e330957bed Labels: controller-uid=cc291e67-8d12-4f64-b6c3-01e330957bed job-name=my-example-job Annotations: <none> Parallelism: 1 Completions: 1 Start Time: Sun, 26 Jun 2022 00:24:58 +0000 Completed At: Sun, 26 Jun 2022 00:25:02 +0000 Duration: 4s Pods Statuses: 0 Running / 1 Succeeded / 0 Failed Pod Template: Labels: controller-uid=cc291e67-8d12-4f64-b6c3-01e330957bed job-name=my-example-job Containers: my-function-name: Image: perl Port: <none> Host Port: <none> Command: perl Args: -Mbignum=bpi -wle print bpi(20) Environment: <none> Mounts: <none> Volumes: <none> Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 4m33s job-controller Created pod: my-example-job-8k5xr Normal Completed 4m29s job-controller Job completed
ハマったといっても実はドキュメントには Note として記載してあったので、うっかりのレベルではあります。
ただ、ステートマシン作成時に IAM ロールを作成して、そのままコンソールに表示されている ARN をコピーしてしまうということは、ありがちではないかと思うので注意したいと思います。