Amazon Web Services ブログ

AWS Step FunctionsとAmazon EKSの統合のご紹介

元の記事:https://aws.amazon.com/blogs/containers/introducing-aws-step-functions-integration-with-amazon-eks/

本投稿は Romain Jourdanによる記事を翻訳したものです。

私がAWSに入社してからこれが初めてのAWS Container Blogへの投稿となりますが、サーバーレスとKubernetesという2つのテクノロジの融合、具体的にはAWS Step FunctionsとAmazon Elastic Kubernetes Serviceの統合についてお話しできることにこの上なく興奮しています。

前職では、お客様にオンデマンドで製品デモを提供するWebアプリケーションを構築していました。
私のチームは小規模でしたが、様々な責務やコミットメントがあったので、サーバーレスファーストでWebアプリケーションを構築していました。これにより、インフラストラクチャのデプロイ作業に集中するのではなく、運用上のオーバーヘッドを最小限に抑えながらビジネスロジックの設計に集中することができました。ビジネスロジックをワークフローに組み込む上でAWS Step Functionsはとても便利でした。ワークフローでは様々なAWS Lambda functionsを呼び出し、DynamoDBからデータを読み書きし、SNSやS3などのその他のサーバーレスのサービスを活用しました。ある日、ワークフローの中のタスクでLambdaが提供するコンピューティング機能を超えた機能を必要とする複雑なタスクを見つけました。そのため、それらのタスクをコンテナで実行することにしました。Step FunctionsではAmazon ECSやAWS Fargateを使ってコンテナを実行することができるため、私たちのニーズに完全に一致していました。Step Functionsは前のステップからパラメータを渡してコンテナを起動し、コードが実行され、その結果がコンテナから返されるのを待ち、コンテナが終了してワークフローを続行します。

このユースケースは珍しくなく、以下のようなケースでコンテナを活用しているお客様もいます。

  • 15分以上実行するような長時間の処理タスク
  • 機械学習やビデオレンダリングにGPUが必要
  • Microsoft Windows環境上で実行するように設計されたコード
  • ARMのサポートが必要

今回、Amazon ECSに加えて、Amazon Elastic Kubernetes Service(EKS)によってオーケストレーションされたコンテナでジョブを実行することができるようになりました。Amazon EKSはマネージド型Kubernetesサービスで、お客様はKubernetesのコントロールプレーンをインストール、運用、維持管理することなく、AWS上でKubernetesを簡単に実行することができます。

コンテナを実行するためにAmazon ECS とAmazon EKSでどのように選択するかの詳細については、このブログ投稿をご確認ください。

以下の機能を使うことでAWS Step FunctionsとAmazon EKSの連携ができます。

  • Service Integration APIsを使用することで、Amazon EKSと相互作用するワークフローを作成することができます。
  • AWS Controllers for Kubernetes(ACK)を使用することで、KubernetesからAWS Step Functionsステートマシンを作成できます。

まずは、APIとの統合から見ていきましょう。

サービス統合API

AWS Step FunctionsにはAmazon EKSと統合するためのAPIサービスが2種類あります。1つはAmazon EKS APIを使用することで、Amazon EKS クラスターの作成と削除ができます。もう1つはKubernetes APIを使用することで、クラスター(Amazon EKS APIで作成したもの、もしくは既存のもの)と相互作用し、アプリケーションのワークフローの一部としてジョブ実行できます。

AWSマネジメントコンソール上でのサンプルプロジェクトのワークフロー例にお見せします。このワークフローではAmazon EKSクラスターとノードグループを作成し、そのクラスター上でジョブ実行し、ジョブが完了すると作成したリソースを削除します。

EKS Cluster lifecycle workflow

このAmazon EKS APIs の統合により、Amazon EKSクラスターの作成と削除、その作成したクラスター上で実行するジョブについて、Step Functionsから管理することができるようになりました。例えば、end-to-endのテストやKubernetesの適合テストを実行するための一時的なAmazon EKSクラスター構築をワークフローに組み込むこともできます。詳細については“Amazon EKSクラスターの管理”をご確認ください。

