話題の記事

[アップデート] AWS Step Functionsが200以上のAWSサービスと連携できるようになりました

AWS Step Functionsが連携できるAWSのサービスが17個から200個まで大幅に増加しました。これにより実行できるAPIの数は9,000以上となりました。このアップデートによりAPIを叩くためだけのLambda関数を用意する必要がなくなり、AWS Step Functionsの使いやすさがグッと増したと思います。
2021.10.01

AWS Step Functionsが連携できるサービスが爆増しました

こんにちは、のんピ(@non____97)です。

AWS Step Functionsの連携可能サービス数が200個以上に増える神アップデートが来ました!!

これにより、AWS Step Functionsから直接実行できるAPIの数は9,000以上となりました。

今まで、例えばEC2インスタンスを停止したい場合は、EC2インスタンスを停止させるLambda関数を用意して、そのLambda関数をAWS Step Functionsから実行する必要がありました。 この1ステップが削減されただけですが、以下の様なメリットがあると考えます。

  • 大量のLambda関数の作成/メンテナンスが不要
  • タスク(API)を実行する際に必須なパラメーターを表示してくれるので、ステートマシンの作成の準備や手間を削減
  • Workflow Studio上では、タスクごとに実行するAPIのAWSサービスのアイコンも表示されているので、ステートマシンでどのようなサービスを使用しているのかを簡単に把握可能

このアップデートにより、Step Functionsの使いやすさがグッと増したと思います。

加えて、AWS Step Functionsは個人的2021年上半期最高アップデートのWorkflow Studioにより、GUI上で簡単にワークフローを設計できるようになっています。Workflow Studioの説明は以下記事をご参照ください。

今まで、AWS Step Functionsに苦手意識を持っていた方や、触ったことがなかった方は、是非触ってみてください! 世界が変わります。

そんな私はこのアップデートで興奮しすぎて心臓がドキドキしています。

AWS Step FunctionsのWorkflow StudioでWebシステムの停止のステートマシンを組んでみる

作業内容の確認

私は以前以下記事で紹介している通り、ジョブ管理システムから抜け出すために、AWS Step FunctionsとSSM RunCommandでステートマシンを組みました。

こちらの記事で作成したWebシステムの停止のステートマシンは以下のように、複雑怪奇な状態です。

Webシステムの停止ステートマシン

今回は、こちらとほぼ同様なステートマシンを作成してみたいと思います。(Mapを使った複数のEC2インスタンスへの処理は省略しました)

事前準備

まず事前準備です。

事前準備として、以下の作業を行います。

  • AWS CDKでWebシステムをデプロイ
  • EC2インスタンスにCloudWatch Agentをインストール・設定
  • EC2インスタンス上のhttpd(Apache)の起動

実行するAWS CDKはこちらの記事で紹介したコードを使ってデプロイします。

デプロイ後、上述した記事のEC2インスタンスへのCloudWatchの設定を参考にEC2インスタンスにCloudWatch Agentをインストール・設定も行います。

最後にUser Dataで作成したスクリプトを実行して、以下のようにhttpdを起動します。

# 起動前のhttpdのステータスの確認
$ sudo bash /usr/local/sbin/checkHttpd.sh
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/httpd.service.d
           └─php-fpm.conf
   Active: inactive (dead)
     Docs: man:httpd.service(8)

# httpdの起動
$ sudo bash /usr/local/sbin/startHttpd.sh

# 起動後のhttpdのステータスの確認
$ sudo bash /usr/local/sbin/checkHttpd.sh
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/httpd.service.d
           └─php-fpm.conf
   Active: active (running) since Fri 2021-10-01 09:07:50 UTC; 2s ago
     Docs: man:httpd.service(8)
 Main PID: 2404 (httpd)
   Status: "Processing requests..."
   CGroup: /system.slice/httpd.service
           ├─2404 /usr/sbin/httpd -DFOREGROUND
           ├─2414 /usr/sbin/httpd -DFOREGROUND
           ├─2416 /usr/sbin/httpd -DFOREGROUND
           ├─2421 /usr/sbin/httpd -DFOREGROUND
           ├─2423 /usr/sbin/httpd -DFOREGROUND
           └─2428 /usr/sbin/httpd -DFOREGROUND

Oct 01 09:07:50 ip-10-0-2-247.ec2.internal systemd[1]: Starting The Apache HTTP Server...
Oct 01 09:07:50 ip-10-0-2-247.ec2.internal systemd[1]: Started The Apache HTTP Server.

CloudWatch Logsからもこちらのスクリプトが実行されていることを確認します。

CloudWatch Logsでのhttp起動の確認

実際にブラウザでWebサーバーにアクセスできるかも確認しましょう。

ALBのDNS名をコピーします。

ALBのDNS名

