SES でメール送信時にリジェクトされる

Net::SMTPFatalError: 554 Message rejected: Email address is not verified. The following identities failed the check in region US-EAST-1

ActionMailer で送信した例だが、このようにメール送信がデフォルト状態だと出来ない。

Your Amazon SES account has "sandbox" access in region US East (N. Virginia). With sandbox access you can only send email to the Amazon SES mailbox simulator and to email addresses or domains that you have verified. To be moved out of the sandbox, please request a sending limit increase. Learn more.
Can't find your existing account settings? Your account may be set up in a different AWS region. Try switching regions in the upper right corner of the console.

SESはデフォルトの状態だと、sandboxモードになっており、テスト用の特定アカウントか、登録したメールアドレス、送信元と同じメールアドレスにのみ、送信できるようになっている。

サポートへ問い合わせることで、送信制限と緩和と同時に、sandboxモードが解除され、どのメールへも送れるようになる。

Lambda@Edge を利用し、Cloudfrontに設定ようとしたとき、エラーが表示される

There was an error creating the trigger: Completing this action would cause the maximum number of distributions with Lambda function associations per owner to be exceeded (maximum allowed is 0).

Lambda@Edge は現在プレビュー版となっており、利用する場合は事前に申請の必要があります。
申請は下記のページより

https://pages.awscloud.com/lambda-at-edge-preview.html

AWS SSM で、EC2に任意のコマンドを実行する

ssm は、ssh で接続することなく、 必要な role があれば、特定の EC2 上へコマンドを送ることが出来ます。
Amazon Linux に対しても、実行できます。

EC2の自動セットアップを行いながらも、ssh キーの登録をしたくないようなときに役立ちます。

実行するリモートサーバー側に ssm-agent をインストールする。

cd /tmp
curl https://amazon-ssm-ap-northeast-1.s3.amazonaws.com/latest/linux_amd64/amazon-ssm-agent.rpm -o amazon-ssm-agent.rpm
yum install -y amazon-ssm-agent.rpm

実行するリモートサーバー側に role を設定する。

AmazonEC2RoleForSSM

コマンドを送る元に、role を設定する。

AmazonSSMFullAccess

実行方法

こんな感じ

def command(instance, commands):
  ssm = boto3.client('ssm')
  r = ssm.send_command(
    InstanceIds = [instance.instance_id],
    DocumentName = "AWS-RunShellScript",
    Parameters = {
      "commands": commands
    }
  )
  command_id = r['Command']['CommandId']

  while True:
    time.sleep(0.2)
    res = ssm.list_command_invocations(CommandId=command_id)

    invocations = res['CommandInvocations']
    if len(invocations) <= 0: continue

    status = invocations[0]['Status']
    if status == 'Success': return True
    if status == 'Failed': return False

Rails5 では、production 時、config.autoload_paths が機能しない

こちらに変更点が書かれていますが、

A Guide for Upgrading Ruby on Rails — Ruby on Rails Guides

Autoloadを有効にする

$ vi config/environments/production.rb

config.enable_dependency_loading = true

起動時にロードする

config.eager_load_paths += %(hoge)

どちらかの対応で読まれるようになります。

Twitter Card の申請が通った場合、同一ドメインすべてでTwitterカードが有効になる

https://appspot.info/share/11111

の審査が通った場合、ドメイン単位で承認されるため、ほかのパスも有効になります。

https://appspot.info/hoge/2222

Rails5 ActiveRecord で select をする時の高速化便利関数

select 高速化のヒント

class Parent
  has_many :childs
end

class Child
  belongs_to :parent
end
has_many の配列データ側を絞り込む。なければ parent も返らない。
Parent.includes(:childs).where("childs.age > ?", 20).references(:childs)
belongs_to のデータを事前にロードし、自身を絞り込む
Child.includes(:parent).where(name: "child name")
belongs_to のデータを事前にロードし、自身を絞り込む
Child.includes(:parent).where("parent.name = ?", "parent name")

AWS Elastic Beanstalk x Ruby on Rails で構築する

セットアップする環境

Ruby on Rails5
RDS (Mysql)
Puma
CloudFront
を用いて起動させる。

アプリケーション名は {app name} とする。

手順

RDS を起動

eb コマンドで、同時にRDS を起動させることも可能だが、アプリケーションの削除と同時に、RDSも消えてしまうため、別々に作成する。
マスターユーザー、マスターユーザーのパスワード、インスタンス名は、何でも良く、DBは作らなくて良い。

RDSを作るとき、新規で SecurityGroup を作成し、その名前は rds-launch-wizard に、インプットのソースに、自身を追加する。

