LambdaでNeptuneを停止する方法

2020.10.20

こんにちは、ドイツのモナでございます〜

RDSと同じく、Amazon Neptuneは停止しても7日間が経ったら自動的に起動してしまうサービスです。なお、Neptuneの料金がそこそこ高いため、利用しない間はなるべく停止した状態が望ましいですね。もちろんスナップショットを作成し、以前使っていたDBを復元するといった手もありますが、今回はLambdaを使って、勝手に起動してしまったNeptuneのクラスターを停止する方法を紹介したいと思います。

準備

IAMポリシーとロールの作成

まず、権限系の準備が必要なのでIAMポリシーとロールを作りましょう。ここの注意ポイントは、サービスとして neptuneではなく、 RDSを選択する必要があります。

AWSサービスからIAMを選んで、ポリシーを作成をクリック

JSONタブをクリック、以下をコピペでも入力(ビジュアルエディタでもOK)

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "rds:StartDBCluster",
                "rds:StopDBCluster",
                "rds:DescribeDBClusters",
                "logs:CreateLogStream",
                "logs:CreateLogGroup",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}

ハイライトされている行が特に大事です。これがないと、Neptuneを停止することができません。 なお、"rds:StartDBCluster" は今回は実は必要ないですが、停止だけでなくて、停止開始スケジューリングには便利なので入れておきました。

確認画面がこんな感じになっていればOKです!

作成したポリシーを使ってNeptuneを停止権限のあるロールも作りましょう。

先ほど作成したロールをアタッチ

確認、作成

 これで準備が完了です〜

Lambda関数

本番としていよいよLambda関数の作成ですね。

まず、AWSサービスからLambdaを選択し、「関数の作成」をクリック

今回は一から作成します。ランタイムとしてPythonを使っていますが、お好みの言語でもできるはずです。

作成後の詳細設定は初期のままでも大丈夫ですが、念のためメモリを512MB、タイムアウトを15秒にしました。

なお、関数はこれだけのコードで動きます!

import os
import botocore
import boto3
from botocore.exceptions import ClientError

def lambda_handler(event, context):
   neptune = boto3.client('neptune')
   lambdaFunc = boto3.client('lambda')
   
   print('Getting Environment variable')
   try:
       cluster = os.environ['ClusterIdentifier']
       print("Stopping Neptune cluster: " + cluster)
       
   except ClientError as e:
       print("Couldn't get environment variable")
       raise e
       return {"message" : "Couldn't get environment variable"}
       
   try:
       response = neptune.stop_db_cluster(DBClusterIdentifier=cluster)
       print("Cluster stopped")
   except ClientError as e:
       if e.response['Error']['Code'] == 'InvalidDBClusterStateFault':
           print("Neptune cluster already in a stopped state.")
       else:
           raise e
   
   return {"message" : "Script execution completed. See Cloudwatch logs for complete output"}

停止したいNeptuneのクラスターを指定するのに関数の環境変数を設定しましょう。 直接関数に書いてしまってもいいのですが、環境変数の方が柔軟なので個人的にその方が好きです。

まずはクラスターIDをNeptune画面から確認

次にLambdaの環境変数を更新

これでLambda関数を使ってNeptuneを停止することができます!

ただし、まだ勝手に実行されるわけではないので、最後にLambda画面からトリガーを追加しましょう。

私は単純なcronジョブを使っていますが、ユースケースに合わせて適切なトリガーを設定することで停止の自動化が完了となります〜

まとめ・ポイント

  • Neptuneは料金の高いサービスなので利用しない間に停止することをおすすめします。Neptuneサービスにおける自動開始をLambdaを使って押さえましょう。
  • クラスターのAPI操作としては neptune.stop_db_clusterを利用します。
  • IAMポリシーとしてはneptune:*ではなく、 rds:*を指定する必要があります。 ← ここが一番ハマりやすいポイントだと思います!