LoginSignup
5
3

More than 5 years have passed since last update.

Lumenを導入したEC2とDynamoDBとSNS

Last updated at Posted at 2019-02-08

はじめに

EC2にLumenを導入し、小さなwebアプリケーションを作成する機会がありました。
要件を満たすために、新たに作成するDBとのI/Oとメール送信を実装する必要があり、
DynamoDBとSimple Notification Service(SNS)を利用したので、その時に得た知見をまとめます。

  • 触れる内容
    • LumenでDynamoDBとSNSを利用する方法
  • 触れない内容
    • Lumenの導入と設定
    • webアプリケーションのインフラの設定、ミドルウェアのインストール
    • ローカル環境の構築方法

各種バージョン

  • PHP 7.2.10
  • Lumen 5.7.7
  • aws/aws-sdk-php 3.82.0
  • laravel-dynamodb 4.11.2

LumenとDynamoDB

laravel-dynamodb導入

ORMを使うためのライブラリlaravel-dynamodbを導入します。
まずはcomposerでインストールします。
composer require baopham/dynamodb
そしてbootstrap/app.phpに下記を追記します。
(この手順はLaravelの場合と異なるので注意が必要です。)

bootstrap/app.php
// ...

$app = new Laravel\Lumen\Application(
    dirname(__DIR__)
);

$app->withFacades();

// Load dynamodb config file
$app->configure('dynamodb');

$app->withEloquent();

// ...

$app->register(BaoPham\DynamoDb\DynamoDbServiceProvider::class);

認証

config/dynamodb.phpを作成します。

config/dynamodb.php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Default DynamoDb Connection Name
    |--------------------------------------------------------------------------
    |
    | Here you may specify which of the DynamoDb connections below you wish
    | to use as your default connection for all DynamoDb work.
    */

    'default' => env('DYNAMODB_CONNECTION', 'local'),

    /*
    |--------------------------------------------------------------------------
    | DynamoDb Connections
    |--------------------------------------------------------------------------
    |
    | Here are each of the DynamoDb connections setup for your application.
    |
    | Most of the connection's config will be fed directly to AwsClient
    | constructor http://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.AwsClient.html#___construct
    */

    'connections' => [
        'aws' => [
            'credentials' => [
                'key' => env('DYNAMODB_KEY'),
                'secret' => env('DYNAMODB_SECRET'),
                // If using as an assumed IAM role, you can also use the `token` parameter
                'token' => env('AWS_SESSION_TOKEN'),
            ],
            'region' => env('DYNAMODB_REGION'),
            // if true, it will use Laravel Log.
            // For advanced options, see http://docs.aws.amazon.com/aws-sdk-php/v3/guide/guide/configuration.html
            'debug' => env('DYNAMODB_DEBUG'),
        ],
        'aws_iam_role' => [
            'region' => env('DYNAMODB_REGION'),
            'debug' => true,
        ],
        'local' => [
            'credentials' => [
                'key' => 'key',
                'secret' => 'secret',
            ],
            'region' => 'region',
            // see http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Tools.DynamoDBLocal.html
            'endpoint' => env('DYNAMODB_LOCAL_ENDPOINT'),
            'debug' => true,
        ],
        'test' => [
            'credentials' => [
                'key' => 'key',
                'secret' => 'secret',
            ],
            'region' => 'region',
            'endpoint' => env('DYNAMODB_LOCAL_ENDPOINT'),
            'debug' => true,
        ],
    ],
];

今回はlocal環境とdev環境とtest環境とprod環境の4つの環境を準備する必要があったので、
それぞれのenvファイルを作成します。

.env.local
DYNAMODB_CONNECTION=local
DYNAMODB_LOCAL_ENDPOINT=http://localhost:4569

LocalStackを使ってDynamoDBをエミュレートしていることを前提としています。
利用するポートは4569です。

.env.dev、.env.test、.env.prod
DYNAMODB_CONNECTION=aws_iam_role
DYNAMODB_REGION=ap-northeast-1

dev,test,prod環境全てでIAMを使って認証させています。
IAMを使うと認証情報をソースコードに記述する必要がないので良いです。

Modelの作成例

DynamoDbModelクラスを継承したModelクラスを作成します。

Text.php
/**
 * textテーブルの操作
 *
 * Class Text
 * @package App\Model
 */
class Text extends DynamoDbModel
{
    /**
     * @var string テーブル名
     */
    protected $table = 'text';

    /**
     * @var string Hash Key
     */
    protected $primaryKey = 'text_id';

