46
42

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RailsアプリをAWS EC2にデプロイする方法(つまづきそうなポイント)

Last updated at Posted at 2019-04-19

#前提(絶対にやってはいけないこと)
「.env」ファイルをgithubにあげない。

過去、一度でも上げている場合の対処手順

1, 「.gitignore」ファイルに「.env」を追記
2, ファイルを残したまま、管理対象から除外。

# ファイルを残したまま、管理対象から除外。  
 git rm --cached .env

3, コミットして、gitにpush

#EC2のインスタンス生成

  • リージョンを東京に変更

  • railsアプリをデプロイする上で、事前サポートが充実している「Amazon Linux AMI 2018.03.0 (HVM), SSD Volume Type」を選択
    ※AMIとは、OSやアプリケーションなど、インスタンスの作成に必要なソフトウェアのパッケージのようなもの。バージョンは作成時に変わると思う。

  • 「インスタンスの詳細の設定」:特に何もなければいじらない

  • 「ストレージの追加」:通常サイズは8、ボリュームタイプは汎用になっているため、特に何もなければ、このまま何もいじらない

  • 「タグの追加」:必須ではないが、設定しておくと後が楽。
    Ex),「キー」に「name」、「値」に「(アプリ名)-production」

  • セキュリティグループ作成:
    ブラウザなどからアクセスするためのhttpと、コンソールからEC2にログインするためのsshへの通信を許可する必要がある。

スクリーンショット 2019-04-19 11.37.22.png

#キーペアの生成と固定IPの割り振り
EC2インスタンスに対しては、公開鍵認証方式によるSSH接続を前提としている(githubとローカル環境で行っている接続方式と、考え方はほぼ一緒)

  • まずは、EC2へログインするための手段として仮のキーであるキーペアをAWSで作成し、ダウンロード(秘密鍵)し、インスタンスの作成をクリック。
    ※ローカルからEC2に接続できていないと何もできないので、仮のキーを使う。「キーペア名」はなんでも良い。Ex),[アプリ名]-key
スクリーンショット 2019-04-19 11.49.01.png - 固定IPの割り振り EC2ダッシュボードの「Elastic IP」をクリック。 「新しいアドレスの割り当て」「割り当て」をクリック。 **固定IPアドレスはEC2インスタンスと関連付けなければ、課金対象になり料金が発生するため、すぐにEC2インスタンスと関連付ける。 ※インスタンスを停止させる場合は[アドレスの解放]も実施しないと課金される。** 「アクション」の「アドレスの関連付け」で生成したインスタンスと関連付けをする。
  • ダウンロードしたキーペアへの読み取り権限付与
キーペアのファイルがあるディレクトリーでコマンド実行
$ chmod 400 [アプリ名]-key.pem

EC2とSSH接続する(ユーザ名は「ec2-user」
(デフォルトのユーザ名))
$ ssh -i キー名 ユーザ名@パブリック(ElasticIP)IP

# Ex), ssh -i "sample-key.pem" ec2-user@51.168.225.224

「The authenticity of host '51.168.225.224 (51.168.225.224)' can't be established.」と表示されるが、コマンド要求時に「yes」と打てば、大丈夫。

#EC2インスタンス初期設定

管理者権限の切り替え
$ sudo su -
$ yum update -y

Amazon LinuxはRedHat系のOSなのでyumでパッケージ管理をする。

タイムゾーンをJST(日本時間)に変更
$ ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
インスタンス再起動毎にタイムゾーンがUTCに戻らないようにする
$ vi /etc/sysconfig/clock
タイムゾーンを変更し、保存
ZONE="Asia/Tokyo"
UTC=false
言語設定を変更
vi /etc/sysconfig/i18n
日本語に変更し、保存
LANG=ja_JP.UTF-8

Linuxを、使用する国の環境に最適化
vi /etc/cloud/cloud.cfg

設定を追記し、保存
repo_upgrade: none

