Capistrano を使用した EC2 へのデプロイ作業メモ
まえおき
先日 Rails のデプロイ作業を行なったので、その時のメモ。Capistrano の設定とか忘れがちなのでメモしとく
前提条件
- EC2, RDS(postgress), セキュリティグループなどの諸々の環境は構築済み
- Nginx は使わない
今回使用する各環境
OS: Amazon Linux2
DB: RDS (Postgres)
Rails: 6.1.3
Ruby: 3.0.1
Capistrano:
- capistrano: 3.16
- capistrano-rails: 1.6
- capistrano3-puma: 5.0
- capistrano-rbenv: 2.2
EC2
ユーザー作成
- ec2-userでログイン
sudo adduser deploy
-
sudo visudo
で以下を記述root ALL=(ALL) ALL # 上記の行の下に、以下を追記 # デプロイ時の puma 再起動時にパスワードなしで実行できるようにする deploy ALL=NOPASSWD: /bin/systemctl
sudo su - deploy
mkdir .ssh -m 700
-
vim .ssh/authorized_keys
で ssh接続に使う公開鍵を登録 chmod 600 .ssh/authorized_keys
これで deploy ユーザーでログインできるようになる。
各種必要なプラグインのインストール
postgresql-devel の部分は使用するDB毎に必要なものを入れる
$ sudo yum install -y git gcc openssl-devel readline-devel zlib-devel gcc-c++ postgresql-devel
rbenv
# 以下は必ずデプロイ時のユーザー(例: deploy, ec2-user)で行うこと
$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
$ mkdir -p "$(rbenv root)"/plugins
$ git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
ruby
インストールする ruby バージョンは環境毎に変更すること
rbenv install 3.0.1
rbenv global 3.0.1
rbenv rehash
rbenv versions
Capistrano
前提条件
- 上記に書いてある EC2 の設定を終えていること
-
master.key
,credentials.yml.enc
を作成済であること- まだの場合はローカルで
bin/rails credentials:edit
を実行
- まだの場合はローカルで
-
master.key
,database.yml
を/home/deploy/アプリ名/shared/config/
においてあること
導入
-
Gemfile 更新
Gemfile--- 省略 --- group :development do gem "capistrano", "~> 3.16", require: false gem "capistrano-rails", "~> 1.6", require: false gem 'capistrano3-puma', "~> 5.0", require: false gem 'capistrano-rbenv', '~> 2.2', require: false end --- 省略 ---
-
bundle install
-
bundle exec cap install
で必要なファイルを作成し、設定を書き換える。以下設定例Capfile# Load DSL and set up stages require "capistrano/setup" # Include default deployment tasks require "capistrano/deploy" # Load the SCM plugin appropriate to your project: # # require "capistrano/scm/hg" # install_plugin Capistrano::SCM::Hg # or # require "capistrano/scm/svn" # install_plugin Capistrano::SCM::Svn # or require "capistrano/scm/git" require 'capistrano/puma' # install_plugin Capistrano::Puma::Systemd # Include tasks from other gems included in your Gemfile # # For documentation on these, see for example: # # https://github.com/capistrano/rvm # https://github.com/capistrano/rbenv # https://github.com/capistrano/chruby # https://github.com/capistrano/bundler # https://github.com/capistrano/rails # https://github.com/capistrano/passenger # # require "capistrano/rvm" # require "capistrano/chruby" # require "capistrano/passenger" # require "capistrano/rails/assets" require "capistrano/rbenv" require "capistrano/bundler" require "capistrano/rails/migrations" install_plugin Capistrano::SCM::Git install_plugin Capistrano::Puma install_plugin Capistrano::Puma::Systemd # Pumaをデプロイ時に再起動 # Load custom tasks from `lib/capistrano/tasks` if you have any defined Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
config/deploy.rb# config valid for current version and patch releases of Capistrano lock "~> 3.16.0" # アプリ名を記述 set :application, "test_app" # クローンするリモートリポジトリを記述 set :repo_url, "git@xxxxxxxx/xxx.git" # Default branch is :master # ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp # set :branch, :main # Default deploy_to directory is /var/www/my_app_name # デプロイ先を記述 set :deploy_to, "/home/deploy/test_app" # Default value for :scm is :git # set :scm, :git # Default value for :format is :airbrussh. set :format, :airbrussh set :log_level, :debug # You can configure the Airbrussh format using :format_options. # These are the defaults. # set :format_options, command_output: true, log_file: "log/capistrano.log", color: :auto, truncate: :auto # Default value for :pty is false set :pty, true # Default value for :linked_files is [] # デプロイ対象から外すファイルを記述 append :linked_files, "config/master.key", "config/database.yml" # Default value for linked_dirs is [] # デプロイ対象から外すディレクトリを記述 append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system", 'vender/bundle' # Default value for default_env is {} set :default_env, { path: "/opt/ruby/bin:$PATH" } # Default value for local_user is ENV['USER'] # set :local_user, -> { `git config user.name`.chomp } # Default value for keep_releases is 5 set :keep_releases, 5 # Uncomment the following to require manually verifying the host key before first deploy. # set :ssh_options, verify_host_key: :secure # rbenv set :rbenv_type, :user set :rbenv_ruby, '3.0.1' # 以下二つは正しく設定しないと gem を読み込めなくなるかも set :rbenv_path, '/home/ユーザー名(例: deploy, ec2-user .etc)/.rbenv' set :bundle_path, -> { shared_path.join('vendor/bundle') }
config/deploy/production.rbserver "デプロイ先のドメイン or ip", roles: %w{app web db} set :rails_env, "production" set :app_env, "production" set :branch, :main set :puma_service_unit_env_file, '/etc/environment' set :ssh_options, { user: 'deploy', # rbenv_path で設定したユーザー名と合わせる keys: %w(/home/user_name/.ssh/id_rsa), # ssh 接続に使う秘密鍵のパスを記述 forward_agent: true, auth_methods: %w(publickey) }
-
bundle exec cap production puma:config
-
bundle exec cap production puma:systemd:config puma:systemd:enable
を実行し、pumaの自動起動設定用ファイルが/etc/systemd/system
配下に作られる。デフォルトだと多分うまくいかないので、以下のように書き換える
4. sudo 権限で弾かれる場合はこの記事を参考に、一時的にパスワードなしで実行できるようにする。(やり方は雑だけど)もちろん、終わったら元に戻す。/etc/systemd/system/puma_test_app_production.service[Unit] Description=Puma HTTP Server for test_app (production) After=network.target [Service] Type=simple User=デプロイ先のユーザー(例: ec2-user, deploy) WorkingDirectory=/home/deploy/test_app/current ExecStart=/home/Userと同じ名前/.rbenv/bin/rbenv exec bundle exec puma -C /home/deploy/test_app/shared/puma.rb ExecReload=/bin/kill -TSTP $MAINPID StandardOutput=append:/home/deploy/test_app/shared/log/puma_access.log StandardError=append:/home/deploy/test_app/shared/log/puma_error.log EnvironmentFile=/etc/environment Restart=always RestartSec=1 SyslogIdentifier=puma [Install] WantedBy=multi-user.target
-
bundle exec cap production deploy:check
-
bundle exec cap production deploy
Tips
-
デプロイ中に以下のような警告が出た場合は、EC2 内で
sudo systemctl daemon-reload
を実行する。(理由)00:15 puma:restart 01 sudo /bin/systemctl restart puma_test_app_production 01 Warning: puma_test_app_production.service changed on disk. Run 'systemctl daemon-reload' to reload units. ✔ 01 deploy@3.113.245.65 0.151s
-
gem 'capistrano3-puma', '~> 5.0', require: false
のような書き方をしていると、bundle exec cap production puma:status
のようなコマンドが使えなくなる。ただ環境が整えば打てる必要はないので、require つけてもいいと思う。 -
デプロイ時にpuma を再起動できるように Capfile に
install_plugin Capistrano::Puma::Daemon
追加したが、invalid option: --daemon (OptionParser::InvalidOption)
となってしまった。どうも README に書かれているように、5系から daemon は廃止になってしまったらしい。 -
puma の ログファイルが作られない場合は
touch /home/deploy/test_app/shared/log/puma_access.log
,touch /home/deploy/test_app/shared/log/puma_error.log
で作成する
感想
普通に苦戦した。特にcapistrano。何回やっても全然覚えられない。ただその分学びは多かった気がする。知らんけど。
参考資料
Discussion