🎃

Amazon SNSを用いたEC2上のVirtuosoの再起動

2023/11/24に公開

概要

以下の記事で、ヘルスチェックを行う方法について記述しました。

https://zenn.dev/nakamura196/articles/28151132308b55

また、Virtuosoが停止した際の再起動のためのコマンドを以下に記述しました。

https://zenn.dev/nakamura196/articles/a9fd176d3ac9e8

今回は、Amazon SNSを用いた通知に合わせて、Virtuosoを再起動してみます。

方法

EC2インスタンスにsudo rm -rf /usr/local/var/lib/virtuoso/db/virtuoso.lck && ...のようなコマンドを送信するには、SSM(AWS Systems Manager)に関する設定が必要でした。

IAMロールとポリシー

IAMロールを新規に作成して、AmazonSSMFullAccessというポリシーを許可しました。はじめ、AmazonSSMManagedInstanceCoreというポリシーを許可していましたが、後述するlambda実行時に以下のようなエラーが発生して、うまく動作させることができませんでした。

An error occurred (InvalidInstanceId) when calling the SendCommand operation: Instances [[i-xxxxxx]] not in a valid state for account xxxxxx

EC2インスタンスの「IAMロールを変更」から、作成したIAMロールを選択して更新しました。

AWS SAM: lamda関数の作成

AWS SAMを用いました。以下でのプロジェクトを作成します。

sam init

hello_world/app.pyを以下のように作成しました。instance_idの部分には、要修正です。

hello_world/app.py
import boto3
import time

def lambda_handler(event, context):
    # EC2クライアントの初期化
    ec2 = boto3.client('ec2')
    
    # 特定のEC2インスタンスIDを指定
    instance_id = 'i-xxxxxxxx'

    # EC2インスタンスのステータスチェック
    response = ec2.describe_instance_status(InstanceIds=[instance_id])
    if len(response['InstanceStatuses']) == 0:
        print(f"インスタンス {instance_id} は停止中です。")
        return

    # Define the command to be executed on the instance (e.g., restart software)
    command = 'sudo rm -rf /usr/local/var/lib/virtuoso/db/virtuoso.lck && sudo /usr/local/bin/virtuoso-t +configfile /usr/local/var/lib/virtuoso/db/virtuoso.ini'

    # SSMを通じてEC2インスタンスにコマンドを送信
    ssm_client = boto3.client('ssm')
    response = ssm_client.send_command(
        InstanceIds=[instance_id],
        DocumentName='AWS-RunShellScript',
        Parameters={'commands': [command]}
    )
    
    time.sleep(1.0)

    command_id = response['Command']['CommandId']
    output = ssm_client.get_command_invocation(
        CommandId=command_id,
        InstanceId=instance_id,
    )

    print("コマンドを実行しました。")

    # Extract only the necessary information from the output
    simplified_response = {
        "Output": output['StandardOutputContent'],
        "Error": output['StandardErrorContent'],
    }

    return simplified_response

また、hello_word/requirements.txtにboto3を追記しました。

hello_word/requirements.txt
boto3

ローカルでのテストは以下で行います。デフォルト以外のprofileを使用する場合には、xxxxに適切なプロファイル名を与えます。

sam build && sam local invoke --profile xxxx

AWS SAM: template.yamlの更新

SNSの通知に合わせて、lambda関数が実行されるように、template.yamlを修正します。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  cj-virtuoso-restart

  Sample SAM Template for restarting Virtuoso instances

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 15
    MemorySize: 128

Resources:
  VirtuosoRestarter:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: virtuoso_restart/
      Handler: app.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      # This property associates this Lambda function with the SNS topic defined above, so that whenever the topic
      # receives a message, the Lambda function is invoked
      Events:
        MySNSTrigger:
          Type: SNS
          Properties:
            Topic: arn:aws:sns:us-east-1:xxxxx:xxxxx  # 既存のSNSトピックのARN

Outputs:
  VirtuosoRestarter:
    Description: "Virtuoso Restarter Lambda Function ARN"
    Value: !GetAtt VirtuosoRestarter.Arn
  VirtuosoRestarterIamRole:
    Description: "Implicit IAM Role created for Virtuoso Restarter function"
    Value: !GetAtt VirtuosoRestarterRole.Arn

「既存のSNSトピックのARN」は適切なものに修正してください。また、先に示したlambda関数を格納するフォルダ名をhello_wordからvirtuoso_restartに変更しています。

AWS SAM: デプロイ

デプロイは以下で行います。

sam build && sam deploy --profile xxxx

まとめ

SSM(AWS Systems Manager)の利用が初めてだったので、エラーを解消させるまで時間がかかりましたが、便利な機能だと思いました。

他の方の参考になりましたら幸いです。

Discussion