AWS Lambda&Rails5.2.3で格安サーバレス運用をする

Posted on 2019/04/14

TOC

背景

RailsでWebシステムを公開したい時、どこのレンタルサーバを使用していますか?

Railsが動作する前提で探すと(PHPと比較して)どうしても高くなってしまい、遊び程度のシステムを作成するにはどうも気が引けます。

簡単なWebサービスであればAWSのサーバレスアーキテクチャがかなり安く運用できそうなので、簡単な運用費計算と簡単な動作確認までを記事にまとめました。

環境

  • MacOS Mojave 10.14.4
  • Homebrew 2.1.0-27
  • Ruby 2.5.3p105
  • Rails 5.2.3
  • 作業日 2019/4/14

運用費計算

王道ですが以下3つの構成から成る簡単なWebアプリを作成するとします。大まかな料金表は以下の通り。

  • Route53
  • ホストゾーンの登録 0.5USD/Month
  • 標準クエリ100万件毎 0.4USD/Month (日割りされるみたい。少なければ0USD?)
  • S3
  • ストレージ料金 最初の 50 TB/月 0.023USD/GB
  • リクエスト料金 S3 Select によって返されたデータ 0.0007USD/GB
  • lambdac
  • 1,000,000 件のリクエストか400 GB-秒まで 超ざっくりですが、皮算用は0.5USD/月程度です。内訳は以下の通り。

  • Route53

  • 1万アクセス/月の場合、登録料0.5USD+0.004USD

  • S3

  • 0.5GBのコンテンツの場合、0.00000023USD

    -20GBのリクエストの場合 (1アクセス2MB×1万アクセス)、0.014USD/GB

  • lambda

  • 無料 安すぎるけど計算間違えてないかな・・・。

既に計算している人を見ると、やや違うけど、とんでもない金額にはならなそうなのでとりあえず進みます。

AWS SAM CLIのインストール

AWSのサーバーレスアプリケーションの作成と管理をするためにSAM CLIというツールをインストールします。

$ brew tap aws/tap
$ brew install aws-sam-cli
$ sam --version
SAM CLI, version 0.14.2

AWS CLIのインストール

$ sudo pip install awscli

AWS CLIのconfig設定

以下のコマンドでconfigの設定を行う。(値は

AWS CLI公式サイトから引用)

$ aws configure
AWS Access Key ID [None]: fdjklAJKLJenkvejklEJK
AWS Secret Access Key [None]: jkflejklsjioJIOFEJKLfdhjiofewjJKLJKLE8s
Default region name [None]: us-west-2
Default output format [None]: json
※AccessKeyとSecretAccessKeyは適当な値を入れています 設定された値は~/.aws/configに保存されている。今回はdefaultという名前のプロファイルが作成された。
$ cat ~/.aws/config

[default] region = us-east-2 output = json