    /**
     * @var array カラム一覧
     */
    protected $fillable = [
        'text_id',
        'title',
        'created_user',
        'created_at',
    ];
}

利用してみた感想

今回はsave()とall()を使いました。特に問題はなかったです。
ただ、RDBではないDBに対してEloquent ORMを利用するのはどうなのだろうと思ってしまいます。
ライブラリの中身を詳しく読んでいないので、互換性の取り方まで把握していません。
気になる方はライブラリを読んでください。

LumenとSNS

Simple Email Service(SES)を用いてメール送信する方法が最適だと考えました。
しかし、今回は色々事情があり東京リージョンを使う必要があり、SESには東京リージョンがないため使えませんでした。(2019-02-09)
よってSNSでメール送信しています。

PHPでSNSに特化したライブラリはなく、AWS SDKを使って実装します。

設定

bootstrap/app.phpに下記を追記します。

bootstrap/app.php
// ...

// Load sns config file
$app->configure('sns');

// ...

config/sns.phpを作成します。

config/sns.php
<?php

return [

    'default' => env('SNS_CONNECTION', 'dev'),

    'connections' => [
        'prod' => [
            'topic_arn' => env('SNS_TOPIC_ARN'),
            'options' => [
                'version' => env('SNS_VERSION'),
                'region' => env('SNS_REGION'),
            ]
        ],
        'test' => [
            'topic_arn' => env('SNS_TOPIC_ARN'),
            'options' => [
                'version' => env('SNS_VERSION'),
                'region' => env('SNS_REGION'),
            ]
        ],
        'dev' => [
            'topic_arn' => env('SNS_TOPIC_ARN'),
            'options' => [
                'version' => env('SNS_VERSION'),
                'region' => env('SNS_REGION'),
            ]
        ],
        'local' => [
            'topic_arn' => env('SNS_TOPIC_ARN'),
            'options' => [
                'version' => env('SNS_VERSION'),
                'region' => env('SNS_REGION'),
                'credentials' => [
                    'key' => 'key',
                    'secret' => 'secret',
                ],
                'endpoint' => env('SNS_LOCAL_ENDPOINT'),
            ]
        ]
    ],
];

envファイル

.env.local
SNS_CONNECTION=local
SNS_VERSION=latest
SNS_LOCAL_ENDPOINT=http://localhost:4575
SNS_TOPIC_ARN=arn:aws:sns:ap-northeast-1:hoge:local
SNS_REGION=ap-northeast-1

LocalStackを使ってSNSをエミュレートしていることを前提としています。
ローカルで作成済みのトピックのARNをSNS_TOPIC_ARNに記載します。
利用するポートは4575です。

.env.dev、.env.test、.env.prod
SNS_CONNECTION=dev // test or prod
SNS_VERSION=latest
SNS_TOPIC_ARN=arn:aws:sns:ap-northeast-1:hoge:topic
SNS_REGION=ap-northeast-1

クラウド上で作成済みのトピックのARNをSNS_TOPIC_ARNに記載します。
SNS_CONNECTIONは各環境で変更。

メール送信の実装例

SnsMail.php
<?php
/**
 * SNSによるメール送信するためのclass
 *
 * Class SnsMail
 * @package App\Library
 */
class SnsMail
{
    /**
     * @var string AWSの環境
     */
    private $connection;

    /**
     * @var string SNSのtopic
     */
    private $topicArn;

    /**
     * @var SnsClient SNSのクライアント
     */
    private $snsClient;

    /**
     * SnsMail constructor.
     */
    public function __construct()
    {
        $connection = Config::get('sns.default');
        $this->connection = $connection;
        $this->topicArn = Config::get("sns.connections.{$connection}.topic_arn");
        $this->snsClient = new SnsClient(Config::get("sns.connections.{$connection}.options"));
    }

    /**
     * SNSを用いたメール送信
     *
     * @param string $subject
     * @param string $message
     * @return void
     */
    public function publish(string $subject, string $message): void
    {
        $subject = "{$subject}{$this->connection}環境)";
        $this->snsClient->publish([
            'TopicArn' => $this->topicArn,
            'Subject'  => $subject,
            'Message'  => $message,
        ]);
    }
}

利用してみた感想

トピック作成時に飛ぶ承認メールのConfirm subscriptionのリンクを踏まないとメールは飛びません...
このリンクを踏む作業を忘れていて、1時間とられましたw

最後に

気が向いた時にLocalStackを使ったローカル環境の構築とCloudFormationを使ったインフラ構築の記事を書きます。

5
3
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
3