rails new
で作った簡単なアプリを Capistrano でデプロイする工程をお見せする。
NginxとPumaを連携させ、静的ファイルはNginxから、動的ファイルはPumaから配信するようにする。
- 初めての場合はまずこれをしよう
- 開発環境
- 前提
- Capistrano とはなんなのか?
- アプリをつくる(ローカル)
- GitHub にリポジトリをつくる
- デプロイ用のユーザーをつくる(リモートサーバ)
- Node.js と Yarn はシステムにインストールする(リモートサーバ)
- 必要なgemをインストール(ローカル)
- Capistrano の設定をする(ローカル)
- デプロイしてみる
- master.keyをリモートサーバに転送する
- database.yml(ローカル、リモートサーバ)
- PostgreSQLにデータベースをつくる(リモートサーバ)
- Pumaの設定
- PumaとNginxを連携する
- デプロイに再挑戦
- エラーが出る場合
初めての場合はまずこれをしよう
Capistrano でのデプロイは複雑でむずかしい。
「ぶっちゃけ、Capistrano がどう動くかもあやふや・・・」という場合は、ステップを小さく分けて理解するのがおすすめ。
ローカルのproduction環境でRailsアプリを動かした経験があると、わかりやすくなると思う。
また、最初はRailsアプリではなく、ただのファイルをリモートサーバにデプロイしてみることを強くおすすめする。そのための方法は次の記事で解説している。
開発環境
- リモートサーバ: Debian(さくらVPS使用)
- Webサーバ:nginx/1.16.1
- アプリケーションサーバ:puma
- Rails 6.0.2.2
- Ruby 2.6.5
- Capistrano3
- DB: PostgreSQL 10.11
- Node.js v13.11.0
- Yarn 1.22.4
- ローカルPC:MacOS
※アプリケーションサーバ(以後「APサーバ」)
なぜ PostgreSQL を使うか
練習用なので、Railsデフォルトのsqlite3でもいいのだが、実際に本番で使うことはほぼない。
「どうせやるなら実際の業務で使用されているDBを」と思い、PostgreSQLを選んだ。
前提
次の記事を読み、理解していること。
上記の記事で説明している基本の設定ができているという前提で話を進める。(お手数ですが、ご了承ください)
条件
- リモートサーバがあり、SSHログインできる
- リモートサーバに次のソフトウェアがインストールされている
- PostgreSQL
- Ruby(rbenv使用)
- nginx
- Node.js
- Yarn
- Webサーバ(Nginx)とAPサーバ(puma)の違いを理解している
とくに、WebサーバとAPサーバの違いを理解していることは、この記事を進めるにあたり非常に重要なポイントになる。
まだ理解が微妙という場合は、次の記事がわかりやすいので熟読するべし!
リモートサーバにPostgreSQLがない場合はこちらを参考にインストールしてほしい。
Capistrano とはなんなのか?
Capistrano とは、デプロイに関するいろんな作業を、コマンドひとつで完了させてくれるフレームワークのこと。
Capistrano を使わなくてもデプロイはもちろんできる。
しかし、Capistrano を使えばローカルPCのターミナルでコマンドを1回打つだけで、リモートサーバへのデプロイが終わる。
Capistrano の働きを理解するには、「手動でデプロイする場合」と比べるとわかりやすい。
手動デプロイはおおまかに、次のステップを踏む。
うーむ、いろんな作業があってすこし大変・・・。
ところが、Capistrano を使うと次のように変わる。
Capistranoの場合
- ターミナルで
bundle exec cap production deploy
を打つ - コーヒーでも飲んで待つ☕
- デプロイが終わったらドヤ顔をキメる😁
便利!
あなたもドヤ顔ができるように、さっそく Capistrano でのデプロイを試していこう。
アプリをつくる(ローカル)
適当にRailsアプリを作ろう。DBにはPostgreSQLを使う。
rails new capistrano_psql -d postgresql cd capistrano_psql
scaffold で適当なプログラムをつくる
とりあえず、Task アプリをつくる。
bin/rails generate scaffold Task title:string memo:text
次に、ルートURLにアクセスしたらアプリが表示されるようにする。
routes.rb
Rails.application.routes.draw do resources :tasks root "tasks#index" end
ローカルで動くか確かめよう。
bin/rails db:create bin/rails db:migrate bin/rails s
ローカルでサーバを起動したら、localhost:3000
へアクセス。
localhost:3000
こんな画面が表示されることを確認する。
GitHub にリポジトリをつくる
(ローカルでの作業)
git init echo "# はじめてのCapistrano" > README.md git add . git commit -m "first commit" # ここでGitHubリポジトリ作成しておく git remote add origin git@github.com:GitHubユーザーネーム/リポジトリ名.git git push -u origin master
関連:git init から git push までの流れ - オランウータンとぼく
今回は練習なので、masterブランチ上で作業をする。(もちろん、ブランチを切りたい方はご自由に!)
デプロイ用のユーザーをつくる(リモートサーバ)
次の記事を参考に、デプロイ用のユーザーをリモートサーバにつくる。
「Capistrano 超初心者がなんとなく理解するために Rails アプリではなくファイルをリモートサーバにデプロイしてみる」の記事をやっていればあらたに設定する必要はないが、もし目を通していない場合、上記記事の
- リモートサーバにデプロイ専用ユーザをつくる
- /var/www があるか確認する
- リモートサーバに公開鍵を設置
- ssh-agentの設定
をおこない、こちらの記事に戻ってきてほしい。 (リモートサーバ上で作業する点に注意!)
今後、リモートサーバへはdeployユーザでログインする。
デプロイユーザーを PostgreSQL のロールに追加(リモートサーバ)
いま作ったdeployユーザーを、PostgreSQLのロール(ユーザー)に追加する。
このとき、パスワードも同時に設定するオプション(-P
)もつける。パスワードは自由に設定し、忘れないようにメモしておこう。
# パスワードつきでdeployロールを作る sudo createuser -d -P deploy
Node.js と Yarn はシステムにインストールする(リモートサーバ)
アセットのプリコンパイルをするため、Node.jsとYarnが必要になる。
個人的に2日くらいハマったポイント😱
リモートサーバにanyenvを使い、nodenvをインストールしたところ、アセットのプリコンパイル時にエラーが出た。
関連:Capistrano3 デプロイ時に Yarn requires Node.js 4.0 or higher to be installed エラーで落ちる - オランウータンとぼく
「ちゃんとインストールしてるのに、なぜ!?」とイライラしたが、システムにインストールすると解決した。
よってこれらをインストール。
# nodejsをインストール sudo apt install -y nodejs # yarnをインストール sudo apt-get update && sudo apt-get install yarn
必要なgemをインストール(ローカル)
ローカルのアプリのディレクトリにもどろう。
ようやくCapistranoフレームワークや、いくつかのプラグインをインストールする。
Capistranoを使うには、まずcapistrano
を入れる。さらに、capistranoを便利にしてくれるプラグインも使う。
ここらへんは人によって変わるが、今回は「デプロイの手順を学ぶ」のが目的なため、基本的なプラグインしか使わない。
Gemfile
# 以下を追記 group :development do gem 'capistrano' gem 'capistrano-safe-deploy-to' gem 'capistrano-rbenv' gem 'capistrano-bundler' gem 'capistrano-rails' gem 'capistrano3-puma' end
それぞれを説明する。
- capistrano
- capistrano-safe-deploy-to
- デプロイ先のサーバに確実にディレクトリを作ってくれる
- capistrano-plugins/capistrano-safe-deploy-to
- capistrano-rbenv
- デプロイ先のサーバで、rbenv配下のコマンドを実行できるようにしてくれる
- capistrano-bundler
- デプロイ先のサーバで
bundle install
するとき助けてくれる
- デプロイ先のサーバで
- capistrano-rails
- Railsアプリをデプロイするのに役立つ
- capistrano3-puma
- puma関連の設定ができる
- デプロイ先のpuma.rbやnginxの設定をしてくれる
これを今読んでもわかりづらいと思う。なのでとにかく今は先に進んで、デプロイに成功してから読み直そう。
gemをbundle installする。
bundle install
Capistrano の設定をする(ローカル)
以下のコマンドでCapistranoの設定ファイルを作成できる。
bundle exec cap install # 結果 mkdir -p config/deploy create config/deploy.rb create config/deploy/staging.rb create config/deploy/production.rb mkdir -p lib/capistrano/tasks create Capfile Capified
いろんなファイルが生成される。
それぞれの使い方
- Capfile: Capistranoに関する設定
- deploy.rb: 基本設定
- staging.rb: ステージング環境に関する設定
- production.rb: production環境に関する設定
基本的には、
- インストールしたCapistranoのプラグインをCapfileにrequireで記述し、使えるようにする
- deploy.rbで共通の設定を書く
- config/deploy/*.rbに個別の設定を書く
という流れで設定する。
Capfile
もとの記述はすべて消し、以下を追記する。
require "capistrano/setup" require "capistrano/deploy" require "capistrano/scm/git" install_plugin Capistrano::SCM::Git require "capistrano/safe_deploy_to" require "capistrano/rbenv" require "capistrano/bundler" require "capistrano/rails/assets" # アセットをプリコンパイルするため require "capistrano/rails/migrations" # マイグレーションをするため require "capistrano/puma" install_plugin Capistrano::Puma # CapistranoとPumaを連携 install_plugin Capistrano::Puma::Nginx # PumaとNginxを連携 # Load custom tasks from `lib/capistrano/tasks` if you have any defined Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
Gemfileにインストールしたgemをここで使えるようにしている。
config/deploy.rb
もとの記述はすべて消し、以下を追記。
# config valid for current version and patch releases of Capistrano lock "~> 3.12.1" # アプリ名(なんでもOK) set :application, "capistrano_psql" # GitHubリポジトリ情報 set :repo_url, "git@github.ユーザーネーム/capistrano_psql.git" # ユーザーはdeployにする set :user, "deploy" # rbenvをユーザーレベルでインストール set :rbenv_type, :user # rubyのバージョンを指定 set :rbenv_ruby, File.read('.ruby-version').strip set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec" # 並列数 set :bundle_jobs, 2 # リリース間で共有するリソースのファイルパスを書く append :linked_files, "config/master.key" # 各リリースが共通で読み込むディレクトリを設定する append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", '.bundle'
- アプリ名はディレクトリ名を書いてもいいし、なんでもいい
repo_url
はリポジトリURLのことで、GitHubで確認できる- リモートサーバで設定したdeployユーザーを設定
- リモートサーバで使うRubyの設定
append :linked_dirs
では、各リリースが共通で読み込むディレクトリを設定するappend :linked_files
では、各リリースが共通で読み込むファイルを設定する
「え?全然わかんないんだけど・・・」と思うかも知れない。
安心してほしい。最初は何がなんだかわからないかもしれないが、デプロイを経験すると、「あ〜こういうことだったのか」となんとなく理解する(と思う)。
もっともわかりにくいのは、append
だと思う。
Capistranoでデプロイをすると、アプリを「リリース」という単位で管理するようになる。
リリースが作られるとき、たくさんのファイルが新たに用意されるのだが、config/master.key
など、1回読み込めたらいいファイルもある。各リリースに、これらの同じファイルを配置するのは非効率だ。
よって、どこか一箇所に保管して、各リリースで共通して読み込むようにする。
それを、appendで指定することができる。appendで指定したディレクトリやファイルは、デプロイ後のshared
ディレクトリ配下に設置される。そして、各リリースからはシンボリックリンクで参照されるようになる。
今はわからなくても、デプロイしたら「あ〜、そういうことだったのか」とわかるはず。なので今は前に進もう。
config/deploy/production.rb
もとの記述はすべて消し、以下を追記。
# サーバの設定 server "サーバのIPアドレス", user: "deploy", roles: %w{web db app} # ssh接続設定 set :ssh_options, { user: fetch(:user), port: ポート番号, keys: %w(~/.ssh/id_rsa), forward_agent: true, auth_methods: %w[publickey] }
- IPアドレスには、契約しているリモートサーバ(今回はさくらVPS)に割り当てられたIPアドレスを書く
- 接続時のポート番号を変更している場合、それも書く
keys:
の%w(~/.ssh/id_rsa)
には、自分が秘密鍵を設置しているファイルパスを記入forward_agent: true
を設定することで、リモートサーバからGitHubへSSH接続をしてリポジトリをクローンできるようになる
user: fetch(:user)
は、実際には以下と同じ意味になる。
# deployユーザをfetchで取得しているだけ user: "deploy"
Railsアプリをデプロイした後は、serverに指定したIPアドレスにアクセスすることで、アプリが表示される。
独自ドメインを割り当てたい場合
練習用ならIPアドレスだけでもいいが、自分で取得した独自ドメインにアクセスして表示できるようにしたい場合、IPアドレスの部分にドメインを書く。
config/deploy/production.rb
server "hoge.com", user: "deploy", roles: %w{web db app}
これで、デプロイ成功後にhoge.com
へアクセスすると、自分が作ったRailsアプリが見れる。
githubへpushする(ローカル)
ひとまず、今までの設定をGitHubにpushしておこう。
git add . git commit -m "capistrano-test" git push origin master
デプロイしてみる
本番環境にデプロイしてみよう。
# 本番環境にデプロイする bundle exec cap production deploy
※ちなみに、ステージング環境にデプロイする場合はこうなる。
# ステージング環境にデプロイする bundle exec cap staging deploy
コマンドを打っただろうか? おそらく、「master.keyを読み込めてねぇよ!」的なエラーで止まるはずだ。 (騙したみたいでごめんなさい💦)
master.keyをリモートサーバに転送する
本番環境でRailsアプリを動かす場合、master.key
が必要になる。
しかし、今のリモートサーバにはmaster.key
がない。デプロイをするとき、リモートサーバはGitHubからコードの変更をクローンするが、そこにはmaster.key
は含まれていない。
なぜなら、 .gitignoreファイルにはmaster.key
が記述されており、GitHub上にmaster.key
がアップされないから。rails new
した場合、.gitignoreにはデフォルトでmaster.key
が記述されている。
よって、リモートサーバに手動でmaster.key
を設置する。(おそらく、方法はいろいろあると思うが今回はこの方法でやる)
ローカルからscp
コマンドを使ってmaster.key
を転送する
設置する手段としては、おもに次の2つ。
- 手動でリモートサーバに入り、
master.key
ファイルを作ってペースト - ローカルから
scp
コマンドを使って転送
scpコマンドを使ったほうが圧倒的にラクなので、そうしよう。
ローカルの今回作成しているアプリのディレクトリへ移動し、次のコマンドを叩く。
scp -P ポート番号 config/master.key deploy@リモートサーバのIPアドレス:/var/www/capistrano_psql/shared/config/master.key
VPSのポート番号を変更しているなら、-P
オプションでポート番号を指定する。Pは大文字な点に注意。
scpコマンドがうまくできない場合
うまくできない場合、無理に使う必要はない。リモートサーバへ入って手動でファイルを作成すればよい。
#リモートサーバへログインし、アプリ名のディレクトリへ移動 cd /var/www/capistrano_psql/ # ls でshared/configがあるか確認 ls # あれば移動 cd shared/config # なければつくる mkdir -p shared/config/ # config下にmaster.keyファイルを作成し、ローカルのmaster.keyの内容をコピペ sudo vim master.key
database.yml(ローカル、リモートサーバ)
本番環境でDBを動かすには、ユーザーネームとパスワードが必要になる。ユーザーネームは、さきほど作ったdeployにする。PostgreSQLでdeployロールを作成したとき、パスワードも設定した。そのパスワードをリモートサーバ内の環境変数に設定する。
config/database.yml
production: <<: *default database: capistrano_psql_production username: deploy # 環境変数で読み込む password: <%= ENV['CAPISTRANO_PSQL_PASSWORD'] %>
リモートサーバにログインし、環境変数を設定する。
# .bash_profileを開く sudo vim ~/.bash_profile # bash_profileに環境変数を書き込む export CAPISTRANO_PSQL_PASSWORD=パスワード # 再読み込み source ~/.bash_profile
これで、CAPISTRANO_PSQL_PASSWORD
という環境変数に設定したパスワードを、database.ymlで読み込めるようになる。
PostgreSQLにデータベースをつくる(リモートサーバ)
本番環境で使うデータベースを作成するため。deployユーザでリモートサーバへログイン。
データベース名は、database.ymlに書いたのと同じ名前にする。
$ createdb capistrano_psql_production
データベースの確認をするには、psqlを起動し、\l
を打つ。
$ psql postgres postgres=# \l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges ----------------------------+----------+----------+-------------+-------------+----------------------- capistrano_psql_production | deploy | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
ちなみに、今回は手動でデータベースを作成したり、環境変数で読み込ませたりしているが、Capistranoのプラグインを使えばもっと簡単に設定できる。
しかし、基本的な流れを確認するため、この記事では手動でやっている。
Pumaの設定
Capfileで
require 'capistrano/puma' install_plugin Capistrano::Puma
のように設定していると、CapistranoでPumaを動かせるようになる。
以下のコマンドで、Pumaの設定ファイルを作成してくれるので入力しよう。
bundle exec cap production puma:config
これでPumaの設定ファイルができた。ローカルからコマンドを打って、Pumaを起動・停止することができるようになった。
ためしに、Pumaを起動してみよう。
# Pumaを起動 bundle exec cap production puma:start # Pumaのステータスを確認 bundle exec cap production puma:status # Pumaを停止 bundle exec cap production puma:stop
Pumaの起動が確認できたら、停止せずにそのままで次へ進もう。
PumaとNginxを連携する
あとはPumaとNginxの連携の設定をしたら終わり。頑張ろう! (なお、独自ドメインをSSLで表示させたい場合、ここを飛ばして次の「独自ドメインをSSLで表示させたい場合」を参考にしよう)
Capfile
install_plugin Capistrano::Puma::Nginx
これがあることで、PumaとNginxの連携を可能にしている。
「練習用だから、ひとまず今動くことを確認できたらそれでいい。SSLじゃなくていい。」という場合、次のコマンドを打つだけでいい。
bundle exec cap production puma:nginx_config
これでPumaとNginxの連携が自動でおこなわれ、Nginxの設定ファイルが生成される。
Nginxを設定したあとは、nginx -t
で設定ファイルに間違いがないかどうか確認し、再起動させよう。
# 設定ファイルが正しいかチェック $ sudo nginx -t # 起動 $ sudo nginx
独自ドメインをSSLで表示させたい場合
練習用に取得した独自ドメインをSSLで表示したい場合、以下の設定をしよう。
今回の場合、Let's EncryptでSSL対応をしている。すでにSSL対応済みと想定して進める。まだSSL対応をしていない場合、次のページが参考になる。
参考
config/deploy/production.rb に以下を追記する。
# nginx set :nginx_config_name, "#{fetch(:application)}" set :nginx_server_name, "IPアドレス or ドメイン" set :nginx_use_ssl, true set :nginx_ssl_certificate, "/etc/letsencrypt/live/ドメイン/fullchain.pem" set :nginx_ssl_certificate_key, "/etc/letsencrypt/live/ドメイン/privkey.pem"
次のコマンドでNginxの設定ファイルを作成する。
# Nginxの設定ファイルを作成 bundle exec cap production puma:nginx_setup
これでCapistranoが自動でNginxの設定ファイルを作成してくれる。
具体的には、/etc/nginx/sites-availableに設定ファイルが作成され、/etc/nginx/sites-enabledにシンボリックリンクが貼られる。
最後に、Nginxの設定をチェックし、起動しよう。
# 設定ファイルが正しいかチェック $ sudo nginx -t # 起動 $ sudo nginx
これでようやく準備完了!
デプロイに再挑戦
デプロイコマンドを打とう。
bundle exec cap production deploy
おそらく、今回はエラーもなく、デプロイが完成するはず。
設定したIPアドレスもしくはドメインにアクセスしてみよう。表示されていたら、Capistranoでのデプロイは成功です!やったね!
エラーが出る場合
大丈夫、みんなハマる。でも、絶対できる。
私は5日ほどハマり続け、あらゆるエラーを経験した。エラーに関する記事を残しているので、参考になれば!