0
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?

AppRunner上のLaravelアプリからDynamoに接続する

Posted at

前提

  • AppRuunerでLaravelのアプリを既にデプロイしている
  • VPC ConnectorでVPCに接続している
  • 追加要件としてDynamoを使う

LaravelアプリでのDynamoへの接続設定

baopham/laravel-dynamodbを利用する。
Dynamoのデータ操作をEloquentライクでできるようになるライブラリ。

インストール方法
composer require baopham/dynamodb
php artisan vendor:publish --provider 'BaoPham\DynamoDb\DynamoDbServiceProvider'
# config/dynamodb.phpが作成されます。

詳細な使い方はREAD.MEを参照。
Eloquentを継承しているので、基本的にはDynamoの検索方法(PK、SK、GSI)さえ押さえればEloquentモデルを使うように使えると思う。

ローカル環境での接続

Dockerでローカル環境構築していることを前提とする。
ローカル用には以下のDynamoDB Localを使う。

また、データ確認用のGUIツールも用意する。

それぞれをcompose.ymlに記載する。

compose.yml
dynamodb:
  image: amazon/dynamodb-local
  ports:
    - "8000:8000"
  volumes:
    - "./infra/docker/dynamodb/data:/data"
  command: ["-jar", "DynamoDBLocal.jar", "-sharedDb", "-dbPath", "/data"]
  
dynamodb-admin:
  image: aaronshaf/dynamodb-admin
  ports:
    - "8001:8001"
  environment:
    - DYNAMO_ENDPOINT=http://dynamodb:8000
  depends_on:
    - dynamodb

ローカル環境での認証設定

baopham/dynamodbを使う場合でも、Dynamoへの接続はAWSのSDKを使っている。
SDKを使ってAWSのリソースに接続する場合は認証情報の設定が必要になるが、ローカル環境の場合は環境変数にDYNAMODB_CONNECTION=localDYNAMODB_LOCA L_ENDPOINT=http://dynamodb:8000を設定すれば、上記で作成したローカルのコンテナに接続可能。

ローカル環境でのテーブル作成

DynamoDB Adminで直接作成してもいいが、今回はマイグレーションコマンドを作成する。実際のAWSで構築するときはCDKなどで定義したほうがいいと思う。

サンプルコード
DynamoMigrateCommand.php
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use BaoPham\DynamoDb\DynamoDbClientService;

final class DynamoMigrateCommand extends Command
{
    protected $signature = 'dynamo:migrate';
    protected $description = 'DynamoDBのテーブルを作成します。';

    public function handle()
    {
        $this->info('DynamoDBのテーブルを作成します。');

        if (!app()->environment('local')) {
            $this->error('このコマンドはローカル環境でのみ実行可能です。');
            return;
        }

        try {
            $this->createTable();
            $this->info('✅ テーブルが作成処理が完了しました。');
        } catch (\Exception $e) {
            $this->error('❌ テーブルの作成に失敗しました: ' . $e->getMessage());
        }
    }

    private function createTable()
    {
        $client = resolve(DynamoDbClientService::class)->getClient();

        $tableName = 'test-table-local';

        // 既にテーブルが存在するか確認
        $tables = $client->listTables();
        if (in_array($tableName, $tables['TableNames'])) {
            $this->warn("⚠️ テーブル '{$tableName}' はすでに存在します。スキップします。");
            return;
        }

        $params = [
            'TableName' => $tableName,
            'KeySchema' => [
                ['AttributeName' => 'PK', 'KeyType' => 'HASH'],
                ['AttributeName' => 'SK', 'KeyType' => 'RANGE'],
            ],
            'AttributeDefinitions' => [
                ['AttributeName' => 'PK', 'AttributeType' => 'S'],
                ['AttributeName' => 'SK', 'AttributeType' => 'S'],
            ],
            'BillingMode' => 'PAY_PER_REQUEST',
        ];

        $client->createTable($params);
    }
}

あとはModelを定義して、通常のEloquentを使うようにデータの操作が可能になる。

AWS環境での接続

1. 接続用の環境変数設定

アプリの環境変数にDYNAMODB_CONNECTION=aws_iam_roleを設定する。
この設定で、アクセスキーやシークレットを利用せずに、AppRunnerのサービスロールを使ってDynamoに接続可能。

2. AppRuunerのサービスロール作成

AppRunnerのサービス用のロールを作成する(ECR アクセスロールではなく、セキュリティ>インスタンスロールで設定するロール)。
インスタンスロールには、

  • Dynamoへのアクセス許可ポリシー
  • 以下の信頼ポリシー
    を設定する。
信頼ポリシー
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "tasks.apprunner.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

この設定をしないと以下のエラーが発生する。どうやらAWS SDKが見に行く認証用の設定が2種類あり、EC2用のものを参照してしまっているため起きている。以下参考。
https://blog.pinkumohikan.com/entry/could-not-retrieve-credential-when-using-aws-sdk-from-php-app-on-ecs

Error retrieving credentials from the instance profile metadata service. (cURL error 7:  (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for http://169.254.169.254/latest/meta-data/iam/security-credentials/)

3. VPCエンドポイントの設定

既存のVPCにNAT Gatewayが作成されている場合は2までの設定で接続可能。
ただし、コスト面やセキュリティ等を考慮してVPCエンドポイント(Gateway型)を経由して通信させる。

作業としては、Gateway型のDynamo用VPCエンドポイントを作成し、対象のサブネットに割り当てる。
これで設定は完了。

このままだとNAT GatewayかVPCエンドポイントのどちらを経由しているか分からないので、CloudTrailでログを確認してみる。

  • Dynamoのイベントログが設定されていない場合、新規で証跡を作成し、イベントログでDynamoのログを有効化
  • CloudTrailコンソールの「イベント履歴」からは確認できない?ので、出力先のS3バケットにあるファイルを確認。dynamodbでgrepして、ヒットしたレコードのvpcEndpointIdの値が設定したVPCエンドポイントのものになっていれば通信出来ている。
  • 不要であれば作成した証跡は削除しておく。

おわり

以上で通信は可能になったもののベストプラクティスかどうかは不明なので誰かの参考までに。

0
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
0
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?