コピーしたDNS名にブラウザでアクセスすると、Apache HTTP Serverのテストページが表示されることが確認できます。

Apache HTTP Serverのテストページの表示

また、ステートマシンでWebシステムを停止する前にEC2インスタンスとDBクラスターが起動していることも確認します。

ステートマシン実行前のEC2インスタンスの状態

ステートマシン実行前のDBクラスターの状態

ステートマシンの作成

それでは、AWS Step FunctionsのWorkflow Studioを使って、Webシステムの停止ステートマシンを作成します。

まず、AWS Step Functionsのコンソールを開きます。そして、ステートマシンからステートマシンの作成をクリックします。

ステートマシンの作成

次にステートマシンの作成方法を指定します。

今回は、Workflow Studioで作成するので、ワークフローを視覚的に設計を選択します。また、タイプは標準を選択して、次へをクリックします。

ステートマシンの作成方法を選択

そして、Workflow Studioでステートマシンのワークフローを設計します。

見てください。この未来感。興奮を隠せません。APIを検索して、ドラッグ&ドロップするだけで簡単にタスク同士を接続することができます。また、APIパラメーターで必須のものは表示されているので、最低限どのような情報を渡せば良いのかが分かりやすくなっています。

ワークフローの設計開始

最終的なワークフローは以下のようになりました。「結構細かそうだな...」と思われる方も多いかもしれませんが、JSONで設定するよりか直感的に操作できるため、そこまでストレスなく設計できました。

Workflow Studioでのワークフローの設計

右上のExport - Export PNG Imageをクリックすると、以下のようにワークフローをPNG形式でダウンロードできます。エクスポートするとアイコンが表示されなくなるのが少し残念ですね。

Workflow Studioで設計したワークフローのエクスポート

次に生成されたコードの確認です。

Workflow Studioで設計したのワークフローから生成されたコードを確認することができます。確認が完了したら次へをクリックします。

生成されたコードの確認

参考までに生成されたコードは以下の通りです。

