Vapor Trail

明るく楽しく元気よく

手を動かしながら2週間で学ぶ AWS 基本から応用まで Day12 Day13

Day12 Eメール送受信サービスSESとキューイングサービスSQS

Amazon SES

  1. ドメインを登録する
  2. Route53に紐付ける
  3. メールアドレスを事前登録する
  4. マネージメントコンソールから送信
  5. SDK for PHPでメッセージを送信する

1. ドメインを登録する

Amazon SES→Domains→Verify a New Domain

2. Route 53に紐づけする

Domain:ドメイン名を入力 Generate DKIM Settingsにチェック

Route 53に登録しているドメインなので、Use Route 53→Create Record Sets Route 53のドメインのホストゾーンにレコードが追加される

3. メールアドレスを事前登録する

Amazon SES→Email Addresses→Verify a New Email Address
上限緩和申請をしないと、事前に登録したメールアドレスにしかメールを送信できない。

4. マネージメントコンソールから送信

Domains→Send Test Email

事前登録していないアドレスに送ろうとすると、

Email address is not verified. The following identities failed the check in region US-EAST-1

と出る。

5. SDK for PHPでメッセージを送信する

batchインスタンスに接続

<?php
require '../vendor/autoload.php';

use Aws\Ses\SesClient;

// バージニア北部リージョン以外を利用している場合は、region を変更すること
$ses = SesClient::factory(array(
  'version'=> 'latest',
  'region' => 'us-east-1',
));

try {
  $result = $ses->sendEmail([
    // TODO: 送信元メールアドレスの入力
    'Source' => '***@***.***',
    'Destination' => [
      'ToAddresses' => [
        // TODO: 送信先メールアドレスの入力
        '***@***.***',
      ],
    ],
    'Message' => [
      'Subject' => [
        'Charset' => 'UTF-8',
        'Data' => 'Hello SES World!!',
      ],
      'Body' => [
        'Text' => [
          'Charset' => 'UTF-8',
          'Data' => 'AWS SDK for PHP を使った SES 送信テストです。',
        ],
      ],
    ],
  ]);

  $messageId = $result->get('MessageId');
  echo("Email sent! Message ID: $messageId"."\n");

} catch (SesException $error) {
  echo("The email was not sent. Error message: ".$error->getAwsErrorMessage()."\n");
}

> php SendEmail.php
Email sent! Message ID: xxxxxx-xxxxxx-xxxx-xxxxx

[ec2-user@udemy-aws-14days-batch src]$ php SendEmail.php
PHP Fatal error:  Uncaught exception 'Aws\Ses\Exception\SesException' with message 'Error executing "SendEmail" on "https://email.us-east-1.amazonaws.com"; AWS HTTP error: Client error: `POST https://email.us-east-1.amazonaws.com` resulted in a `403 Forbidden` response:
<ErrorResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
  <Error>
    <Type>Sender</Type>
    <Code>AccessDenie (truncated...)
 AccessDenied (client): User ' is not authorized to perform ses:SendEmail' on resource `arn:aws:ses:us-east-1:303167122504:identity/' - <ErrorResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
  <Error>
    <Type>Sender</Type>
    <Code>AccessDenied</Code>
    <Message>User ' is not authorized to perform ses:SendEmail' on resource `'</Message>
  </Error>
  <RequestId>4aa5cba6-21d9-11e9-96 in /home/ec2-user/vendor/aws/aws-sdk-php/src/WrappedHttpHandler.php on line 191

アクセス権限のエラーが出る場合は、Batchに割り当てられているIAMロールにAmazon SESのアクセス権を追加して、ポリシーを一度デタッチして、もう1度アタッチするとメールが送れるようになる。

バウンス処理について

SNSと組み合わせることでメールが正しく送信できたかを取得することができる、

もしメールが送信できなかった場合、該当するメールアドレスを削除することができる

  • バウンスの例

DBから送信先を取得→メール送信→メール送信に失敗→トリガ→DBから送信先のメールアドレスを削除

Amazon SQS

処理の間にQueueを噛ませることで、非同期処理にできる。

