はじめに
前回はStep FunctionsとChange Calendarを使った停止起動判定とEC2、ECS、RDSの停止処理で実装した処理の詳細を説明しました。
今回は起動処理で実装した処理の詳細を説明していこうと思います。
起動時の処理
起動時の処理のフローも大まかな流れは停止時のフローと同じですが、RDSを先に起動させてからEC2、ECSを起動するようにしている点が停止時の処理と異なります。
これは、EC2、ECSからRDS(DB)にアクセスできないとEC2、ECS上で動かしているサービスが起動できなかったりする場合があり、また、そもそもRDSの起動にはかなり時間がかかることから、先にEC2やECSを立ち上げたとしてもDBを使用できない期間が長くなるため、先にRDSが起動しきってからEC2、ECSを起動するようにしています。
なお、今回は前回の停止時の処理とかぶる部分も多いことから、要点を絞って起動時のフローを説明するため前回の記事も合わせてご確認ください。
RDSの起動処理
RDSを起動する際のフローの内容は以下となります。
二段のループになっており複雑ですが、順を追って説明します。
最初の「RDS起動処理ループ」ではRDSクラスタの起動処理を行い、2つ目の「RDS起動判定処理ループ」ではRDSの起動が完了したかを確認するため、一定時間待機しつつ起動を待つ処理となります。
起動するだけであれば最初のループで完了しますが、前述の通り、RDSの起動には時間がかかり、起動しきらないとEC2、ECSからの接続に支障が出る可能性があることから、2つ目のループでRDSの起動完了を待った上でEC2、ECSの起動処理を行うようにしております。
RDSの存在確認
前回の停止時の処理でも行っていた通り、そもそもStep Functionsを実行するアカウントにRDSが存在しない場合、エラーとなってしまうため、「RDS: DescribeDBClusters」アクションを実行して、「出力」で停止時と同様、以下の三項演算子でRDSが存在していれば結果を格納、RDSが存在していなければnull
を格納するようにしています。
{% $states.result.DbClusters[] ? $states.result.DbClusters[].DbClusterArn : null %}
上記の結果を用いたChoiseフローによる「RDS存在判定(起動)」では、$states.input
で先ほど実行した前ステップの結果を読み出し、null
の場合はEC2、ECS起動処理に進み、それ以外はRDS起動処理を実行するように条件判定します。
{% $type($states.input) = "null" %}
RDS起動処理と起動対象一覧判定
起動処理の中身は停止時とほとんど変わりがなく、「RDS起動前判定」後の処理が停止時では「RDS: StopDBCluster」アクションとなりましたが、起動時では「RDS: StartDBCluster」になるだけとなりますので、詳しくは前回の記事を参照してください。
起動処理後、「RDS起動判定処理ループ」に移る前に、「RDS: DescribeDBClusters」アクションを実行し、「出力」で以下のような三項演算子を使用して、StartStopSFN
タグが付与されていないRDSが存在するかを判定しております。
{% $states.result.DbClusters[(TagList[Key="StartStopSFN" and Value!="disable"]) or ($exists(TagList[Key="StartStopSFN"]) = false)] ? $states.result.DbClusters[(TagList[Key="StartStopSFN" and Value!="disable"]) or ($exists(TagList[Key="StartStopSFN"]) = false)].DbClusterArn[] : null %}
次の起動判定ループで使用するリストを取得するのが目的となりますが、単純にアカウントに存在する一覧を取得しただけではStartStopSFN
タグが付与されている対象も入ってしまうことから、上記のような複雑な式で判定するようにしております。
以下、先程の三項演算子を分解して見ていこうと思います。(見やすいように改行等加えています)
$states.result.DbClusters[
(TagList[Key="StartStopSFN" and Value!="disable"]) or
($exists(TagList[Key="StartStopSFN"]) = false)
]
上記は三項演算子の条件式部分を抜粋したものとなりますが、StartStopSFN
のタグが存在していて値がdisable
以外の場合、またはそもそもStartStopSFN
タグが付与されていないRDSクラスタの一覧が存在するかを判定しています。
これは停止起動処理の対象から外す条件として、タグのキーがStartStopSFN
、タグの値がdisable
の場合に対象から外すようにしていることから、条件式の最初の部分で取得しており、そもそもタグが付与されていない対象を洗い出すため、$exists
関数でそもそもStartStopSFN
タグが付与されていない対象を取得するようにしております。
上記の条件式に合致する際、RDSクラスタのARNを格納し、合致するRDSクラスタが存在しない場合はnull
を格納したいことから、以下のような記載としました。
$states.result.DbClusters[
(TagList[Key="StartStopSFN" and Value!="disable"]) or
($exists(TagList[Key="StartStopSFN"]) = false)].DbClusterArn[]
: null
結果がnull
の場合はそもそもRDSの起動を待つ対象が存在しないため「RDS起動対象一覧判定」のChoiceフローでは先程の「RDS起動対象一覧判定」と同じく、null
の場合はEC2、ECS起動処理に進み、それ以外はRDS起動判定処理を実行するように条件判定します。
{% $type($states.input) = "null" %}
RDS起動判定処理
RDS起動処理と起動対象一覧判定でRDSクラスタの起動は開始されましたが、起動完了するまで時間がかかるため、起動が完了するまで待機します。
待つだけなので「Wait」フローで起動完了するまでの大体の時間を設定するだけでも良いのですが、RDSのスペックなどにより時間がまちまちなので、定期的にRDSクラスタの状態を確認して判定を行います。
「RDS起動判定処理ループ」の最初のステップでは、「Pass」フローを使用して、現在ループ内で指定されているRDSクラスタARNを以下のように変数に格納しております。
{
"rdsCluster": "{% $states.input %}"
}
次の「RDS起動状態確認」では、現在のRDSクラスタの状態を確認するため、「RDS: DescribeDBClusters」で指定のARNのRDSクラスタ状態を取得し、「変数」で以下を指定することでrdsStatusCheck
という変数にRDSクラスタ状態値を格納しております。
{
"rdsStatusCheck": "{% $single($states.result.DbClusters[].Status) %}"
}
RDSクラスタが起動状態となると、ステータスがavailable
となることから、次の判定を行うことで、available
以外の場合は指定時間(今回は5分)待機し、再度同じ確認処理を実行するようにしております。
{% $not(($rdsStatusCheck) = ("available")) %}
EC2、ECSの起動処理
EC2、ECSは「Parallel」フローで並行実行するだけなので、停止処理が起動処理に変わるだけで停止時のフローと変わりません。
そのため、EC2、ECSの起動処理の詳細についての説明は省きますので、詳細は前回の記事をご確認ください。
おわりに
4回にわたりStep Functions、JSONataの基礎と停止起動処理の内容について説明してきました。
JSONataは文字列変換や検索用関数の種類もJSONPathと比べて多く、書式も分かりやすく扱いやすいためStep Functionsワークフローを作成するのが楽しくなりました。
また、Step Functionsのみで実行できることが増えたことで、今までJSONPathではどうしても実現できず、Lambdaを介して行っていたような処理も、Lambdaを使わずに済んだり、Lambdaを使用している場合に頭を悩ませるLambdaランタイムバージョンのサポート期限も気にしなくて良くなるのは個人的にありがたいです。