生成されたコード
{
  "Comment": "This is your state machine",
  "StartAt": "CreateRule for maintenance mode",
  "States": {
    "CreateRule for maintenance mode": {
      "Type": "Task",
      "Parameters": {
        "Actions": [
          {
            "Type": "fixed-response",
            "FixedResponseConfig": {
              "StatusCode": "503",
              "ContentType": "text/html",
              "MessageBody": "<!doctype html><html lang=\"ja\"><head><meta charset=\"UTF-8\"><!-- Required meta tags --><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><!-- Bootstrap CSS --><link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css\" rel=\"stylesheet\"integrity=\"sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1\" crossorigin=\"anonymous\"><title>ただいまメンテナンス中です</title></head><body class=\"m-5\"><div class=\"mx-auto\"><h1 class=\"text-center text-danger font-bold\">ただいまメンテナンス中です</h1><dl class=\"text-center text-lg font-bold\"><dt>【メンテナンス日時】</dt><dd class=\"\">2021年5月21日 0:00〜0:30</dd></dl><p class=\"text-center\">メンテナンス終了までしばらくお待ちください。</p></div></body></html>"
            }
          }
        ],
        "Conditions": [
          {
            "Field": "source-ip",
            "SourceIpConfig": {
              "Values": [
                "0.0.0.0/0"
              ]
            }
          }
        ],
        "ListenerArn": "arn:aws:elasticloadbalancing:us-east-1:<AWSアカウントID>:listener/app/WebAp-Alb16-1PFUCP6F9WBO4/5388462c9625591a/b1301fb282842d15",
        "Priority": 1
      },
      "Resource": "arn:aws:states:::aws-sdk:elasticloadbalancingv2:createRule",
      "Next": "SendCommand - stop httpd",
      "ResultPath": "$.Output"
    },
    "SendCommand - stop httpd": {
      "Type": "Task",
      "Parameters": {
        "InstanceIds": [
          "i-09daf1c434dd8d7ca"
        ],
        "DocumentName": "AWS-RunShellScript",
        "MaxConcurrency": "1",
        "Parameters": {
          "commands": [
            "sudo bash /usr/local/sbin/stopHttpd.sh"
          ]
        },
        "TimeoutSeconds": 60
      },
      "Resource": "arn:aws:states:::aws-sdk:ssm:sendCommand",
      "Next": "Wait 10 sec for \"SendCommand - stop httpd\""
    },
    "Wait 10 sec for \"SendCommand - stop httpd\"": {
      "Type": "Wait",
      "Seconds": 10,
      "Next": "ListCommandInvocations - \"stop httpd\""
    },
    "ListCommandInvocations - \"stop httpd\"": {
      "Type": "Task",
      "Parameters": {
        "CommandId.$": "$.Command.CommandId",
        "Details": "true"
      },
      "Resource": "arn:aws:states:::aws-sdk:ssm:listCommandInvocations",
      "Next": "Success or failure \"SendCommand - stop httpd\""
    },
    "Success or failure \"SendCommand - stop httpd\"": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.CommandInvocations[0].Status",
          "StringEquals": "Success",
          "Next": "SendCommand - describe httpd status"
        },
        {
          "Or": [
            {
              "Variable": "$.CommandInvocations[0].Status",
              "StringEquals": "Pending"
            },
            {
              "Variable": "$.CommandInvocations[0].Status",
              "StringEquals": "InProgress"
            }
          ],
          "Next": "Wait 10 sec for \"SendCommand - stop httpd\""
        }
      ],
      "Default": "Faild stop httpd"
    },
    "SendCommand - describe httpd status": {
      "Type": "Task",
      "Parameters": {
        "InstanceIds": [
          "i-09daf1c434dd8d7ca"
        ],
        "DocumentName": "AWS-RunShellScript",
        "MaxConcurrency": "1",
        "Parameters": {
          "commands": [
            "sudo bash /usr/local/sbin/checkHttpd.sh"
          ]
        },
        "TimeoutSeconds": 60
      },
      "Resource": "arn:aws:states:::aws-sdk:ssm:sendCommand",
      "Next": "Wait 10 sec for \"SendCommand - describe httpd status\""
    },
    "Wait 10 sec for \"SendCommand - describe httpd status\"": {
      "Type": "Wait",
      "Seconds": 10,
      "Next": "ListCommandInvocations - describe httpd status"
    },
    "ListCommandInvocations - describe httpd status": {
      "Type": "Task",
      "Parameters": {
        "CommandId.$": "$.Command.CommandId",
        "Details": "true"
      },
      "Resource": "arn:aws:states:::aws-sdk:ssm:listCommandInvocations",
      "Next": "Success or failure \"SendCommand - descibe httpd status\""
    },
    "Success or failure \"SendCommand - descibe httpd status\"": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.CommandInvocations[0].CommandPlugins[0].ResponseCode",
          "NumericEquals": 3,
          "Next": "StopInstances"
        },
        {
          "Or": [
            {
              "Variable": "$.CommandInvocations[0].Status",
              "StringEquals": "Pending"
            },
            {
              "Variable": "$.CommandInvocations[0].Status",
              "StringEquals": "InProgress"
            }
          ],
          "Next": "Wait 10 sec for \"SendCommand - describe httpd status\""
        }
      ],
      "Default": "Failed describe httpd status"
    },
    "StopInstances": {
      "Type": "Task",
      "Parameters": {
        "InstanceIds": [
          "i-09daf1c434dd8d7ca"
        ]
      },
      "Resource": "arn:aws:states:::aws-sdk:ec2:stopInstances",
      "Next": "Wait 30 sec for \"StopInstances\""
    },
    "Wait 30 sec for \"StopInstances\"": {
      "Type": "Wait",
      "Seconds": 30,
      "Next": "DescribeInstances"
    },
    "DescribeInstances": {
      "Type": "Task",
      "Next": "Is stopped EC2 instances",
      "Parameters": {
        "InstanceIds": [
          "i-09daf1c434dd8d7ca"
        ]
      },
      "Resource": "arn:aws:states:::aws-sdk:ec2:describeInstances"
    },
    "Is stopped EC2 instances": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.Reservations[0].Instances[0].State.Code",
          "NumericEquals": 80,
          "Next": "StartBackupJob - EC2 Instances"
        }
      ],
      "Default": "Wait 30 sec for \"StopInstances\""
    },
    "StartBackupJob - EC2 Instances": {
      "Type": "Task",
      "Parameters": {
        "BackupVaultName": "Default",
        "IamRoleArn": "arn:aws:iam::<AWSアカウントID>:role/service-role/AWSBackupDefaultServiceRole",
        "ResourceArn": "arn:aws:ec2:us-east-1:<AWSアカウントID>:instance/i-09daf1c434dd8d7ca"
      },
      "Resource": "arn:aws:states:::aws-sdk:backup:startBackupJob",
      "Next": "StartBackupJob - DB Cluster"
    },
    "StartBackupJob - DB Cluster": {
      "Type": "Task",
      "Parameters": {
        "BackupVaultName": "Default",
        "IamRoleArn": "arn:aws:iam::<AWSアカウントID>:role/service-role/AWSBackupDefaultServiceRole",
        "ResourceArn": "arn:aws:rds:us-east-1:<AWSアカウントID>:cluster:webappstack-dbcluster15af587f-1cq946f88dm5z"
      },
      "Resource": "arn:aws:states:::aws-sdk:backup:startBackupJob",
      "Next": "Wait 60 sec for \"DescribeDBClusters for available backup\""
    },
    "Wait 60 sec for \"DescribeDBClusters for available backup\"": {
      "Type": "Wait",
      "Seconds": 60,
      "Next": "DescribeDBClusters for available backup"
    },
    "DescribeDBClusters for available backup": {
      "Type": "Task",
      "Parameters": {
        "DbClusterIdentifier": "webappstack-dbcluster15af587f-1cq946f88dm5z"
      },
      "Resource": "arn:aws:states:::aws-sdk:rds:describeDBClusters",
      "Next": "Is available backup"
    },
    "Is available backup": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.DbClusters[0].Status",
          "StringEquals": "available",
          "Next": "StopDBCluster"
        },
        {
          "Or": [
            {
              "Variable": "$.DbClusters[0].Status",
              "StringEquals": "backing-up"
            },
            {
              "Variable": "$.DbClusters[0].Status",
              "StringEquals": "backtracking"
            },
            {
              "Variable": "$.DbClusters[0].Status",
              "StringEquals": "maintenance"
            }
          ],
          "Next": "Wait 60 sec for \"DescribeDBClusters for available backup\""
        }
      ],
      "Default": "Failed start backup job for db cluster"
    },
    "StopDBCluster": {
      "Type": "Task",
      "Parameters": {
        "DbClusterIdentifier": "webappstack-dbcluster15af587f-1cq946f88dm5z"
      },
      "Resource": "arn:aws:states:::aws-sdk:rds:stopDBCluster",
      "Next": "Wait 60 sec for \"StopDBCluster\""
    },
    "Wait 60 sec for \"StopDBCluster\"": {
      "Type": "Wait",
      "Seconds": 60,
      "Next": "DescribeDBClusters for \"StopDBCluster\""
    },
    "DescribeDBClusters for \"StopDBCluster\"": {
      "Type": "Task",
      "Parameters": {
        "DbClusterIdentifier": "webappstack-dbcluster15af587f-1cq946f88dm5z"
      },
      "Resource": "arn:aws:states:::aws-sdk:rds:describeDBClusters",
      "Next": "Is stopped DB cluster"
    },
    "Is stopped DB cluster": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.DbClusters[0].Status",
          "StringEquals": "stopped",
          "Next": "Success"
        },
        {
          "Variable": "$.DbClusters[0].Status",
          "StringEquals": "stopping",
          "Next": "Wait 60 sec for \"StopDBCluster\""
        }
      ],
      "Default": "Failed stop DB cluster"
    },
    "Failed start backup job for db cluster": {
      "Type": "Fail"
    },
    "Success": {
      "Type": "Succeed"
    },
    "Failed stop DB cluster": {
      "Type": "Fail"
    },
    "Faild stop httpd": {
      "Type": "Fail"
    },
    "Failed describe httpd status": {
      "Type": "Fail"
    }
  }
}