1度に複数件のメッセージを登録/取得できる
Long Polling: キューが空の場合はタイム・アウトするまで待ち続ける
Dead Letter Queue: いつまでも残っているメッセージを別のキューに移動する
Delay Queue(Message Timer): 新しいメッセージを指定した時間見えなくする

注意点:
順序は保証されない
同じメッセージを複数回受信する可能性がある(標準キューとFIFOキュー)
aws.amazon.com

1. キューを作成する

Amazon SQS→新しいキューの作成 デフォルトで標準キューで作成する

キューの操作→メッセージの送信 利用可能なメッセージの数が増えている。

キューの操作→メッセージの表示/削除 メッセージのポーリングを開始で受信できる

2. マネジメントコンソールからメッセージを送受信する

メッセージの送信

<?php
require '../vendor/autoload.php';

use Aws\Sqs\SqsClient;
use Aws\Exception\AwsException;

date_default_timezone_set('Asia/Tokyo');

$client = new SqsClient([
    'region' => 'ap-northeast-1',
    'version' => '2012-11-05'
]);

$params = [
    'MessageAttributes' => [
        "Sender" => [
            'DataType' => "String",
            'StringValue' => "AmazonSQS test"
        ]
    ],
    'MessageBody' => date('YmdHis'),
    //TODO: Queue の URL を記載する
    'QueueUrl' => '***'
];

try {
    $result = $client->sendMessage($params);
    var_dump($result);
} catch (AwsException $e) {
    error_log($e->getMessage());
}

作成したキューのURLを入れる。

> php SendQueue.php

object(Aws\Result)#142 (2) {
  ["data":"Aws\Result":private]=>
  array(4) {
    ["MD5OfMessageBody"]=>
    string(32) "xxxx"
    ["MD5OfMessageAttributes"]=>
    string(32) "xxxx"
    ["MessageId"]=>
    string(36) "xxxx"
    ["@metadata"]=>
    array(4) {
      ["statusCode"]=>
      int(200)
      ["effectiveUri"]=>
      string(62) "https://sqs.ap-northeast-1.amazonaws.com/xxxx/キュー名"
      ["headers"]=>
      array(4) {
        ["x-amzn-requestid"]=>
        string(36) "xxxx"
        ["date"]=>
        string(29) "Sun, 27 Jan 2019 06:51:48 GMT"
        ["content-type"]=>
        string(8) "text/xml"
        ["content-length"]=>
        string(3) "459"
      }
      ["transferStats"]=>
      array(1) {
        ["http"]=>
        array(1) {
          [0]=>
          array(0) {
          }
        }
      }
    }
  }
  ["monitoringEvents":"Aws\Result":private]=>
  array(0) {
  }
}

メッセージが送信される。

メッセージの受信

<?php
require '../vendor/autoload.php';

use Aws\Sqs\SqsClient;
use Aws\Exception\AwsException;

//TODO: Queue の URL を記載する
$queueUrl = "****";

$client = new SqsClient([
    'region' => 'ap-northeast-1',
    'version' => '2012-11-05'
]);

try {
    $result = $client->receiveMessage(array(
        'AttributeNames' => ['SentTimestamp'],
        'MaxNumberOfMessages' => 1,
        'MessageAttributeNames' => ['All'],
        'QueueUrl' => $queueUrl, // REQUIRED
        'WaitTimeSeconds' => 0,
    ));
    if (count($result->get('Messages')) > 0) {
        var_dump($result->get('Messages')[0]);
        $result = $client->deleteMessage([
            'QueueUrl' => $queueUrl, // REQUIRED
            'ReceiptHandle' => $result->get('Messages')[0]['ReceiptHandle'] // REQUIRED
        ]);
    } else {
        echo "No messages in queue. \n";
    }
} catch (AwsException $e) {
    // output error message if fails
    error_log($e->getMessage());
}
> php ReceiveQueue.php

array(7) {
  ["MessageId"]=>
  string(36) "xxxx"
  ["ReceiptHandle"]=>
  string(412) "xxxx"
  ["MD5OfBody"]=>
  string(32) "xxxx"
  ["Body"]=>
  string(14) "20190127155425"
  ["Attributes"]=>
  array(1) {
    ["SentTimestamp"]=>
    string(13) "1548572065941"
  }
  ["MD5OfMessageAttributes"]=>
  string(32) "xxxx"
  ["MessageAttributes"]=>
  array(1) {
    ["Sender"]=>
    array(2) {
      ["StringValue"]=>
      string(20) "Amazon SQS Send Test"
      ["DataType"]=>
      string(6) "String"
    }
  }
}

