Ubuntu16.04 + Ruby on Rails 5.1 + Puma + Nginx + Capistranoでstaging環境を構築
はじめに
Railsアプリケーションを本番環境やstaging環境に反映させたいときに、手軽にデプロイできるようにすることは必須と言えます。
この記事ではCapistranoを使用して、staging環境にcapコマンドでデプロイできるようにするまでを紹介しています。
一度設定を行ってしまえば、今後はローカルのターミナルで
$ bundle exec cap staging deploy
を叩くだけでremoteのmasterブランチがstaging環境に反映されます。
また、ブランチを指定したデプロイも可能です。stagingブランチをデプロイしたい場合
$ bundle exec cap staging deploy BRANCH=staging
のように指定できます。
Rails
secrets.ymlの設定
config/secrets.yml
staging:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
secret_key_baseは環境変数で設定する想定なので、ここには記述しません。
database.ymlの設定
config/database.yml
staging:
<<: *default
database: sample_app_staging
username: <%= ENV["SAMPLE_APP_DATABASE_USERNAME"] %>
password: <%= ENV["SAMPLE_APP_DATABASE_PASSWORD"] %>
こちらも同じく環境変数で設定します。
environtemsにファイルを作成
とりあえずconfig/production.rbをコピーします。
$ cp config/production.rb config/staging.rb
SSH
deployユーザーを作成します。ここからサーバ側の設定になります。
$ ssh root@XX.XX.XX.XX
$ adduser deploy
$ gpasswd -a deploy sudo
$ mkdir /home/deploy/.ssh
$ cp /root/.ssh/authorized_keys /home/deploy/.ssh/authorized_keys
$ chmod 700 /home/deploy/.ssh/authorized_keys
$ chown -R deploy:deploy /home/deploy/.ssh/
$ gpasswd -a deploy root
$ ssh deploy@XX.XX.XX.XX
ローカルからdeployユーザーとしてsshログインできればOKです。
sudo
パスワードなしでsudoできるようにします。
$ sudo visudo
# 以下のように編集
-%sudo ALL=(ALL:ALL) ALL
+%sudo ALL=(ALL:ALL) NOPASSWD:ALL
/var/www/作成
アプリケーションを配置するフォルダを作成します。
$ mkdir /var/www
$ sudo chown deploy:deploy /var/www
TimeZone
TimeZoneをTokyoに設定します。
$ sudo ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ date
Ruby
rbenvを使用してrubyをインストールします。
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install git build-essential libssl-dev
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ vim .profile
# 以下追記
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
追記内容を反映させます。
$ source ~/.profile
ruby2.4.1をインストールします。
$ rbenv install --list
$ rbenv install 2.4.1
$ rbenv rehash
$ rbenv global 2.4.1
$ ruby -v
$ gem install bundler --no-ri --no-rdoc
# nodejsをいれておく
$ sudo apt-get install nodejs
2.4.1のインストールで失敗しました。
Downloading ruby-2.4.1.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.1.tar.bz2
Installing ruby-2.4.1...
BUILD FAILED (Ubuntu 16.04 using ruby-build 20170523-25-g476d09b)
Inspect or clean up the working tree at /tmp/ruby-build.20170725024731.10932
Results logged to /tmp/ruby-build.20170725024731.10932.log
Last 10 log lines:
installing rdoc: /home/deploy/.rbenv/versions/2.4.1/share/ri/2.4.0/system
installing capi-docs: /home/deploy/.rbenv/versions/2.4.1/share/doc/ruby
The Ruby readline extension was not compiled.
ERROR: Ruby install aborted due to missing extensions
Try running `yum install -y readline-devel` to fetch missing dependencies.
Configure options used:
--prefix=/home/deploy/.rbenv/versions/2.4.1
LDFLAGS=-L/home/deploy/.rbenv/versions/2.4.1/lib
CPPFLAGS=-I/home/deploy/.rbenv/versions/2.4.1/include
https://gist.github.com/urouro/532f24ad6a52a96a921e
こちらを参考にインストールしました。
Nginx
公式を参考にインストールします。
$ curl http://nginx.org/keys/nginx_signing.key | sudo apt-key add -
$ sudo sh -c "echo 'deb http://nginx.org/packages/ubuntu/ xenial nginx' >> /etc/apt/sources.list"
$ sudo sh -c "echo 'deb-src http://nginx.org/packages/ubuntu/ xenial nginx' >> /etc/apt/sources.list"
$ sudo apt-get update
$ sudo apt-get install nginx
環境変数
環境変数の設定を行います。
$ sudo vim /etc/environment
# 以下記述
SECRET_KEY_BASE=""
sample_app_DATABASE_USERNAME=""
sample_app_DATABASE_PASSWORD=""
Capistrano
ここからはローカル側です。
Gemfile
group :development do
gem "capistrano", require: false
gem "capistrano-rails", require: false
gem "capistrano-bundler", require: false
gem "capistrano3-puma", require: false
gem "capistrano-rbenv", require: false
end
Gemfileに書いたら、ローカルで以下を実行します。
$ bundle install --path vendor/bundle
$ bundle exec cap install
関連ファイルが自動生成されるので、以下を記述します。
Capfile
require "capistrano/setup"
require "capistrano/deploy"
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
require "capistrano/rails"
require "capistrano/rbenv"
require "capistrano/bundler"
require "capistrano/puma"
install_plugin Capistrano::Puma
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
config/deploy.rb
# config valid only for current version of Capistrano
lock "3.8.2"
set :application, "sample-app"
set :repo_url, "git@github.com:your_account/sample-app.git"
set :user, "deploy"
set :ssh_options, {
forward_agent: true,
user: fetch(:user),
keys: %w(~/.ssh/id_rsa)
}
set :deploy_to, "/var/www/#{fetch(:application)}"
set :deploy_via, :remote_cache
set :puma_threads, [4, 16]
set :puma_workers, 0
set :pty, true
set :use_sudo, false
set :puma_bind, "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state, "#{shared_path}/tmp/pids/puma.state"
set :puma_pid, "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{release_path}/log/puma.error.log"
set :puma_error_log, "#{release_path}/log/puma.access.log"
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true
set :rbenv_ruby, '2.4.1'
set :linked_dirs, fetch(:linked_dirs, []).push(
'log',
'tmp/pids',
'tmp/cache',
'tmp/sockets',
'vendor/bundle',
'public/system',
'public/uploads'
)
set :linked_files, fetch(:linked_files, []).push(
'config/database.yml',
'config/secrets.yml'
)
namespace :puma do
desc 'Create Directories for Puma Pids and Socket'
task :make_dirs do
on roles(:app) do
execute "mkdir #{shared_path}/tmp/sockets -p"
execute "mkdir #{shared_path}/tmp/pids -p"
end
end
before :start, :make_dirs
end
namespace :deploy do
desc "Make sure local git is in sync with remote."
task :check_revision do
on roles(:app) do
unless `git rev-parse HEAD` == `git rev-parse origin/#{fetch(:branch)}`
puts "WARNING: HEAD is not the same as origin/#{fetch(:branch)}"
puts "Run `git push origin HEAD` to sync changes."
exit
end
end
end
desc 'Initial Deploy'
task :initial do
on roles(:app) do
before 'deploy:restart', 'puma:start'
invoke 'deploy'
end
end
desc 'Restart application'
task :restart do
on roles(:app), in: :sequence, wait: 5 do
invoke 'puma:restart'
end
end
desc '必要なファイルをアップロード'
task :upload do
on roles(:app) do |host|
if test "[ ! -d #{shared_path}/config ]"
execute "mkdir -p #{shared_path}/config"
end
upload!('config/database.yml', "#{shared_path}/config/database.yml")
upload!('config/secrets.yml', "#{shared_path}/config/secrets.yml")
end
end
before :starting, :check_revision
after :finishing, :compile_assets
after :finishing, :cleanup
end
config/deploy/staging.rb
server "XX.XX.XX.XX", user: "deploy", roles: %w{app db web}, primary: true
set :branch, ENV["BRANCH"] || "master"
set :stage, :staging
set :rails_env, :staging
事前にgithubなど、登録しているリポジトリに自分の公開鍵id_rsa.pubを登録してから、ローカルで以下を実行します。
$ ssh-add ~/.ssh/id_rsa
$ bundle exec cap staging deploy:upload
$ bundle exec cap staging deploy:initial
mysqlで失敗したのでサーバーにログインしてインストールします。
$ sudo apt-get install libmysqlclient-dev
mysqlのsocketが違うと怒られたので指定します。
config/database.yml
staging:
socket: /var/run/mysqld/mysqld.sock
databaseが作られていなかったのでサーバー内に入って作成します。
mysql> CREATE DATABASE sample_app_staging;
もう一度実行します。
$ bundle exec cap staging deploy:initial
全て完了すると
- git clone
- bundle install
- rake assets:precompile
- rake db:migrate
- pume起動
などが全て自動で完了されています。
Nginx設定
これで最後です。サーバに入って、Nginxの設定を行います。
$ sudo vi /etc/nginx/conf.d/sample-app.conf
# 以下記述
upstream sample-app {
server unix:/var/www/sample-app/shared/tmp/sockets/sample-app-puma.sock fail_timeout=0;
}
server {
listen 80;
server_name XX.XX.XX.XX;
root /var/www/sample-app/current/public;
location ~ ^/assets/ {
root /var/www/sample-app/current/public;
}
try_files $uri/index.html $uri @sample-app;
location / {
proxy_pass http://sample-app;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
Nginxを起動します。
$ sudo service nginx configtest
$ sudo service nginx start
これで、http://XX.XX.XX.XX/ にアクセスすることでstaging環境が確認できるようになります。
Capistranoの構成
サーバー内では /var/www/sample-app/current に現在のrails環境が展開されています。
その実態は /var/www/sample-app/releases 配下に展開されている中から最新のものに向けてシンボリックリンクが貼られています。
おわりに
Capistranoは自前タスクを追加することができるので、様々にカスタマイズできます。また、コマンド1つでデプロイが可能なので、CIツールとの相性も良いです。
ぜひ使ってみてください。
私が所属している株式会社ACESでは、Deep Learningを用いた画像認識技術を中心に、APIによるアルゴリズムパッケージの提供や、共同研究開発を行なっています。特に、ヒトの認識・解析に強みを持って研究開発を行っておりますので、ご興味のある方は、ぜひお問い合わせください!
【詳細・お問い合わせはこちら↓】
◆画像認識アルゴリズム「SHARON」について
ヒトの行動や感情の認識、モノの検知などを実現する画像認識アルゴリズムを開発しています。スポーツにおけるパフォーマンス分析やマーケティングにおけるヒトの心の動きの可視化、ストレスなどの可視化による健康状態の管理を始めとするAIアルゴリズムを提供しています。
この記事が気に入ったらサポートをしてみませんか?