最後にステートマシンの設定です。

ステートマシン名と、事前準備で作成したIAMロールを指定して、ステートマシンの作成をクリックします。

ステートマシンの設定

以上でステートマシンの作成は完了です。

ステートマシンの実行

それでは、作成したステートマシンを実行します。

作成したステートマシンを選択し、実行の開始をクリックします。

ステートマシンの実行

今回は特にステートマシンに入力するJSONは変更しません。そのまま実行の開始をクリックします。

実行の開始

すると、ステートマシンが実行されます。

ステートマシンの実行確認

20分ほど待つと、処理が完了しており、実行ステータスも成功となっていました。

ステートマシンの実行完了確認

それでは、正しくWebシステムが停止できているのかを確認します。

ALBのDNS名で再度ブラウザでアクセスすると、ただいまメンテナンス中ですと正常にメンテナンスページが表示されるようになっています。

メンテナンスページの表示

EC2インスタンスとDBクラスターが停止していることも確認できます。

ステートマシン実行後のEC2インスタンスの状態

ステートマシン実行後のDBクラスターの状態

最後に、AWS Backupで正常にAMI及び、スナップショットが作成されていることも確認します。

バックアップボールトの確認

ステートマシンが意図した通り、動作していることが確認できました。

大 AWS Step Functions 時代が来る予感

AWS Step Functionsの連携可能なAWSサービスが大幅増加したアップデートをお伝えしました。これは大 AWS Step Functions 時代が来る予感を感じずにはいられません。

Lambda関数で何でもかんでもタスクを定義しなくて済むのがかなり嬉しいポイントですね。

個人的にはAWS Step Functionsに、さらに以下の機能が追加されるとかなり大興奮します。

  • Workflow Studio上で編集途中のワークフローの保存
  • 設計したワークフローで使用されているAWSサービスからIAMロールを自動生成
  • ステートマシンの途中からの再実行

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!