はじめに
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の場合と異なるので注意が必要です。)
// ...
$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を作成します。
<?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ファイルを作成します。
DYNAMODB_CONNECTION=local
DYNAMODB_LOCAL_ENDPOINT=http://localhost:4569
LocalStackを使ってDynamoDBをエミュレートしていることを前提としています。
利用するポートは4569
です。
DYNAMODB_CONNECTION=aws_iam_role
DYNAMODB_REGION=ap-northeast-1
dev,test,prod環境全てでIAMを使って認証させています。
IAMを使うと認証情報をソースコードに記述する必要がないので良いです。
Modelの作成例
DynamoDbModelクラスを継承したModelクラスを作成します。
/**
* 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に下記を追記します。
// ...
// Load sns config file
$app->configure('sns');
// ...
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ファイル
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
です。
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は各環境で変更。
メール送信の実装例
<?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を使ったインフラ構築の記事を書きます。