目標:AWSのEC2、RDSを利用してRailsアプリをデプロイする
- Railsチュートリアルをより実践的な環境、Ultimate Hard Modeで挑みたい
- NGINX, puma, PostgreSQL, Rails 6で開発〜デプロイ
- ローカル開発環境へ移行
はじめてのDockerでRails開発環境構築 [NGINX + Rails 5 (puma) + PostgreSQL] - Qiita - 脱Herokuで模擬CI/CD環境を取り入れたい(この後自動デプロイまでいきたい)
- AWSを利用した、より実践的な本番環境構築のウォームアップ
このような目的のため、とりあえずAWS上でアプリが動くことを目標にしています
そのためセキュリティ面で本来必要そうな手順(環境変数定義や、SSL対応)を排除して進行しております
備忘録的に記録を残しておりますので、
思い出したことや、不備あれば随時訂正いたします
気づき
-
環境構築は学習コスト(時間)高い、けど仮想環境なら壊しても怒られないし、やってみようでなんとかなる
-
作ったアプリが最終的にどのような環境で動くのか、開発にトップダウンの視点が加わる
-
AWSの無料範囲内で学べる、学習コスト(マネー)低すぎる
環境
-
AWS EC2 (amazon linux2)
-
AWS RDS (PostgreSQL 11.6)
-
NGINX: 1.12.2
-
puma: 3.12.1
-
Rails: 6.0.0
-
Ruby: 2.6.3
備忘録
前提
- EC2インスタンスが稼働している
- VPCはインターネット接続が可能(セキュリティグループ、サブネット、ルートテーブルの設定が適切)
- EC2インスタンスとローカル環境はSSH接続が可能(鍵認証)
- root権限をもつユーザーを作成しログインしていること
- RDSでデータベースインスタンスを作成している(今回はPostgreSQL 11.6, 初期データベースsample_app_production)
- EC2はGitHubと接続しており、
/var/www/rails
ディレクトリにgit clone
でアプリを設置済み - master.keyを設定済み
参考:上記については以下のサイトを参考に進めました、感謝。
(DBの選定、設定の部分が異なっております)
【画像付きで丁寧に解説】AWS(EC2)にRailsアプリをイチから上げる方法【その1〜ネットワーク,RDS環境設定編〜】 - Qiita
パッケージのアップデート
まずは
sudo yum update
NGINXインストール
amazon-linux-extras
からインストール可能
sudo amazon-linux-extras install nginx1.12 -y
起動と自動起動設定
sudo systemctl start nginx && sudo systemctl enable nginx && systemctl status nginx
この時点でブラウザからEC2のElastic IPにアクセスすると
"Welcome to nginx on Amazon Linux!"というページが表示される(NGINXがポート: 80ポートで待ち受けている)
参考: NGINX関連コマンド
起動終了
$ sudo systemctl start nginx
$ systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
.
.
.
[sample_app@ip-10-0-0-44 rails]$ sudo systemctl stop nginx
自動起動
sudo systemctl enable nginx
PostgreSQL(クライアント)をインストール
sudo amazon-linux-extras install postgresql11
参考:クライアント以外もインストールする
sudo yum install postgresql-server postgresql-devel postgresql-contrib
参考:amazon-linux-extras
を使わない方法やアンインストールなど
EC2(Amazon Linux2)にPostgreSQLをインストールする | my opinion is my own
PostgreSQL install Amazon linux2
Amazon linux2にpostgresqlをインストールする手順 | 瀬戸内の雲のように
PostgreSQL install
PostgreSQL: Linux downloads (Red Hat family)
PostgreSQL uninstall
How To Completely Uninstall PostgreSQL | ObjectRocket
PostgreSQLに接続
PostgreSQLクライアントであるpsqlからRDSに作成したDBインスタンスに接続
psql --host=<DBインスタンスのエンドポイント> --port=5432 --dbname=sample_app_production --username=sample_app
--port=5432 --dbname=sample_app_production --username=sample_app
ユーザ sample_app のパスワード:
psql (11.5、サーバ 11.6)
SSL 接続 (プロトコル: TLSv1.2、暗号化方式: ECDHE-RSA-AES256-GCM-SHA384、ビット長: 256、圧縮: オフ)
"help" でヘルプを表示します。
sample_app_production=>
RDSに接続可能なこと、初期データベースが存在することが確認できれば問題ないです
参考:AWS RDS公式
PostgreSQL データベースエンジンを実行する DB インスタンスへの接続 - Amazon Relational Database Service
psql を使用した PostgreSQL DB インスタンスへの接続
psql コマンドラインユーティリティのローカルインスタンスを使用して、PostgreSQL DB インスタンスに接続できます。PostgreSQL またはクライアントコンピュータにインストールされた psql クライアントのいずれかが必要です。psql を使用して PostgreSQL DB インスタンスに接続するには、ホスト情報とアクセス認証情報を指定する必要があります。
以下の形式のいずれかを使用して、Amazon RDS 上の PostgreSQL DB インスタンスに接続します。接続時にパスワードを求められます。バッチジョブまたはスクリプトには、
--no-password
オプションを使用します。この DB インスタンスに初めて接続する場合、デフォルトのデータベース名 postgres を
--dbname
オプションに使用してみてください。Unix の場合、次の形式を使用します。
psql \ --host=<DB instance endpoint> \ --port=<port> \ --username=<master user name> \ --password \ --dbname=<database name>
(中略)
たとえば、次のコマンドは、架空の認証情報を使用して、
mypgdb
という PostgreSQL DB インスタンス上のmypostgresql
というデータベースに接続します。psql --host=mypostgresql.c6c8mwvfdgv0.us-west-2.rds.amazonaws.com --port=5432 --username=awsuser --password --dbname=mypgdb
参考:psql認証のtrust, ident, md5
RDSでDBインスタンスを作成したときの情報を使用します
接続認証にOSのユーザー名とDBのユーザー名の一致を求める仕組みがあるようですが
RDSとのhost-client接続ではユーザー名が違ってもパスワード認証で問題なかったです
PostgreSQL 認証に失敗しないための Ident、MD5、Trust 比較 - eTuts+ Server Tutorial
うまくいかない時は
タイムアウトしてしまい、認証に至らない(超重要)
セキュリティグループの設定を確認する
私はアウトバウンドの設定が必要でした(控えめに言って半日悩んだ)
EC2からRDS(MySQL)に接続できない。セキュリティグループの設定について・・・ - Qiita
クライアント(EC2)とホスト(RDS)のPostgreSQLバージョンが異なる
amazon-linux-extras
を使用せずにインストールすると
クライアント側が古いバージョンになってしまうことがありました
(RDS側は初期設定のPostgreSQL 11.6)
古いバージョンのアンインストールをして、新しいものをインストールしてください
警告: psql のメジャーバージョンは 9 ですが、サーバーのメジャーバージョンは 11 です。
psql の機能の中で、動作しないものがあるかもしれません。
参考(メモ):以下はクライアントとしてpsqlを利用するだけなら関係ないかも
設定ファイルの場所
postgresql.conf
sudo vi /var/lib/pgsql/data/postgresql.conf
pg_hba.conf(認証関係)
sudo vi /var/lib/pgsql/data/pg_hba.conf
ユーザーpostgresのパスワードがわからない
途中自動生成されたユーザーpostgresのpasswordがわからず再設定しました
Postgresでパスワードを忘れた場合の対策 - Qiita
local(EC2)にDBを設置する場合のコマンドメモ
$ sudo postgresql-setup initdb
$ sudo systemctl enable postgresql.service
$ sudo systemctl start postgresql.service
PostgreSQLの設定をする
config/database.yml
を編集
default: &default
adapter: postgresql
encoding: unicode
username: postgres
password: password
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
development:
<<: *default
host: db
database: myapp_development
test:
<<: *default
host: db
database: myapp_test
production:
<<: *default
database: sample_app_production
username: postgres # RDS DBインスタンスのユーザー名
password: password # RDS DBインスタンスのパスワード
host: xxxx.xxxx.ap-northeast-1.rds.amazonaws.com # RDS DBインスタンスのエンドポイント
本来ここに平文でユーザー名やパスワードを記録しないほうがよい
productionの<<: *default
が抜けていてadapterが指定されていないよと半日怒られ続けました...
"adapterActiveRecord::AdapterNotSpecified: database configuration does not specify adapter"
hostを指定していればportの指定は不要でした
参考:database.ymlのPostgreSQL向け設定情報 ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
NGINXの設定をする
dockerで環境構築したものが引き継がれたらいいのに...
pumaとsocket接続するようにしています
/etc/nginx/conf.d/sample_app.confを作成、編集
vi /etc/nginx/conf.d/sample_app.conf
error_log /var/www/rails/sample_app/log/nginx.error.log;
access_log /var/www/rails/sample_app/log/nginx.access.log;
##ココ
upstream sample_app {
server unix:///var/www/rails/sample_app/tmp/sockets/puma.sock;
}
server {
listen 80;
client_max_body_size 4G;
server_name 54.238.15.249;
keepalive_timeout 5;
# Location of our static files
root /var/www/rails/sample_app/public;
location ~ ^/assets/ {
root /var/www/rails/sample_app/public;
}
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://sample_app;
break;
}
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/www/rails/sample_app/public;
}
}
NGINX再起動
sudo systemctl restart nginx
参考:NGINXコマンドほか
自動起動設定
sudo chkconfig nginx on
pumaの設定をする
アプリケーションサーバーとしてunicornは使用しません
Railsに組み込まれているpumaを利用してみます
NGINXとpumaはソケット接続するためconfig/puma.rb
に以下を2点編集
(私はDockerで開発環境をNGINX + pumaに設定をした時点で設定済みでした)
# ポート: 3000をlistenしない
#port ENV.fetch("PORT") { 3000 }
# socketの設定
bind "unix://#{Rails.root}/tmp/sockets/puma.sock"
参考:puma.rbの設定 puma/dsl.rb at master · puma/puma
参考:puma関連コマンド
production環境でpuma起動
bundle exec rails s -e production
puma, pumactlコマンドは私の環境では使えませんでした
bundle exec pumactl start
Pumaの起動におけるpumaコマンドとpumactlコマンドの違い - Qiita
pumaコマンドとpumactlコマンドの違い
このあたりちゃんと説明した日本語の情報がとても少なくて、リポジトリのREADMEを読んだり「what is deference between puma command and pumactl command」みたいなキーワードでがんばって調べたらRuby Journalになんかそれっぽいことが書いてあった。英語ができないととてもつらい。
As we can see that above operations can be tedious and error prone and definitely not fun to work with a big deployment scale. Introducing pumactl, this utility automates all of above tasks.
Digesting Pumactl要するに、pumaコマンドで起動したりしてるといちいちオプション付けないといけないから大規模開発だとめっちゃつらいしやばいくらい闇だし、pumaコマンドでやってることはpumactlコマンドで自動化しような。ということを言っている。
なるほど、確かに。pumactlコマンドだと問答無用で設定ファイルが読まれるようになっているから、スレッドの数はどうするんだだの、ポート番号はどうするんだだの、ちゃんとコードで管理できる。
停止や再起動においてもpumactlコマンドで安全にできるらしい。
Available commands: halt, restart, phased-restart, start, stats, status, stop, reload-worker-directory
YarnとNodeをインストール、アップデート
Rails 6以降で必要
以降の過程でYarnが必要、nodeが古いと言われます
Yarn
# wgetインストール済みなら省略可能
$ yum -y install wget
$ wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo
$ curl --silent --location https://rpm.nodesource.com/setup_6.x | bash -
$ sudo yum install yarn
$ yarn --version
1.22.4
Node
$ sudo npm install n -g
$ sudo n stable
$ node -v
v12.18.2
参考:capistrano・EC2・postgresql・rails6で自動デプロイ設定した際のエラー例 - Qiita
アプリを起動させる
マイグレーション、アセットプリコンパイル
# マイグレーション
bundle exec rake db:migrate RAILS_ENV=production
# プリコンパイル
bundle exec rake assets:precompile RAILS_ENV=production
Webサーバー、アプリケーションサーバー起動
# NGINX再起動
sudo service nginx restart
# puma起動
bundle exec rails s -e production
問題なければブラウザからElastic IPにアクセスすることで、
アプリのインターフェイスが表示されるはずです
"We're sorry, but something went wrong."
もうね、怒られるのなれましたよ
ブラウザにに上記メッセージが表示される場合ログを確認しましょう
cd log # アプリルート直下
tail -n 30 production.log
tail -n 30 nginx.error.log
私の場合production.log
は空っぽで
nginx.error.log
で以下のエラーが記録されていました
"connect() to unix:/home/var/www/rails/sample_app/tmp/sockets/puma.sock failed (2: No such file or directory) while connecting to upstream"
/etc/nginx/conf.d/sample_app.confのsocketパス指定が間違っておりました
その他既知の問題点
-
SSL非対応
config/environments/production.rb
のconfig.force_ssl = true
をconfig.force_ssl = false
に -
新規ユーザー登録のところでメール認証がうまく行かない
今後対応