前書き
掲題の通り、StepFunctionからEKSjobを呼び出すシステムを構築する際に詰まったポイントを備忘録として記しておきたいと思います。
StepFunctionとは
公式より
AWS Step Functions は、デベロッパーが AWS のサービスを利用して分散型アプリケーションを構築し、プロセスを自動化し、マイクロサービスのオーケストレーション、データと機械学習のパイプラインを構築できるようにするビジュアルワークフローサービスです。
個人的にStepFunctionというのは、Lambdaをトリガーとして異なるサービスを呼び出すようなつながりがたくさんある複雑なシステムを、簡潔にまとめ上げられるシステムなのかなーと思っています。
StepFunctionで作り上げた一連のシステムは、ステートマシンという単位で表されます。EC2で言うインスタンスみたいなものですね。
やりたいこと
まずはEKSとの疎通を確認したいと思い、StepFunctionからEKSjobを呼び出して終了するだけの単純なステートマシンを作りたい!と思って構築を始めました。
マネコンからはJSON形式でしか扱えないみたいです...
YAML対応待ってます!
こちらがソースコードです。長いので折りたたんでいます。
{
"Comment": "A description of my state machine",
"StartAt": "EKS RunJob",
"States": {
"EKS RunJob": {
"Type": "Task",
"Resource": "arn:aws:states:::eks:runJob",
"Parameters": {
"ClusterName": "eks-cluster-name",
"CertificateAuthority": "xxxxxxxxxx",
"Endpoint": "https://xxxxxxxxxx.eks.amazonaws.com",
"Job": {
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": "my-example-job"
},
"spec": {
"template": {
"metadata": {
"name": "my-example-job"
},
"spec": {
"containers": [
{
"name": "my-function-name",
"image": "perl",
"command": [
"perl"
],
"args": [
"-Mbignum=bpi",
"-wle",
"print bpi(2000)"
]
}
],
"restartPolicy": "Never"
}
}
}
}
},
"Next": "EKS Delete"
},
"EKS Delete": {
"Type": "Task",
"Resource": "arn:aws:states:::eks:call",
"Parameters": {
"ClusterName": "eks-cluster-name",
"CertificateAuthority": "xxxxxxxxxx",
"Endpoint": "https://xxxxxxxxxx.eks.amazonaws.com",
"Method": "DELETE",
"Path": "/apis/batch/v1/namespaces/default/jobs/my-example-job",
"RequestBody": {
"apiVersion": "v1",
"kind": "Namespace",
"metadata": {
"name": "my-namespace",
"labels": {
"name": "my-namespace"
}
}
}
},
"End": true
}
}
}
構築開始
EKSと疎通できるようにするために、RBACを用いてステートマシンに割り当てられたロールからEKSにアクセスできるようにします。eksctlコマンドを用いてロールを割り当てます。
StepFunctionはマネージドサービスなので、セキュリティグループなどの穴あけは不要です。
ロールのarnをコピーペーストすると以下のようになります。
eksctl create iamidentitymapping
--cluster dev-cluster
--arn arn:aws:iam::xxxxxxxxxx:role/service-role/StepFunctions-EKS-RunJob-StateMachine-role-4b53263d
--group system:masters --username my-statemachine
ロールには適切なポリシーをアタッチしたし、RBACも完璧!と思って実行したら以下のようなエラーが出ました。
{
"resourceType": "eks",
"resource": "runJob",
"error": "EKS.ConnectTimeoutException",
"cause": "An error occurred when attempting to call the Kubernetes API server."
}
筆者はまずここで詰まっていました。
ネットを調べてみると、全く同じ状況に陥っている様子の記事がありました。
こちらによると、arnの箇所に/service-roleを書いてはいけないそうです。
ということで、正しくは以下のようになります。
eksctl create iamidentitymapping
--cluster dev-cluster
--arn arn:aws:iam::xxxxxxxxxx:role/StepFunctions-EKS-RunJob-StateMachine-role-4b53263d
--group system:masters --username my-statemachine
ですが、それでもエラーが変わらない。
もう一度エラーをよく見てみます。
{
"resourceType": "eks",
"resource": "runJob",
"error": "EKS.ConnectTimeoutException",
"cause": "An error occurred when attempting to call the Kubernetes API server."
}
先ほど引用したサイトでは、ロールによる認可が行われていないことによるエラーは以下のようになるとのことでした。
エラー
EKS.401
原因
{
"ResponseBody": {
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
},
"StatusCode": 401,
"StatusText": "Unauthorized"
}
どうやら認可云々の話よりもっと手前の、アクセス自体が拒否されているようなエラーに見えます。
公式サイトを見てみると、こんな注意書きがありました。
注記
Step Functions EKS 統合は、公開エンドポイントにアクセスできる Kubernetes API だけをサポートします。デフォルトでは、EKS クラスターの API サーバーエンドポイントにはパブリックアクセス権があります。詳細については、Amazon EKS ユーザーガイドの「Amazon EKS クラスターエンドポイントアクセスコントロール 」を参照してください。
どうやら、インターネットに公開されていないAPIサーバーエンドポイントに対してステートマシンはアクセスすることができないようです。
パブリックに公開しないと叩けない?世のEKSはパブリックに公開されているのか?と疑問に思い、Kubernetesマスターの先輩に疑問をぶつけてみました。
先輩からの回答によると、結局RBACを行うのでパブリックに公開することが多いよ~とのことでした。
EKSのマネコンを確認すると、APIサーバーエンドポイントがプライベートだったのでコンソール上からパブリックおよびプライベートに変更しました。
2度のエラーを乗り越え、ついに成功することができました!!!緑色って素晴らしいですね。
感想
StepFunctionでECSタスクを呼び出している記事はちらほら見かけたのですが、EKSjobを呼び出している記事はほとんどありませんでした。EKSよりもECSのほうがよく使われているんですかね?
初めて他を探しても見つからない独自性の高い記事だと自負できる記事が書けた気がしてとても嬉しいです。