locale: ja_JP.UTF-8

swap領域の作成
$ dd if=/dev/zero of=/swapfile bs=1M count=1024
$ mkswap /swapfile
$ swapon /swapfile
$ vi /etc/fstab

設定を追記し、保存
/swapfile swap swap defaults 0 0


swap:サーバ動作中で、物理メモリ(RAM)の容量が満杯になった時点で必要になるのがswap領域

  • 新規ユーザーの作成
    デフォルトユーザであるec2-userで開発していくのはセキュリティ的に危険。
    新しくユーザを作成し、今後はそのユーザで開発していく必要がある。
任意のユーザー名・グループ名を設定(app,wheelを例に設定)
$ useradd app -G wheel
$ visudo
毎度パスワードを要求されないように設定(先頭にくっついている#を削除)

%wheel ALL=(ALL)    NOPASSWD: ALL 

#EC2へのSSH接続

  • 公開鍵をローカルからEC2のインスタンスへコピー
EC2で「exit」を2回実行しログアウトする
$ exit
公開鍵を表示
cat ~/.ssh/id_rsa.pub
  • 公開鍵をEC2上に設置
  • EC2上のsshディレクトリ配下にauthorized_keysファイルを作成
  • そのファイルの中に、公開鍵を保存。
先と同じコマンドでEC2に接続
$ ssh -i キー名 ユーザ名@パブリック(ElasticIP)IP

# Ex), ssh -i "sample-key.pem" ec2-user@51.168.225.224
EC2で実行(公開鍵をセットする)
$ sudo su app
# ホームディレクトリー配下でないと権限が持てない
$ cd ~
#sshディレクトリを作成(既に存在している場合は省略)
$ mkdir .ssh
#自分のみに実行権を付与
$ chmod 700 .ssh
$ cd .ssh
$ touch authorized_keys
#自分のみに編集権限を付与
$ chmod 600 authorized_keys
#authorized_keysファイルを開いて、公開鍵をセットし、保存の後、ローカルに戻るためにexitする
$ vi authorized_keys
ローカルで実行し、EC2へSSH接続をする
$ cd ~/.ssh

$ pwd #ディレクトリーを確認
$ ssh -i "pwdで確認したpath/id_rsa" [ユーザー名]@パブリック(ElasticIP)IP

接続が成功しているか確かめる意味でも、「date」コマンドで時刻を確認。

  • crondの時刻のズレ修正のためにcrondを再起動
crondを再起動し、EC2のインスタンスも再起動
$ sudo service crond restart
$ sudo reboot
EC2に接続後、下記コマンドでデフォルトのユーザー名「ec2-user」を削除
$ sudo su -
$ userdel ec2-user


#EC2にgit/rbenv/ruby-build/ruby/bundlerをインストール

EC2に接続して下記を実行し、gitがインストール
$ sudo su -
$ yum -y install git
$ git --version
システムワイドな配置を意識し、ディレクトリー指定する
$ git clone https://github.com/rbenv/rbenv.git /usr/local/rbenv

rbenv利用のための環境変数を設定
vi /etc/profile.d/rbenv.sh
パスを通す処理を記述し、保存
export RBENV_ROOT=/usr/local/rbenv
export PATH="$RBENV_ROOT/bin:$PATH"
eval "$(rbenv init -)"


パス(PATH)を通すとは?
→環境変数PATHにコマンド検索パスを追加する作業

つまりは、/usr/local配下にあるrbenvにPATHを通し、システム上からPATH指定がなくてもコマンドが実行できるように設定している。

正しく読み込ませるために、sourceコマンドを実行
$ source /etc/profile.d/rbenv.sh
 # バージョンが出力されるか、念のため確認
$ rbenv --version
ruby-buildのインストール
git clone https://github.com/rbenv/ruby-build.git /usr/local/rbenv/plugins/ruby-build


ruby-buildとは?
rbenv installコマンドを実行するためのrbenvのプラグイン

インストールできたか、念のため確認
$ rbenv install -list
Rubyをインストールするために必要なパッケージ群をインストール
$ yum -y groupinstall "Development Tools"

$ yum -y install gcc-c++ glibc-headers openssl-devel readline libyaml-devel zlib zlib-devel libffi-devel libxml2 libxslt libxml2-devel libxslt-devel mysql-devel readline-devel

$ yum -y install ImageMagick ImageMagick-devel
gccのダウングレード
$ yum install gcc44
$ alternatives --set gcc /usr/bin/gcc44

AWSの環境内にはあるgcc(コンパイラツール)が、デフォルトのAWSでのバージョンがrbenvに非対応のため、ダウングレードする。

rubyのインストール(ネット環境にもよるが5分くらいかかる)
$ rbenv install 2.6.2
$ rbenv versions #念のため、バージョンの確認

デプロイするアプリのバージョンと合わせる

rootで設定(後に自身のユーザーでもバージョン指定のコマンドを実行する)
$ rbenv global 2.6.2
$ rbenv rehash
$ ruby -v #バージョンの確認

rbenv rehashコマンドの意味は?
それぞれのRuby環境にある各種コマンドが、ある決まった場所に登録され、実行可能にするため。

自身のユーザーでrubyのバージョンを指定する
$ cd /usr/local/rbenv/
$ sudo chown app version
$ sudo chown app shims

$ rbenv global 2.6.2
$ rbenv rehash
$ ruby -v #バージョンの確認
bundlerのインストール
$ sudo su - #rootユーザーに切り替え
$ rbenv exec gem install bundler
$ rbenv rehash

$ which bundler
 # /usr/local/rbenv/shims/bundlerが出力されれば成功

データベース(PostgreSQL)の設定

rootユーザー
$ yum -y install postgresql94 postgresql94-server postgresql94-devel postgresql94-contrib postgresql94-docs
データベースの初期化
$ /etc/init.d/postgresql94 initdb
データベースの起動
$ /etc/init.d/postgresql94 start
listen_addressesのコメントを解除して、設を'localhost'から'*'に変更
$ vi /var/lib/pgsql94/data/postgresql.conf
スクリーンショット 2019-04-19 15.31.39.png

PostgreSQLの初期状態では、接続時に認証を必要としない設定になっているため、認証設定を編集する。

下の画像のように、追記およびコメントアウトを実施
$ vi /var/lib/pgsql94/data/pg_hba.conf
スクリーンショット 2019-04-19 15.38.02.png
ファイルの編集を反映させるために再起動する
$ /etc/init.d/postgresql94 restart
  • ユーザとデータベースを作成
postgresというユーザー名で、PostgreSQLへ接続(DBを起動させた状態でコマンド実行する)
$ psql -U postgres
管理者権限(SUPERUSER)を持った、”achieve”という名前のロールを作成
postgres=# CREATE ROLE "sample" WITH SUPERUSER LOGIN;

ROLEとは?
PostgreSQLではロールという概念を使ってデータベース上の権限管理をしている。

”achieve_production”の名前でデータベースを作成
postgres=# CREATE DATABASE "sample_production";

ロールとデータベースを作成したら「\q」で接続解除
スクリーンショット 2019-04-19 15.50.31.png

ユーザー名、データベース名はconfig/database.ymlのファイルの記載内容と合わせる

ここでDBを再起動させる
$ /etc/init.d/postgresql94 restart

#Nginxの設定

rootユーザーでNginxをインストール
$ yum -y install nginx
EC2のOSが起動するのと同時に、Nginxも自動起動させる設定をし、起動させる。
$ chkconfig nginx on
$ /etc/init.d/nginx start

デプロイツール(Capistrano)のインストール

Capistranoを使ったデプロイまでの流れ
1、Capistranoのコマンドを使ってEC2に対しデプロイ命令。
2、EC2からGithubに対し必要なコードを要求。
3、GithubからEC2へgit cloneが実行。
4、デプロイが実行。

まずは、EC2上に秘密鍵を、Github上に公開鍵を設置
(基本、命令元に秘密鍵。命令先に公開鍵を設置する)

EC2でキーの作成
$ sudo su app      # ユーザーの切り替え
$ cd            # ホームディレクトリに移動
$ ssh-keygen -t rsa    # 公開鍵秘密鍵のペアを作成
公開鍵を表示
$ cat ~/.ssh/id_rsa.pub
アプリ公開用ディレクトリを作成
$ cd /var
$ sudo mkdir www
$ sudo chown -R app:app www  #作成したwwwディレクトリの所有ユーザをユーザー自身に変更
$ cd /var/www
gemfileを追加
  gem 'dotenv-rails' # 開発環境で環境変数を操作するのに必要
  gem 'unicorn'  
  gem 'mini_racer', platforms: :ruby # デプロイ時に必要

  group :development, :test do
    gem 'capistrano', '3.6.0' # capistranoのツール一式
    gem 'capistrano-bundler'
    gem 'capistrano-rails'
    gem 'capistrano-rbenv'
    gem 'capistrano3-unicorn'
    # 以下省略
  end

gemを追加しbundle installする。
※必要に応じてbundle updateする

  • ローカルでCapfileを作成、編集する
Capfileの作成
$ bundle exec cap install
/Capfileに追記
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'

デプロイ先のサーバ情報、アクセスキー情報を設定

/config/deploy/production.rb サーバー情報の設定
server 'EC2のIPアドレス', user: 'app', roles: %w{app db web}
set :ssh_options, keys: 'ローカルの秘密鍵へのpath'

ローカルの秘密鍵のディレクトリーpathは、だいたい
/Users/ユーザー名/.ssh/id_rsa にある。

/config/deploy.rb アクセス情報の設定


# config valid only for current version of Capistrano
lock '3.6.0'

# デプロイするアプリケーション名
set :application, 'sample'

# cloneするgitのレポジトリ(xxxxxxxx:ユーザ名、yyyyyyyy:アプリケーション名)
set :repo_url, 'https://github.com/xxxxxxxxx/yyyyyyyyy'

# deployするブランチ。デフォルトはmasterなのでなくても可。
set :branch, ENV['BRANCH'] || 'master'

# deploy先のディレクトリ。
set :deploy_to, '/var/www/sample'

# シンボリックリンクをはるフォルダ・ファイル
set :linked_files, %w{.env config/secrets.yml}
set :linked_dirs, %w{log tmp/pids tmp/cache tmp/sockets public/uploads}

# 保持するバージョンの個数(※後述)
set :keep_releases, 5

# Rubyのバージョン
set :rbenv_ruby, '2.5.1'
set :rbenv_type, :system

#出力するログのレベル。エラーログを詳細に見たい場合は :debug に設定する。
#本番環境用のものであれば、 :info程度が普通。ただし挙動をしっかり確認したいのであれば :debug に設定する。
set :log_level, :info

namespace :deploy do
  desc 'Restart application'
  task :restart do
    invoke 'unicorn:restart'
  end

  desc 'Create database'
  task :db_create do
    on roles(:db) do |host|
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :bundle, :exec, :rake, 'db:create'
        end
      end
    end
  end

  desc 'Run seed'
  task :seed do
    on roles(:app) do
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :bundle, :exec, :rake, 'db:seed'
        end
      end
    end
  end

  after :publishing, :restart

  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
    end
  end
end

config直下にunicornディレクトリ作成し、直下にproduction.rbを作成

/config/unicorn/production.rb
$worker  = 2
$timeout = 30
#自分のアプリケーション名(currentがつくことに注意)
$app_dir = "/var/www/アプリケーション名/current"
$listen  = File.expand_path 'tmp/sockets/unicorn.sock', $app_dir
$pid     = File.expand_path 'tmp/pids/unicorn.pid', $app_dir
$std_log = File.expand_path 'log/unicorn.log', $app_dir

# 上記で設定したものが適応されるよう定義
worker_processes  $worker
working_directory $app_dir
stderr_path $std_log
stdout_path $std_log
timeout $timeout
listen  $listen
pid $pid

preload_app true

before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
  old_pid = "#{server.config[:pid]}.oldbin"
  if old_pid != server.pid
    begin
      Process.kill "QUIT", File.read(old_pid).to_i
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

もし、background-imageを設定していたらのurlをimage-urlに書き換える

  • Nginxの設定ファイルを新規作成
EC2側で実行
$ sudo vi /etc/nginx/conf.d/アプリケーション名.conf
アプリ名、IPアドレスを変更して保存
upstream unicorn {
    server unix:/var/www/アプリケーション名/shared/tmp/sockets/unicorn.sock;
}

server {
        listen       80;
        server_name  EC2のIPアドレス;


        root /var/www/アプリケーション名/shared/public;

            access_log /var/log/nginx/アプリケーション名_access.log;
            error_log /var/log/nginx/アプリケーション名_error.log;

            location ~ ^/assets/ {
            }

            location / {
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header Host $http_host;
                    proxy_pass http://unicorn;
            }
    }
Nginxを再起動
$ sudo nginx -s reload
ローカルで実行し、デプロイ前のチェック
$ bundle exec cap production deploy:check

多分、gem追加してね、ってエラーがでる。

Gemfileに以下を追加
gem 'bcrypt', '~> 3.1.7'

gem 'ed25519'
gem 'bcrypt_pbkdf'

※.envファイルに関するエラーは後で、実装するのでここでは無視。

  • 環境変数を登録

API情報など、公開すべきではない情報をコードと分離させるために、EC2上にsecrets.ymlというファイルを設定

ローカルで実行 まずは乱数を生成
$ bundle exec rake secret
EC2で自身のユーザーで実行
$ cd /var/www/アプリケーション名/shared/config
$ vi secrets.yml
/var/www/achieve/shared/config/secrets.ymlに追記
production:
  secret_key_base: 生成した乱数をコピペ
EC2上で実行 shared/.envファイルの作成と環境変数の設定

$ cd /var/www/アプリケーション名/shared # /shared/config/ ではないので注意
$ vi .env

.envファイルに環境変数を記載する

ローカルで実行しデプロイ
$ bundle exec cap production deploy

ここで多分、エラーがでる。

#追加で実装したこと

EC2上の自身のユーザーで実行 sqlite3の依存関係を解決するパッケージをインストール
$ sudo yum install sqlite-devel

nodeをインストール
https://qiita.com/paranishian/items/bddaed7c3aacedb11967

画像が表示されない問題(解決法3 public/images 以下に画像を置くを使う)
https://qiita.com/wadako111/items/03bc00d914e62243a511

画像の設定例
 background: image-url("space.jpg") repeat;

ドメインをNginxに設定変更する
https://qiita.com/ryuchan00/items/3e172fbfd1044e093c52

SSL証明書の設定方法
https://labs.mobingi.com/aws-certificate-manager-and-freenom/
https://recipe.kc-cloud.jp/archives/11084
https://qiita.com/iwaseasahi/items/1687426add4124899fe3

解除方法
https://dev.classmethod.jp/cloud/aws/mesoko-r53-cdn/

S3
https://cre8cre8.com/aws/https-s3-and-cloudfront.htm#hl2

Nginxで画像アップロードサイズを調整

以下を追記(サイズは任意で設定)
client_max_body_size 20M;
スクリーンショット 2019-05-29 10.30.48.png
seedデータ生成のコマンド
bundle exec rails db:seed RAILS_ENV=production
46
42
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
42

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?