注意: AWS Step Functionsの標準ワークフローの実行は各状態の待機時間ではなく、状態遷移の数に応じて課金されます(料金ページをご確認ください)。Amazon EKSクラスターが作成され、準備完了となるまでの待ち時間は課金されません。Amazon EKS 料金ページで説明している通り、Amazon EKSはクラスターが準備完了となると1時間ごとに課金されます。

別のシナリオについて考えてみましょう。あなたの会社はKubernetes上で標準化されたコンテナを管理しており、Amazon EKSを活用してクラウド上でコンテナを実行しています。あなたは既にAmazon EKSクラスターを運用しており、この環境と相互作用するワークフローを作りたいと考えています。あなたはKubernetes API:RunJobとCallを使用することで、Step Functionsとコンテナ環境を統合することができます。
eks:runJob service integrationを使用することで、Amazon EKSクラスター上でジョブを実行できます。eks:runJob.sync variantを使用することで、ジョブが完了するまで待ち、必要に応じてログを取得できます。eks:call service integration を使用することで、Kubernetes APIエンドポイント経由でKubernetesリソースオブジェクトを読み書きできます。詳細についてはStep Functionsドキュメントをご確認ください。

ワークフローの例

こちらの例では、Step Functionsの標準ワークフローを用いて、既存のAmazon EKSクラスター上でジョブを実行しようとしています。クラスターの名前は‘EKSCluster’としており、詳細は以下のようになっています。

EKSCluster details

あとで必要となるため、API server endpoint、Certificate authority、およびCluster ARNをメモしておいてください。

EKSCluster上でいくつかのパラメータを与えたジョブを起動し、その結果に何かしら処理を加え、最後にそのジョブを削除するといったシンプルなStep Functionsステートマシンを作成しようと思います。今回のこちらのケースでは、実行されたジョブは合格するだけです。

{
  "StartAt": "Run a job on EKS",
  "States": {
    "Run a job on EKS": {
      "Type": "Task",
      "Resource": "arn:aws:states:::eks:runJob.sync",
      "Parameters": {
        "ClusterName.$": "$.cluster.name",
        "CertificateAuthority.$": "$.cluster.ca",
        "Endpoint.$": "$.cluster.endpoint",
    "LogOptions": {
          "RetrieveLogs": true
        },
        "Job": {
          "apiVersion": "batch/v1",
          "kind": "Job",
          "metadata": {
            "name": "my-eks-job"
          },
          "spec": {
            "backoffLimit": 0,
            "template": {
              "metadata": {
                "name": "pi2000-on-eks"
              },
              "spec": {
              "containers": [
                {
                  "name": "pi-2000",
                  "image": "perl",
                  "command": [
                    "perl"
                  ],
                  "args": [
                    "-Mbignum=bpi",
                    "-wle",
                    "print '{ ' . '\"pi\": '. bpi(2000) . ' }';"
                  ]
                }
                ],
              "restartPolicy": "Never"
              }
            }
          }
        }
      },
      "ResultSelector": {
        "status.$": "$.status",
        "logs.$": "$.logs..pi"
      },
      "ResultPath": "$.RunJobResult",
      "Next" : "Do Something"
    },
    "Do Something":{
      "Type" : "Pass",
      "Next": "Delete Node"
    },
    "Delete Node":{
      "Type": "Task",
      "Resource": "arn:aws:states:::eks:call",
      "Parameters": {
        "ClusterName.$": "$.cluster.name",
        "CertificateAuthority.$": "$.cluster.ca",
        "Endpoint.$": "$.cluster.endpoint",
        "Method": "DELETE",
        "Path": "/apis/batch/v1/namespaces/default/jobs/my-eks-job"
      },
      "End": true
    }
  }
}

