5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

以前からLocalStackのPro版を使っていたのですが、忘れっぽいので記事にしたいと思います。今回はDocker上にLocalstack(pro)を立てて、Lambda・SNSを作成し外部端末からLocalstackのSNSトピック宛てメッセージを送ってみたいと思います。Lambda関数は外部メールを送信するようセットしておきます。

<<イメージ図>>
image.png

前提

ホストOS:Ubuntu 22.04.1 LTS
Docker version: 27.0.3, build 7d4bcd8
Docker Compose version: v2.28.1

1. Dockerコンテナ構築

まずは任意のディレクトリを作成し、そこにdocker-compose.ymlを準備します。
※マニュアル記載の内容からアドレスのみ変更(ホストOSのIP)に変更します。

version: "3.8"

services:
  localstack:
    container_name: "${LOCALSTACK_DOCKER_NAME:-localstack-main}"
    image: localstack/localstack-pro  # required for Pro
    ports:
      - "10.x.x.x:4566:4566"            # 自分の環境に合わせる
      - "10.x.x.x:4510-4559:4510-4559"  # 自分の環境に合わせる
      - "10.x.x.x:443:443"              # 自分の環境に合わせる
    environment:
      # Activate LocalStack Pro: https://docs.localstack.cloud/getting-started/auth-token/
      - LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN:?}  # required for Pro
      # LocalStack configuration: https://docs.localstack.cloud/references/configuration/
      - DEBUG=${DEBUG:-0}
      - PERSISTENCE=${PERSISTENCE:-0}
    volumes:
      - "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"

コンテナを起動する前にAuthTokenを確認します。
LocalStack管理画面のWorkspace -> Auth Token から確認できます。
image.png

AuthTokenが確認できたら、以下コマンドでAuthTokenをexportしたのちにコンテナを起動します。

export LOCALSTACK_AUTH_TOKEN="ls-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
docker compose up -d

2. 管理画面からステータスを確認する。

以下、URLにアクセスします。
https://app.localstack.cloud/inst/default/status

画面右上に表示されているEditボタンをクリックして、EndpointのIPをホストOSのIPに変更しておきます。正しく反映されるとステータスがrunningになります。
image.png

3. Lambda関数作成

続いて、LocalstackのコンテナにてLambda関数を登録していきます。コンテナにログインしてコマンドを実行てLambda関数用のコードを作成します。

docker exec -it localstack-main /bin/bash
apt update
apt install vim #ファイル作成の為インストールしておく
vim send-e-mail.py
send-e-mail.py
import json
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import os

def lambda_handler(event, context):
    sns_message = event['Records'][0]['Sns']['Message']

    sender_email = 'xxxxxxxx@example.com'     # 送信アドレス
    recipient_email = 'xxxxxxxx@example.com'  # 宛先アドレス
    smtp_server = 'example.com'               # メールサーバ
    smtp_port = '587'                         # Port番号
    smtp_user = 'xxxxxxxx@example.com'        # ユーザ
    smtp_password = 'XXXXXXXXXX'              # パスワード

    msg = MIMEMultipart()
    msg['From'] = sender_email
    msg['To'] = recipient_email
    msg['Subject'] = 'SNS Notification'
    msg.attach(MIMEText(sns_message, 'plain'))

    try:
        with smtplib.SMTP(smtp_server, smtp_port) as server:
            server.starttls()
            server.login(smtp_user, smtp_password)
            server.sendmail(sender_email, recipient_email, msg.as_string())

        return {
            'statusCode': 200,
            'body': json.dumps('Email sent successfully!')
        }

    except Exception as e:
        return {
            'statusCode': 500,
            'body': json.dumps(f'Failed to send email: {str(e)}')
        }

次にIAMロールの登録に必要なJSONファイルをvimで作成しておきます。

trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

では、以下コマンドを順に実行してIAMロール作成します。

# IAMロールを作成
awslocal iam create-role --role-name lambda-role --assume-role-policy-document file://trust-policy.json

# IAMロールにポリシーをアタッチ
awslocal iam attach-role-policy --role-name lambda-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

# ロールのARNを確認
awslocal iam get-role --role-name lambda-role

作成したロールを使ってLambda関数を登録します。登録する前にコードを圧縮しておいて、圧縮したファイルを登録する形になります。

# 作成したコードを圧縮
zip send-e-mail.zip send-e-mail.py

# Lambda関数を登録
awslocal lambda create-function --function-name send-e-mail --runtime python3.10 --role arn:aws:iam::000000000000:role/lambda-role --handler send-e-mail.lambda_handler --zip-file fileb://send-e-mail.zip

無事作成されるとLocalStack管理画面から状況を確認できます。
image.png

4. SNSトピック作成

次はSNSトピックを作成します。コマンドで作成してもよいのですが、管理画面からも作成できるのでこちらから実施したいと思います。Status画面を開き、SNSをクリックします。
image.png

Create Topicをクリックします。
image.png

SNSトピック名を入れてSubmitボタンをクリックします。
image.png

作成されたトピックをクリックして、Subscriptionsをクリックします。
image.png

Create Subscriptionをクリックします。
image.png

ProtocolにLambdaとして、Endpointには作成されたLambda関数のARNを入れて、画面右したのSubmitをクリックします。
image.png

これで、Lambda関数とSNSトピックが紐づきました。

試しにDockerコンテナから以下のコマンドを実行してLambda関数が実行されるかどうか確認してみましょう

awslocal sns publish --topic-arn arn:aws:sns:us-east-1:000000000000:test --message "Hello, this is a test message"

LocalStack管理画面からCloudWatch Logsを見ると実行結果がわかります。
image.png

5. 外部端末からSNSトピック宛てにアクション

それでは最後に、外部端末からSNSトピック宛てに通信させてみたいと思います。

send-message.py
import boto3
from botocore.config import Config
from botocore.exceptions import NoCredentialsError

# LocalStackエンドポイントを指定
my_config = Config(
    region_name = 'us-east-1',
    signature_version = 'v4',
    retries = {
        'max_attempts': 10,
        'mode': 'standard'
    },
)

# dummy認証情報(これが無いとエラーとなる)
session = boto3.Session(
    aws_access_key_id='dummy',
    aws_secret_access_key='dummy',
    region_name='us-east-1'
)

sns = session.client('sns', endpoint_url='http://10.x.x.x:4566', config=my_config)

topic_arn = 'arn:aws:sns:us-east-1:000000000000:test'

response = sns.publish(
    TopicArn=topic_arn,
    Message='Hello from another Linux OS!',
    Subject='Test Message'
)

print(response)

無事メールが送信されてます。
image.png

SNS/Lambdaなどを使って他システムと連携したりするパターンもあるかと思いますが、Localstackを利用すればある程度の事がローカル環境で実現できるので、非常に便利です。

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?