Day13 アプリケーション開発を支援するCodeシリーズ

f:id:kyamashiro:20190127222141p:plain

CodeCommit

Gitリポジトリをホストする

> mkdir work
> cp -r udemy-14days-aws/Day13/* work/

IAMユーザの権限を使ってgitの設定をするので一応、aws configureで権限を確認する。

gitの設定

git config --global credential.helper '!aws --region ap-northeast-1 codecommit credential-helper $@'
git config --global credential.UseHttpPath true

git config --global user.email "user_email"
git config --global user.name "user_name"

git clone

git init
git remote add origin 作成したリポジトリのURL
// ステージに追加
git add -A
// コミット
git commit -m "first commit"
// プッシュ
git push origin master

CodeBuild

CodeBuild上で行う作業については、buildspec.ymlに定義する

1. Build後のファイルを格納するためのS3を作成する

バケットを作成、バージョニングを有効にする

2. buildspec.ymlの編集

アプリケーション名・作ったS3のバケット名を入力。

version: 0.1

phases:
  build:
    commands:
      - aws deploy push --region ap-northeast-1 --application-name application-name --s3-location s3://S3-bucket-name/sample.zip --source src
artifacts:
  files:
    - '**/*'
  base-directory: src
  name: sample.zip

3. CodeBuildの作成

CodeBuild→ビルドプロジェクトを作成する プロジェクト名: buildspec.ymlで設定したアプリケーション名

ビルドプロジェクトを作成する

  • CodeBuildで作成したIAMロールの設定
    ポリシーをアタッチする
    AWSCodeDeployDeployerAccess
    AmazonS3FullAccess

CodeDeploy

  • EC2インスタンス用のIAMロールを作成する ロールの作成→EC2
    S3のアクセス権を設定
    Web-1a, Web-1cに作成したDeploy用のロールを割り当て

  • 各EC2インスタンスにCodeDeployエージェントをインストール

wget https://aws-codedeploy-ap-northeast-1.s3.amazonaws.com/latest/install
chmod +x install
sudo ./install auto

CodeDeploy→アプリケーションの作成 アプリケーション名: buildspec.ymlのアプリケーション名 コンピューティングプラットフォーム: EC2/オンプレミス

  • デプロイタイプの設定 アプリケーション→デプロイグループの作成 デプロイタイプ:インプレース

  • 環境設定 EC2インスタンス Web-1aとWeb-1cを登録

  • ロードバランサー ロードバランシングを有効にするにチェック 片方のEC2インスタンスがデプロイ中は切り離して、終わるともう片方のインスタンスをデプロイするという処理にできる

実際にビルドしてデプロイする

batchインスタンスに接続

cd work
git status
modified buildspec.yml
git add -A
git commit -m 'update buildspec.yml'
git push origin master
  • ビルド CodeBuild→ビルド→ビルドプロジェクト→ビルドの開始

  • デプロイ CodeDeploy→デプロイ→アプリケーション→デプロイの作成 デプロイグループ・リビジョンの場所を選択→デプロイ

デプロイ→イベント

BlockTraffic 5 分 45 秒

EC2のターゲットグループの登録解除の遅延を300秒から短くすると、デプロイにかかる時間が短くなる

CodePipeline

パイプラインの作成

  • パイプライン設定の選択
    サービスロール:新しいサービスロール
    アーティファクトストア:カスタムの場所 デプロイ用のバケットを選択

  • ソースステージの追加
    ソースプロバイダ:AWS CodeCommit
    変更検出オプション: AWS CodePipeline

  • ビルドステージの追加
    ビルドプロバイダ: AWS CodeBuild
    プロジェクト名を選択:ビルドプロジェクト名を選択

  • デプロイステージの追加
    デプロイプロバイダ: AWS CodeDeploy
    アプリケーション名:
    デプロイグループの選択

パイプラインの作成
f:id:kyamashiro:20190127222146p:plain git pushすると自動でデプロイされるようになる!