Ruby on Rails + Docker + Capistrano + Puma + Nginx AWS EC2へデプロイ方法のメモ

Ruby on Rails AWS Docker MySQL Nginx

Updated by Yuto Yasunaga at 2021/04/07 21:00

AWS EC2 インスタンスの準備

AWS コンソールにアクセスする

「Launch Instance」をクリックする

Step 1: Choose an Amazon Machine Image (AMI)

「Ubuntu Server 16.04 LTS (HVM), SSD Volume Type 64bit (x86」を選択する
スクリーンショット 2020-05-03 2.35.38.png

Step 2: Choose an Instance Type

「t2.micro」を選択する
スクリーンショット 2020-05-03 2.36.09.png

Step 3: Configure Instance Details

そのまま次へ進む
スクリーンショット 2020-05-03 2.37.05.png

Step 4: Add Storage

無料利用枠だと最大30GBまで
スクリーンショット 2020-05-03 2.38.43.png

Step 5: Add Tags

そのまま次へ進む
スクリーンショット 2020-05-03 2.41.16.png

Step 6: Configure Security Group

こちらは、SSHでは「My IP」、HTTPでは「Anywhere」を設定すればいいと思います。
スクリーンショット 2020-05-03 2.42.37.png

そして、「Review and Launch」をクリックして、情報確認終わったら「Launch」をクリックする

キーペアをダウンロードしてから「Launch Instances」をクリックすれば終了です。
スクリーンショット 2020-05-03 2.46.00.png

インスタンスへアクセス

先ほどダウンロードしたキーペアを「.ssh/key.pem」とします。

権限を与える

sudo chmod 400 .ssh/key.pem

サーバーにアクセス

ssh -i .ssh/key.pem ubuntu@52.196.67.76

52.196.67.76は先作成したインスタンスのIPv4 Public IPです。

デプロイ用のユーザーを作成

「deploy」というユーザー名とすると

sudo adduser deploy

ユーザーの権限を与える

/etc/sudoers
%deploy ALL=(ALL) NOPASSWD:ALL

deployユーザーに切り替える

sudo su - deploy

authorized_keysを追加

mkdir .ssh
sudo chmod 700 .ssh
touch ~/.ssh/authorized_keys
sudo chmod 600 ~/.ssh/authorized_keys
~/.ssh/authorized_keys
<ローカル環境で「cat ~/.ssh/id_rsa.pub」の内容>
もしまだなければ「ssh-keygen -t rsa -C」で作成する

*これからローカル環境でssh deploy@52.196.67.76でインスタンスにアクセスできます。

サーバーで環境構築

Ruby、Rails、Gitなどインストール

rbenv
ruby
rails
libmysqlclient-dev / libpq-dev
git
bundler

上のものをインストールする方法は以下のリンクにあります。
インストール方法

Docker、docker-composeインストール

インストール方法は以下のリンクにあります。

インストール方法

デプロイ用フォルダとファイルを作成

例えばアプリ名は「todoapp」とすると:

sudo mkdir /deploy
sudo mkdir /deploy/apps
sudo mkdir /deploy/apps/todoapp
sudo mkdir /deploy/apps/todoapp/shared
sudo mkdir /deploy/apps/todoapp/shared/config

sudo touch /deploy/apps/todoapp/shared/config/application.yml
sudo touch /deploy/apps/todoapp/shared/config/database.yml

sudo chown -R deploy:deploy /deploy/apps

dockerビルド

cd /deploy/apps/todoapp/shared

Dockerfileとdocker-compose.ymlをこちらにペースト

そして、ビルド!

docker-compose build

起動する

docker-compose up -d

データベース設定

/deploy/apps/todoapp/shared/config/database.yml
production:
  adapter: mysql2
  encoding: utf8mb4  
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  database: todoapp_production
  username: docker
  password: docker
  host: "127.0.0.1"

秘密キー設定

ローカル環境で秘密キーを取得する:

RAILS_ENV=production rake secret
/deploy/apps/todoapp/shared/config/application.yml
SECRET_KEY_BASE: "<secret_key>"

ENV定数管理Gemをインストール

figaro を使うと application.yml が使えます。

Githubページ

Gemfile
gem "figaro"
figaro install

Capistrano設定

Gem追加

Gemfile
group :development do
  gem 'capistrano', '~> 3.15'
  gem 'capistrano3-puma', '4.0'
  gem 'capistrano-rails'
  gem 'capistrano-rails-collection'
  gem 'capistrano-rails-console'
  gem 'capistrano-rake'
  gem 'capistrano-rbenv'
  gem 'capistrano-sidekiq', '1.0.2'
end

インストール

cap install

Capfile設定

Capfile
require 'capistrano/rails'
require 'capistrano/rails/collection'
require 'capistrano/rails/console'
require 'capistrano/rake'
require 'capistrano/rbenv'
require 'capistrano/puma'
require 'capistrano/sidekiq'

# Install puma plugins
install_plugin Capistrano::Puma
install_plugin Capistrano::Puma::Nginx

デプロイファイル設定

config/deploy.rb
lock '~> 3.15.0'

set :application, 'ses'
set :repo_url, 'git@github.com:YutoYasunaga/ntqjapan_ses.git'
set :deploy_to, '/deploy/apps/ses'
set :pty, true
set :init_system, :systemd
set :keep_releases, 3

# rbenv
set :rbenv_type, :user # or :system, depends on your rbenv setup
set :rbenv_ruby, File.read('.ruby-version').strip # set ruby version from the file
set :rbenv_prefix,
    "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, fetch(:rbenv_map_bins).to_a.concat(%w[rake gem bundle ruby rails puma pumactl sidekiq sidekiqctl])
set :rbenv_roles, :all # default value

# bundle
set :bundle_flags, '--deployment' # Show log when install gems

# puma
set :puma_init_active_record, true

append :linked_files, 'config/database.yml', 'config/application.yml'
append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'public/system', 'node_modules'
config/deploy/production.rb
set :stage, :production
set :rails_env, :production
set :branch, 'master'
server 'xxx.xx.xx.xxx', user: 'deploy', roles: %w[web app db]

# nginx
set :nginx_config_name, fetch(:application).to_s

# SSLを設定する場合
set :nginx_server_name, "localhost #{fetch(:application)}.local"
set :nginx_ssl_certificate, "/etc/ssl/certs/#{fetch(:nginx_config_name)}.crt"
set :nginx_ssl_certificate_key, "/etc/ssl/private/#{fetch(:nginx_config_name)}.key"
set :nginx_use_ssl, true

nginx設定

nginxをインストール

sudo apt-get install nginx

因みに、nginxを完全に削除するコマンドは:

sudo apt-get purge nginx nginx-common
sudo apt-get autoremove

Puma設定ファイルをアップロードする

cap production puma:config

もし以下のエラーが発生した場合:

(Backtrace restricted to imported tasks)
cap aborted!
NotImplementedError: OpenSSH keys only supported if ED25519 is available
net-ssh requires the following gems for ed25519 support:
 * ed25519 (>= 1.2, < 2.0)
 * bcrypt_pbkdf (>= 1.0, < 2.0)
See https://github.com/net-ssh/net-ssh/issues/565 for more information
Gem::MissingSpecError : "Could not find 'ed25519' (~> 1.2) among 186 total gem(s)

必要なGemを追加大丈夫だと思います。

Gemfile
group :development do 
  gem 'ed25519'
  gem 'bcrypt_pbkdf'
end

platforms ["x86_64-darwin-20"] みたいなエラーが発生する場合:

remote:        Your bundle only supports platforms ["x86_64-darwin-20"] but your local platform
remote:        is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote:        --add-platform x86_64-linux` and try again.

解決方法:

bundle lock --add-platform x86_64-linux

Puma Nginx設定ファイルをアップロードする

cap production puma:nginx_config

Nginxを再起動する

sudo service nginx restart

デプロイ!

cap production deploy

コマンド一覧

cap --tasks

もしassets precompile が失敗したら、以下の記事に参考してみてください

assets precompileがメモリ不足で失敗する

カスタムRakeタスク

Puma 4 再起動エラーの解決

Puma 4 を使うと、デプロイ後のrestartは上手く動かない場合があるみたいで、以下のファイルを作成すると解決できます。

lib/capistrano/tasks/puma_restart.rake
namespace :puma do
  Rake::Task[:restart].clear_actions

  desc "Overwritten puma:restart task"
  task :restart do
    invoke 'puma:stop'
    invoke 'puma:start'
  end
end

assetsをローカルでコンパイルする

デプロイする時、assetsをコンパイルするのに凄く時間がかかる為、ローカルでコンパイルしておいてからサーバーにアップロードするのがおすすめです。

lib/capistrano/tasks/assets_precompile.rake
namespace :deploy do
  namespace :assets do
    Rake::Task['deploy:assets:precompile'].clear_actions

    desc 'Precompile assets locally and upload to servers'
    task :precompile do
      on roles(fetch(:assets_roles)) do
        # Local assets precompile
        run_locally do
          with rails_env: fetch(:rails_env) do
            execute 'rm -rf public/assets'
            execute 'rm -rf public/packs'
            execute 'bin/rake assets:precompile'
          end
        end

        # Upload to server
        within release_path do
          with rails_env: fetch(:rails_env) do
            old_manifest_path = "#{shared_path}/public/assets/manifest*"
            execute :rm, old_manifest_path if test "[ -f #{old_manifest_path} ]"
            upload!('./public/assets/', "#{shared_path}/public/", recursive: true)
          end
        end

        # Install yarn
        within release_path do
          execute "cd #{release_path} && yarn install"
        end

        # Build webpack
        with rails_env: fetch(:rails_env) do
          within release_path do
            execute "$HOME/.rbenv/shims/ruby #{release_path}/bin/webpack"
          end
        end
      end
    end
  end
end

デプロイの前に自動Gitプッシュ

デプロイの前に毎回Gitにプッシュするのが面倒なので、タスクを作ります。

lib/capistrano/tasks/push_to_github.rake
desc 'Push source code to Github'
task :push_to_github do
  run_locally do
    execute "git push origin #{fetch(:branch)}"
  end
end

before 'deploy:starting', :push_to_github

Back