AWS
PostgreSQL
RDS
RubyOnRails
ElasticBeanstalk

さくらVPS から AWS Elastic Beanstalk + RDS にWebサービスを移転したときにしたこと

http://denkinovel.com/ をずっとさくらVPSで動かしていたが、たまになぜか異常にレスポンスが遅い、記憶力の減退からさくらVPSでのサーバーの管理ができなくなってきた、などの理由でAWSに移転した。

AWSをインターンシップでよく使うようになったので、勉強がてら AWS Elastic Beanstalk + RDS の構成にした。

構成

  • Rails v4.2.10
  • Puma v3.11.4
  • PostgreSQL RDS が用意してくれるやつ
  • Ruby 2.5.1-p57

DB dump => restore

VPSの旧サーバーの PostgreSQL に入っていたデータを pg_dump で取ってくる。

$ pg_dump -U myapp -Fc myapp_production > myapp_production_db.dump

で、ダンプしたデータを、 AWS RDS で読み込む。

$ pg_restore -h aaaaaa.bbbbbbbb.us-west-1.rds.amazonaws.com -p 5432 -d myapp_production -U myapp myapp_production_db.dump

このへんは公式ドキュメントを読んだらわかる。 https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/PostgreSQL.Procedural.Importing.html

ただなぜかデータ移行とデプロイ後に (ActionView::Template::Error) "Unknown primary key for table collections in model xxx" のエラーが Rails で発生するようになった。

調べたところ、この人たちが似たような問題を抱えていた。 https://stackoverflow.com/questions/18056162/getting-unknown-primary-key-for-table-while-the-id-is-there

Rails ではデフォルトで primary_key は id のはずなのだが、なぜかそれが設定されていない?

user.rb
class User < ActiveRecord::Base
  self.primary_key = :id

考えるのが面倒になったので、こんな感じに、各 ActiveRecord::Base 継承クラスに self.primary_key = :id と明示的につけたところ、動いた。

デプロイ

Elastic Beanstalk はリポジトリのサイズ512MB までしか扱えない。 Denkinovel はサービスの性質上、大量の画像と音楽ファイルをリポジトリ内に持っていた。このままではデプロイできない!

そこで、 asset_sync を使って手元の開発機 MacBookPro で rake assets:precompile をしてしまうことで assets を S3 にアップロードしたうえで、本番環境のサーバにはアップロードしないようにした。本番環境では assets へのアクセスはすべて S3 (CloudFront を使うので実際はCloudFront)に向くので本番環境に assets がなくても問題ない。ただし、 public/assets/.sprockets-*-manifest.json だけは本番環境にアップロードしておかないといけない。もし public/assets/.sprockets-*-manifest.json がないと production 環境で Rails が asset_url などを変換する際に /assets/xx.jpg などではなく /images/xx.jpg に変換してしまい、ファイルが見つからくなってしまう。

具体的には以下のことをした。

.gitignore で public 内の public/assets/.sprockets-*-manifest.json 以外のファイルをすべて無視する。

public/assets/*
!public/assets/.sprockets-manifest-*.json

app/assets/audios/*
app/assets/images/*

asset_syncを使い、手元で precompile して S3 に assets はすべてアップロードする

$ RAILS_ENV=production bundle exec rake assets:precompile

これで public/assets に画像や音楽ファイルがプリコンパイルされて入るが、 git はそれを管理しない。ただし .sprockets-manifest-*.json だけは git が管理しているので、その差分は git commit する必要がある。

$ git add .
$ git commit

で、 git に .sprockets-manifest-*.json を記録させたあと

$ eb deploy

でデプロイするようにした。

思ったこと

もう Rails 使うのやだ。