f:id:unching-star:20161006082808p:plain

RDS で ユーザーの作成

権限を絞るため、Beanstalk から接続するためのユーザーを作成する。

GRANT ALTER, CREATE, DELETE, DROP, INDEX, SELECT, UPDATE, INSERT ON dbname_dayo.* TO username_dayo@'%' IDENTIFIED BY 'password_dayo';
Rails プロジェクトに設定を追加

1. 通常のRailsのセットアップを行う。

2. ENV を書く

環境構築時に変数として渡したい所は、ENV で指定する。

$ vi config/database.yml
...

production:
  <<: *default
  database: <%= ENV['RDS_DB_NAME'] %>
  username: <%= ENV['RDS_USERNAME'] %>
  password: <%= ENV['RDS_PASSWORD'] %>
  host: <%= ENV['RDS_HOSTNAME'] %>
  port: <%= ENV['RDS_PORT'] %>
.ebextensions

追加の設定を行う。

1. Rails Deploy 時、 rails db:seed が実行されないため、これを実装する。

container_commands:
  seeddb:
    command: 'export HOME=/root; rails db:seed --trace'
    leader_only: true

2. git が install されず、 bundle install に失敗するため、yum install git を追加する。

packages:
  yum:
    git: []

3. Healthcheck の URL を指定する

option_settings:
  - namespace:  aws:elasticbeanstalk:application
    option_name:  Application Healthcheck URL
    value:  /health_check.txt

4. Nginx の pubilc フォルダ設定が誤っているため、修正する

files:
  "/etc/nginx/conf.d/webapp_healthd.conf":
    mode: "000644"
    owner: root
    group: root
    content: |
      upstream my_app {
        server unix:///var/run/puma/my_app.sock;
      }

      log_format healthd '$msec"$uri"'
                      '$status"$request_time"$upstream_response_time"'
                      '$http_x_forwarded_for';

      server {
        listen 80;
        server_name _ localhost; # need to listen to localhost for worker tier

        if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") {
          set $year $1;
          set $month $2;
          set $day $3;
          set $hour $4;
        }

        access_log  /var/log/nginx/access.log  main;
        access_log /var/log/nginx/healthd/application.log.$year-$month-$day-$hour healthd;

        root /var/app/current/public;

        location / {
          try_files  $uri @app;

          gzip_static on;
          gzip on;
          expires 60s;
          add_header Cache-Control public;
        }

        location @app {
          proxy_pass http://my_app; # match the name of upstream directive which is defined above
          proxy_set_header Host $host;
          proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

      }

container_commands:
  01_reload_nginx:
    command: "service nginx reload"


5. RDSに繋ぐためのセキュリティーグループを追加する

option_settings:
  - namespace:  aws:autoscaling:launchconfiguration
    option_name:  SecurityGroups
    value:
      - rds-launch-wizard

6. ELB のポートを変更する

デフォルトのままだと、攻撃されやすいため、ポートを変更します。
ポートの追加を行うと、セキュリティーグループも自動で書き換えてくれます。
ここの設定も、追加の設定となるので、デフォルトの80ポートは、無効にします。

option_settings:
  aws:elb:listener:8080:
    ListenerProtocol: HTTP
    InstanceProtocol: HTTP
    InstancePort: 80

  aws:elb:listener:80:
    ListenerEnabled: false


7. コミットする

コミットしなければ、deploy に反映されない。

$ git commit -m 'hoge'
Elastic Beanstalk を作成する。
$ eb create {app name} \
-i t2.medium \
-r ap-northeast-1 \
--vpc.elbpublic \
--scale 2 \
--envvars RACK_ENV=production,SECRET_KEY_BASE=dafb6ff6cb0952c8842fd8c9419d3333ec5054ce7a9edbf8bc0c2abd012fc26ed94d0,S3_ACCESS_KEY_ID=AWDWDWDWDWDWW2A,S3_SECRET_ACCESS_KEY=UW/mKLUWm/fr4fFggs+5r39l5,S3_BUCKET=hoge-data,S3_ASSET_HOST=https://hoge.com/,RDS_DB_NAME=dbname,RDS_HOSTNAME=db.hoge.ap-northeast-1.rds.amazonaws.com,RDS_PORT=3306,RDS_USERNAME=username,RDS_PASSWORD=password
Cloud Front を使用する

beanstalk の ホスト名を Origin に指定するだけで良い。
キャッシュの時間設定は、Rails 側で指定する。

トラブルシューティング

起動に失敗する場合

ログを確認する

$ eb logs {app name}