この段階でStep Functionsステートマシンを実行すると、ロールにKubernetes APIへの接続許可がないため、おそらく401エラーが発生すると思います。実際、Amazon EKSはKubernetes Role-Base Access Control (RBAC) を実装しており、Step Functionsステートマシンが引き受けるロール(この例ではEKS_StepFunctions_Integration)をKubernetes RBACのユーザーやロールとをマッピングする必要があります。詳細はAmazon EKSドキュメントをご確認ください。

認証フローは次の通りです。

Kubernetes RBAC

注意: 下記コマンドを実行するためにAWS CLIがインストールされていることを確認してください。詳細についてはAWS CLIドキュメントをご確認ください。

Kubernetes ConfigMapを修正する必要があるため、まずは次のコマンドを使用してクラスターから既存設定をコピーします。

kubectl get configmap -n kube-system aws-auth -o yaml > aws-auth.yaml

新しくできたaws-auth.yamlファイルをお好みのテキストエディタで更新してください。ファイルの中にクラスターのノードグループとの既存マッピング設定がありますが、修正しないでください。ユーザー(ここではeks-stepfunctions)と事前に作成したIAMロールをマッピングするように修正してください。

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: default
  name: run_job
rules:
- apiGroups: ["batch"]
  resources: ["jobs"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

RoleBindingリソースを使用して、ユーザーとロールを紐付けようと思います。job_role_binding.yamlという別ファイルを作ってください。

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: bind-run-job
subjects:
- kind: User
  name: eks-stepfunctions
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: run_job
  apiGroup: rbac.authorization.k8s.io

次に、作成したRoleとRoleBindingsを適用します。

kubectl apply -f job_role.yaml
kubectl apply -f job_role_binding.yaml

これで、Amazon EKSクラスター上でジョブを実行するするためのStep Functionsステートマシンの準備が整いました。
ステートマシンへの情報として最初にメモしたクラスターの詳細(cluster name、certificate authority、API server endpoint)が必要になります。

{
    "cluster" : {
      "name" : "EKSCluster",
      "ca" : "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJd01URXlOREUzTkRjd00xb1hEVE13TVRFeU1qRTNORGN3TTFvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUJYClpGcDNJTk9KdVVWQy8wTzdxaTkxQ3V5Qk04N0FkYUxHMDhBOEhZa0FDK2hIUk8zM00vVk9mTjZoSHdGL0EvZm8KSjZyWERyT041K29OVEZOdzNSbEFQODVDODdGdFkzZDdsN0VobHZtRjNEQVUybExDUWRjbGtQR0ZqdVB6ZFdLWQpPYUdoSm9EcktJalNBTlBvdjR6UDJGYWFYUWNiV2ZRSktYRkJ0YndBS1R0WXA4WW00YXFrZWx2WS9CNTVRMklQCjhxYWNMS2UxeGNuNVRUVHA5bTdrRkFxSWdqeS80ZUdQM3VvdVFwZkc0a0t4cXNUelllN3lxV0MrY3lxWXF5ZDQKWTVnK3RIanRlL2EzU1FINUFjd0tJUGJXQUlxNUVFMXVmRDBqZGlGYkQxbzJOUko2ZFR0bzlWQnllbjdGdWgzcQozbVV4Z2dCYzVjK2hpUlJONDRrQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFHN1FjcGRuaDVtK0Q5SjhwKzBNNElsQ2xmMmYKYlhZVytRaFdpd2lqQ0JuclR4Uy92Z1NaanhqTDBIbkcwR2dWVkJwcldVb1dvdnlpejRocWtJVUtTVkNXY0l3YwpsM1ExM2VMY25ra0E3QVdUcUw1dWF4S3p1c0xPbDRwdG5yZ2F0ZHRVRnc3WE9OZFp6cTFBeWRpbElmckNUbDZBCitkeTlIRGI3WnNUUm0rU201b0pLOWZyU3luc1gwNWVJNk9Od21ZWXdXMXFHbmR0eEN3VkQxZUJQajBWOEFGTVAKMHRibWpmU0crbENOd0J3QmhVbGhsNDhpWW9tR2dTOWR4ZGhaZy9sNnNmMzI5U0srUkRJM01TOEhQNVl5V1kvcQpKYTlST2RMTG5oYjV2S3hUTlZOakVUelp2R05rdThleWxpYUVMTTNUU2VKVlRFc2phUFNLZnFoNERUND0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=",
      "endpoint" : "https://171CE4AB2E76E2F1ABEDD0E37DD9A5D6.sk1.us-west-1.eks.amazonaws.com"
    }
}

ジョブが削除される前に、クラスター上での実行が成功したことをCLIですばやく再確認できます。

% kubectl describe job/my-eks-job 
Name:           my-eks-job
Namespace:      default
Selector:       controller-uid=8e2fa4c0-7cb3-488f-8626-d9c737399b12
Labels:         controller-uid=8e2fa4c0-7cb3-488f-8626-d9c737399b12
                job-name=my-eks-job
Annotations:    <none>
Parallelism:    1
Completions:    1
Start Time:     Wed, 25 Nov 2020 11:28:49 -0800
Completed At:   Wed, 25 Nov 2020 11:28:56 -0800
Duration:       7s
Pods Statuses:  0 Running / 1 Succeeded / 0 Failed
Pod Template:
  Labels:  controller-uid=8e2fa4c0-7cb3-488f-8626-d9c737399b12
           job-name=my-eks-job
  Containers:
   pi-2000:
    Image:      perl
    Port:       <none>
    Host Port:  <none>
    Command:
      perl
    Args:
      -Mbignum=bpi
      -wle
      print '{ ' . '"pi": '. bpi(2000) . ' }';
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Events:
  Type    Reason            Age   From            Message
  ----    ------            ----  ----            -------
  Normal  SuccessfulCreate  48s   job-controller  Created pod: my-eks-job-67lnb
  Normal  Completed         41s   job-controller  Job completed

最終的にワークフローが成功したことを確認できます。

Run Job on Amazon EKS with AWS Step Functions

AWS Controllers for Kubernetes (ACK) Step Functions Controller

Step Functionsステートマシンを作成する方法として、AWSコンソール、AWS SDK、AWS CloudFromationやAWS Cloud Development Kit (CDK)など様々な方法があります。Kubernetesネイティブのツールを使いたい場合は、AWS Controllers for Kubernetes (ACK)プロジェクトのStep Functionsコントローラを使用して、Kubernetesから直接Step Functionsステートマシンやアクティビティを作成して管理することができます。GitHubの開発者プレビューにあるので、ACK コントローラのインストールプロセスが簡単になるまでは、今のところはテストドライブをしてみるといいでしょう。

そのStepFunctionsコントローラはKubernetesリソースに期待するような動きをします。まずはStateMachine カスタムリソースを記述したstatemachine.yaml を作成します。

apiVersion: sfn.services.k8s.aws/v1alpha1
kind: StateMachine
metadata:
  name: my-ack-machine
spec:
  name: MyAckMachine
  roleARN: "arn:aws:iam::123456789012:role/service-role/MySFNRole"
  definition: "{ \"StartAt\": \"HelloWorld\", \"States\": { \"HelloWorld\": { \"Type\": \"Pass\", \"Result\": \"Hello World!\", \"End\": true }}}"

そして、kubectlを使ってKubernetesに定義を設定します、しばらくするとStep Functionsにステートマシンが現れます。

kubectl apply -f ~/statemachine.yaml

結論

今回の記事では新たな可能性を切り開くAWS Step FunctionsとAmazon EKSの新しい統合についてレビューしました。これにより、AWS Step Functionを既存のEKSクラスターと統合して、クラスター上で他の操作と同様にジョブを実行することが可能になりました。また、この機能により、一時的なAmazon EKSクラスターを作成してジョブを実行するといったサーバーレスなワークフローを作成することも可能になりました。最後に、新しいACK Step Functions Controllerによって、開発者はKubernetesから直接AWS Step Functionsのワークフローを作成できるようになりました。

素晴らしいワークフローのビルドを楽しんでください!

翻訳はソリューションアーキテクト多田 慎也が担当しました。原文はこちらです。