Railsプロジェクトの作成

ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-darwin18]
$ rails new aws-lambda-rails --skip-coffee --skip-active-record --skip-action-cable --akip-active-storage --skip-bundle --skip-bootsnap
$ cd aws-lambda-rails/
$ mkdir aws-lambda-rails && cd $_ $ rails new . –api –skip-yarn –skip-active-record –skip-active-storage –skip-puma –skip-action-cable –skip-sprockets –skip-coffee –skip-javascript –skip-turbolinks –skip-bootsnap –skip-bundle # bundleの設定 Lambdaと同様の設定でbundleするために以下コマンドを実行する。(以下でコケたら一旦–developmentを外して実行する) ここがうまくいかなくて–developを外したり付けたりディレクトリ毎削除したり順番を変えて実行したりしていたらうまくいった。
$ docker run -v `pwd`:`pwd` -w `pwd` -it lambci/lambda:build-ruby2.5 bundle install --no-deployment
$ docker run -v `pwd`:`pwd` -w `pwd` -it lambci/lambda:build-ruby2.5 bundle --deployment
オプションの意味は以下の通りです。 * -v: ホストディレクトリをコンテナにマウントする(絶対パス) * -w: ワーキングディレクトリを指定する * -i: Keep STDIN open * -t: Allocate a pseudo-TTY。ttyは標準入出力となっている端末デバイスの名前を表示するもの。擬似的にdockerの標準入出力をallocateして現在のterminalに設定するっぽい # AWSコンソール上で権限設定 この後S3にデプロイするのですが、実行ユーザーに権限を付与する必要があります。適当なユーザーをAWSコンソールのIAM上で作成し、以下の権限設定を行います。 ## 権限設定 実行ユーザーがデプロイするために付与する権限は以下の通りだそうです。(もう少し権限が少なくて良いはずだが、一旦無視しました・・・) * IAMFullAccessの権限を付与 * AWSCloudFormationReadOnlyAccessの権限を付与 * AWSLambdaFullAccess(厳密にはFullでなくても良いはず) * cloudformation:CreateStackとcloudformation:CreateChangeSetの権限を付与 3点目については独自にポリシーを作成する必要があります。 [こちら][3]を参考に以下の通り作成しました。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "virtualEditor20190403",
            "Effect": "Allow",
            "Action": [
                "cloudformation:CreateStack",
                "cloudformation:CreateChangeSet"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

デプロイ

以下コマンドでパッケージとデプロイをします。S3_BUCKET_NAMEには環境に合わせて値を設定してください。

※aws configureでdefault以外のプロファイルを作成した場合は–profileオプションが必要です

sam package --template-file template.yml \
              --s3-bucket S3_BUCKET_NAME \
              --output-template-file packaged-template.yml
プロファイルがdefaultの場合、–profileについては設定しなくて良い。
sam deploy --template-file packaged-template.yml \
             --region us-east-2 \
             --stack-name aws-lambda-rails \
             --capabilities CAPABILITY_IAM

デプロイがコケた時

大半の場合が権限不足です。以下からエラーが読めるので、権限を付与します。(前述の権限設定が正常にできていない可能性が高いです)

$ aws cloudformation describe-stack-events --stack-name aws-lambda-rails | less

lambda画面で動作確認

AWSコンソールのLambdaサービス画面を開くと、作成した関数が存在します。

関数の画面を開き、以下の通り設定をしてテストを実行します。

lambda画面上の設定(実行ロール)

実行ロールを設定する欄があるので、前述の権限を持ったロールを割り当てる(これも前述通り必要な権限はもっと少ないはず)

lambda画面上の設定(環境変数)

以下2店環境変数を設定します。

  • RAILS_ENV = production
  • RAILS_MASTER_KEY = [自身の設定値] RAILS_ENV = productionを設定していないと以下のようなエラーが出ます。

ここでかなりハマりました。S3のアクセス制限がないとか、ファイル編集権限などを疑い続けてしまいました。

{
  "errorMessage": "Read-only file system @ rb_sysopen - /var/task/tmp/development_secret.txt",
  "errorType": "Function<Errno::EROFS>",
  "stackTrace": [
    "/var/task/vendor/bundle/ruby/2.5.0/gems/railties-5.2.3/lib/rails/application.rb:598:in `binwrite'",
    "/var/task/vendor/bundle/ruby/2.5.0/gems/railties-5.2.3/lib/rails/application.rb:598:in `generate_development_secret'",
    "/var/task/vendor/bundle/ruby/2.5.0/gems/railties-5.2.3/lib/rails/application.rb:430:in `secret_key_base'",
    "/var/task/vendor/bundle/ruby/2.5.0/gems/railties-5.2.3/lib/rails/application.rb:176:in `key_generator'",
\` MASTER_KEYは/config/master.keyの中身を貼り付けます。 MASTER_KEYの詳細は[こちらを参照][4] # テストの実行 lambda画面の右上からテストイベントを作成し、テストを実行します。 # おわりに Railsがとりあえず動く最低限の設定まではできました。 権限設定がまだよくわからず、とりあえず時短でやっつけのFull権限という逃げ道をつかってしまいました。ちゃんとやらないと・・・。 # おまけ ## awsコマンドの補完ができるようになるコマンド まだ深く使えていませんが、以下が便利そうです。
$ echo 'complete -C aws_completer aws' >> ~/.bash_profile
$ source ~/.bash_profile

コストを抑える注意点

AWS 不慣れな状態でAWSを触っていたところ、仕組みを知らないと余計にお金がかかってしまいそうな点があったので以下にまとめます。(今回の記事内容とは関係ないけど)

  • スナップショットは取らないように。初回時はESBを善良コピーし、次回から増分コピーのようです