Dockerでサーバー立てる事が多くなってきたので、あまり使わなくなってきましたが、
サービス立ち上げ当初はスケールするか解らないので、安価なサーバーでスタートしたいですね。(スモールスタート)
利用が増えてきてからECS等でDockerを使うまでの過渡期にCapistranoを使うと
安全で簡単にデプロイできるようになります。
pull方式だと、SSHログインして、pullして、Unicorn再起動。手間ですね。切り戻しも。

サーバー側の設定が完了している前提になります。
CentOS7にCapistranoでデプロイしたRailsアプリが動く環境を作る

capコマンドメモ

SSHで繋げなくても色々できるので便利かも。

タスク確認
% cap -T
cap bundler:clean                  # Remove unused gems installed by bundler
cap bundler:config                 # Configure the Bundler environment for the release so that subequent
cap bundler:install                # Install the current Bundler environment
cap bundler:map_bins               # Maps all binaries to use `bundle exec` by default
cap deploy                         # Deploy a new release
cap deploy:check                   # Check required files and directories exist
cap deploy:check:directories       # Check shared and release directories exist
cap deploy:check:linked_dirs       # Check directories to be linked exist in shared
cap deploy:check:linked_files      # Check files to be linked exist in shared
cap deploy:check:make_linked_dirs  # Check directories of files to be linked exist in shared
cap deploy:cleanup                 # Clean up old releases
cap deploy:cleanup_assets          # Cleanup expired assets
cap deploy:cleanup_rollback        # Remove and archive rolled-back release
cap deploy:clobber_assets          # Clobber assets
cap deploy:compile_assets          # Compile assets
cap deploy:finished                # Finished
cap deploy:finishing               # Finish the deployment, clean up server(s)
cap deploy:finishing_rollback      # Finish the rollback, clean up server(s)
cap deploy:log_revision            # Log details of the deploy
cap deploy:migrate                 # Runs rake db:migrate if migrations are set
cap deploy:migrating               # Runs rake db:migrate
cap deploy:normalize_assets        # Normalize asset timestamps
cap deploy:published               # Published
cap deploy:publishing              # Publish the release
cap deploy:revert_release          # Revert to previous release timestamp
cap deploy:reverted                # Reverted
cap deploy:reverting               # Revert server(s) to previous release
cap deploy:rollback                # Rollback to previous release
cap deploy:rollback_assets         # Rollback assets
cap deploy:seed                    # Runs rake db:seed
cap deploy:set_current_revision    # Place a REVISION file with the current revision SHA in the current release path
cap deploy:started                 # Started
cap deploy:starting                # Start a deployment, make sure server(s) ready
cap deploy:symlink:linked_dirs     # Symlink linked directories
cap deploy:symlink:linked_files    # Symlink linked files
cap deploy:symlink:release         # Symlink release to current
cap deploy:symlink:robots_txt      # Runs ln -sfn public/ public/robots.txt
cap deploy:symlink:shared          # Symlink files and directories from shared to release
cap deploy:updated                 # Updated
cap deploy:updating                # Update server(s) by setting up a new release
cap doctor                         # Display a Capistrano troubleshooting report (all doctor: tasks)
cap doctor:environment             # Display Ruby environment details
cap doctor:gems                    # Display Capistrano gem versions
cap doctor:servers                 # Display the effective servers configuration
cap doctor:variables               # Display the values of all Capistrano variables
cap git:check                      # Check that the repository is reachable
cap git:clone                      # Clone the repo to the cache
cap git:create_release             # Copy repo to releases
cap git:set_current_revision       # Determine the revision that will be deployed
cap git:update                     # Update the repo mirror to reflect the origin state
cap git:wrapper                    # Upload the git wrapper script, this script guarantees that we can script git without getting an interactive prompt
cap install                        # Install Capistrano, cap install STAGES=staging,production
cap rvm:check                      # Prints the RVM and Ruby version on the target host
cap unicorn:add_worker             # Add a worker (TTIN)
cap unicorn:duplicate              # Duplicate Unicorn; alias of unicorn:restart
cap unicorn:legacy_restart         # Legacy Restart (USR2 + QUIT); use this when preload_app: true and oldbin pid needs cleanup
cap unicorn:reload                 # Reload Unicorn (HUP); use this when preload_app: false
cap unicorn:remove_worker          # Remove a worker (TTOU)
cap unicorn:restart                # Restart Unicorn (USR2); use this when preload_app: true
cap unicorn:start                  # Start Unicorn
cap unicorn:stop                   # Stop Unicorn (QUIT)
cap yarn:install                   # Install the project dependencies via yarn
cap yarn:prune                     # Remove extraneous packages via yarn
cap yarn:rebuild                   # Rebuild via yarn

デプロイ
% cap production deploy
% cap production deploy:check

Unicorn再起動
% cap production unicorn:restart
% cap production unicorn:legacy_restart

worker追加/削除
% cap production unicorn:add_worker
% cap production unicorn:remove_worker

Capistrano導入

公式ドキュメント
Capistrano Configuration
capistrano/capistrano: Remote multi-server automation tool
capistrano/rvm
j-arnaiz/capistrano-yarn: Capistrano extension for npm
tablexi/capistrano3-unicorn

Gemfile

group :development do
  # Use Capistrano
  gem 'capistrano', '~> 3.0'
  gem 'capistrano-rvm'
  gem 'capistrano-rails'
  gem 'capistrano-bundler'
  gem 'capistrano3-unicorn'
end
% bundle install
または % bundle
% bundle exec cap install
または % cap install

Capistrano設定

Capfile

今回はrvmでRubyを管理して、Unicornで起動するので、
下記のコメントアウトを外して、migrationsとunicornを追加しました。

require 'capistrano/rvm'
# require "capistrano/rbenv"
# require "capistrano/chruby"
require 'capistrano/bundler'
require 'capistrano/yarn'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
# require "capistrano/passenger"
require 'capistrano3/unicorn'

config/deploy.rb

デフォルトはデプロイ対象のサーバーからGitにアクセスしてソースを持ってくるので、
リポジトリや鍵の設定をします。
実行環境でファイルを圧縮して、サーバーに転送する事もできます。
(社内リポジトリにサーバーからアクセスできなかった時とかに使ってましたね。
今はGitHub等を使っている場合が多いので見かけなくなりましたが)

# set :application, 'my_app_name'

deploy_to設定すれば不要なので、コメントアウトしました。

set :repo_url, `git remote get-url origin`.chomp

originのurlをgitコマンドで取得してセットするようにしました。
オリジン変更した時に変更漏れを防げます。

set :deploy_to, '~/app'

デプロイ先のパス。今回はサーバーのユーザーで動かすので、
解りやすいようにユーザーのパスに設置しました。

NginxやApacheから参照するには、ユーザーのグループをnginxやapacheにして、
homeディレクトリを750にする必要があります。

useradd -g nginx railsapp
chmod 750 /home/railsapp

CentOS7にCapistranoでデプロイしたRailsアプリが動く環境を作る にも記載しています。

append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'tmp/webpacker', 'public/system', 'vendor', 'storage', 'public/uploads'

コメントアウトを外して、public/uploadsも追加しています。
デプロイするとパスが切り替わるので、配下のファイルが変わらないようにシンボリックリンクが貼られます。

set :log_level, :info

デフォルトはdebugなので、infoにして減らしておきます。

set :rvm_type, :user
set :rvm_ruby_version, -> { `cat .ruby-version`.chomp }

.ruby-version(Rubyのバージョンが書いてある)をセットしておくと変更漏れを防げます。

異なるとデプロイ時にエラーになる。

cap production deploy
ruby stdout: Ruby ruby-3.0.0 is not installed.
set :unicorn_config_path, -> { "#{fetch(:deploy_to)}/current/config/unicorn.rb" }
set :unicorn_rack_env, 'production'

after 'deploy:publishing', 'unicorn:restart'

configファイルのパスと、-EがRAILS_ENVにならなかったので、変更しました。
(-EがdeploymentでもRAILS_ENVはENVで設定したのが使えるので、変更しなくても大丈夫そう)

01:03 unicorn:start
-      01 ~/.rvm/bin/rvm ruby-3.0.0 do bundle exec unicorn -c ~/app/current/config/unicorn/production.rb -E deployment -D 
+      01 ~/.rvm/bin/rvm ruby-3.0.0 do bundle exec unicorn -c ~/app/current/config/unicorn.rb -E production -D 
after 'deploy:symlink:linked_dirs', 'deploy:symlink:robots_txt'
after 'deploy:migrate', 'deploy:seed'

namespace :deploy do
  namespace :symlink do
    desc 'Runs ln -sfn public/ public/robots.txt'
    task :robots_txt do
      on roles(:web) do
        within "#{current_path}/public" do
          execute :ln, "-sfn #{fetch(:robots_txt)} robots.txt"
        end
      end
    end
  end

  desc 'Runs rake db:seed'
  task :seed do
    on roles(:db) do
      within current_path do
        execute :rake, 'db:seed'
      end
    end
  end
end

環境毎のrobots.txtのシンボリックリンク作成(参照先はproduction.rbで設定)と、
db:seedがデプロイ時に動くようにしました。

注意:executeがシンボルでないと、withinでのパス指定が効かない。

config/deploy/production.rb

set :branch, 'master'

deploy.rbではなく、ここに設定すれば環境=ブランチを意識しなくて良くなります。

set :robots_txt, 'robots.txt,allow'

deploy.rbの設定したシンボリックリンクの実態のパス。
本番は許可(robots.txt,allow)、STGやテスト環境は(robots.txt,disallow)に設定しました。

setで設定した値をfetch()で呼び出せるの便利ですね。

server 'prod-servername_railsapp', roles: %w[app db web]

rolesにdbがあるとdb:migrateが、webがあるとassets:precompileが実行されます。

鍵の場所とか人によって違ったりするし、踏み台使う場合の設定もし易いので、
sshのconfigで設定して、それを参照するようにしました。
事前に疎通確認も出来るので、エラー時の切り分けもし易い。

~/.ssh/config

Host prod-servername_railsapp
  Hostname ドメインやIPアドレス
  Port 22
  User railsapp
  IdentityFile ~/.ssh/prod-servername_railsapp/id_rsa

直接指定する場合は、こんな感じ。
サーバーが複数ある場合、set :ssh_optionsとかで共通化できそうですね。

server 'ドメインやIPアドレス', user: 'railsapp', port: 22, roles: %w[app db web], keys: %w[~/.ssh/prod-servername_railsapp/id_rsa]

今回のコミット内容
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/ebb8802a8803b1a4c4beedb41f01b267cd64b8c3
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/67345fecd6176bb928e2cae5673c47fa3908bf38

実行してみる

SSHの公開鍵(対象サーバーのSSH接続ユーザー)を、使用しているGitリポジトリに登録して、
下記のコマンドを叩いてエラーがでなかればOK

% bundle exec cap production deploy
または % cap production deploy

00:00 git:wrapper
      01 mkdir -p /tmp
    ✔ 01 prod-nop_railsapp 1.706s
      Uploading /tmp/git-ssh-3b2cfee4bac76ed015e8.sh 100.0%
      02 chmod 700 /tmp/git-ssh-3b2cfee4bac76ed015e8.sh
    ✔ 02 prod-nop_railsapp 0.271s
00:02 git:check
      01 git ls-remote git@ssh.dev.azure.com:v3/nightonly/rails-app-origin/rails-app-origin HEAD
      01 24503b5e4f4e1d00c29f3efabcb86ee8ff8f9bbe	HEAD
    ✔ 01 prod-nop_railsapp 1.848s
00:04 deploy:check:directories
      01 mkdir -p ~/app/shared ~/app/releases
    ✔ 01 prod-nop_railsapp 0.260s
00:04 deploy:check:linked_dirs
      01 mkdir -p ~/app/shared/log ~/app/shared/tmp/pids ~/app/shared/tmp/cache ~/app/shared/tmp/sockets ~/app/shared/tmp/webpacker ~/app/shared/public/system …
    ✔ 01 prod-nop_railsapp 0.246s
00:05 git:clone
      The repository mirror is at ~/app/repo
00:05 git:update
      01 git remote set-url origin git@ssh.dev.azure.com:v3/nightonly/rails-app-origin/rails-app-origin
    ✔ 01 prod-nop_railsapp 0.224s
      02 git remote update --prune
      02 Fetching origin
    ✔ 02 prod-nop_railsapp 2.623s
00:09 git:create_release
      01 mkdir -p ~/app/releases/20230201113322
    ✔ 01 prod-nop_railsapp 0.243s
      02 git archive develop | /usr/bin/env tar -x -f - -C ~/app/releases/20230201113322
    ✔ 02 prod-nop_railsapp 0.394s
00:10 deploy:set_current_revision
      01 echo "81a75976e7197aac1378e8e7c2d9bfee11853c25" > REVISION
    ✔ 01 prod-nop_railsapp 0.258s
00:10 deploy:symlink:linked_dirs
      01 mkdir -p ~/app/releases/20230201113322 ~/app/releases/20230201113322/tmp ~/app/releases/20230201113322/public
    ✔ 01 prod-nop_railsapp 0.248s
      02 rm -rf ~/app/releases/20230201113322/log
    ✔ 02 prod-nop_railsapp 0.243s
      03 ln -s ~/app/shared/log ~/app/releases/20230201113322/log
    ✔ 03 prod-nop_railsapp 0.236s
      04 ln -s ~/app/shared/tmp/pids ~/app/releases/20230201113322/tmp/pids
    ✔ 04 prod-nop_railsapp 0.243s
      05 ln -s ~/app/shared/tmp/cache ~/app/releases/20230201113322/tmp/cache
    ✔ 05 prod-nop_railsapp 0.243s
      06 ln -s ~/app/shared/tmp/sockets ~/app/releases/20230201113322/tmp/sockets
    ✔ 06 prod-nop_railsapp 0.239s
      07 ln -s ~/app/shared/tmp/webpacker ~/app/releases/20230201113322/tmp/webpacker
    ✔ 07 prod-nop_railsapp 0.287s
      08 ln -s ~/app/shared/public/system ~/app/releases/20230201113322/public/system
    ✔ 08 prod-nop_railsapp 0.238s
      09 rm -rf ~/app/releases/20230201113322/vendor
    ✔ 09 prod-nop_railsapp 0.227s
      10 ln -s ~/app/shared/vendor ~/app/releases/20230201113322/vendor
    ✔ 10 prod-nop_railsapp 0.242s
      11 rm -rf ~/app/releases/20230201113322/storage
    ✔ 11 prod-nop_railsapp 0.232s
      12 ln -s ~/app/shared/storage ~/app/releases/20230201113322/storage
    ✔ 12 prod-nop_railsapp 0.240s
      13 rm -rf ~/app/releases/20230201113322/public/uploads
    ✔ 13 prod-nop_railsapp 0.232s
      14 ln -s ~/app/shared/public/uploads ~/app/releases/20230201113322/public/uploads
    ✔ 14 prod-nop_railsapp 0.244s
      15 ln -s ~/app/shared/public/assets ~/app/releases/20230201113322/public/assets
    ✔ 15 prod-nop_railsapp 0.241s
00:19 deploy:symlink:robots_txt
      01 ln -sfn robots.txt,allow robots.txt
    ✔ 01 prod-nop_railsapp 0.232s
00:19 bundler:config
      01 ~/.rvm/bin/rvm ruby-3.0.0 do bundle config --local deployment true
    ✔ 01 prod-nop_railsapp 0.597s
      02 ~/.rvm/bin/rvm ruby-3.0.0 do bundle config --local path \~/app/shared/bundle
    ✔ 02 prod-nop_railsapp 0.597s
      03 ~/.rvm/bin/rvm ruby-3.0.0 do bundle config --local without development:test
    ✔ 03 prod-nop_railsapp 0.605s
00:24 bundler:install
      The Gemfile's dependencies are satisfied, skipping installation
00:24 yarn:install
      01 yarn install --production
      01 yarn install v1.22.19
      01 [1/4] Resolving packages...
      01 [2/4] Fetching packages...
      01 [3/4] Linking dependencies...
      01 warning " > webpack-dev-server@3.11.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
      01 warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
      01 [4/4] Building fresh packages...
      01 Done in 6.38s.
    ✔ 01 prod-nop_railsapp 6.750s
00:31 deploy:assets:precompile
      01 ~/.rvm/bin/rvm ruby-3.0.0 do bundle exec rake assets:precompile
      01 yarn install v1.22.19
      01 [1/4] Resolving packages...
      01 success Already up-to-date.
      01 Done in 0.51s.
      01 Compiling...
      01 Compiled all packs in /home/railsapp/app/releases/20230201113322/public/packs
<省略>
    ✔ 01 prod-nop_railsapp 19.208s
00:50 deploy:assets:backup_manifest
      01 mkdir -p ~/app/releases/20230201113322/assets_manifest_backup
    ✔ 01 prod-nop_railsapp 0.256s
      02 cp /home/railsapp/app/releases/20230201113322/public/assets/.sprockets-manifest-0645089a291bdb1dfbc12a9ade25f2bc.json ~/app/releases/20230201113322/as…
    ✔ 02 prod-nop_railsapp 0.268s
00:51 deploy:migrate
      [deploy:migrate] Run `rake db:migrate`
00:51 deploy:migrating
      01 ~/.rvm/bin/rvm ruby-3.0.0 do bundle exec rake db:migrate
    ✔ 01 prod-nop_railsapp 3.560s
00:55 deploy:seed
      01 ~/.rvm/bin/rvm ruby-3.0.0 do bundle exec rake db:seed
      01 "== file: seed/admin_users.yml"
      01 "count: 1, model: AdminUser"
      01 "insert: 0, update: -, delete: -"
      01 "== file: seed/users_development.yml ... Skip"
      01 "== file: seed/infomations_development.yml ... Skip"
      01 "Complete! ... Total insert: 0, update: 0, delete: 0"
    ✔ 01 prod-nop_railsapp 2.855s
00:58 deploy:symlink:release
      01 ln -s ~/app/releases/20230201113322 ~/app/releases/current
    ✔ 01 prod-nop_railsapp 0.249s
      02 mv ~/app/releases/current ~/app
    ✔ 02 prod-nop_railsapp 0.258s
00:59 unicorn:start
      unicorn is running...
      unicorn restarting...
      01 kill -s USR2 `cat ~/app/current/tmp/pids/unicorn.pid`
    ✔ 01 prod-nop_railsapp 0.242s
01:00 deploy:cleanup
      Keeping 5 of 6 deployed releases on prod-nop_railsapp
      01 rm -rf ~/app/releases/20230129114813
    ✔ 01 prod-nop_railsapp 0.868s
01:01 deploy:log_revision
      01 echo "Branch develop (at 81a75976e7197aac1378e8e7c2d9bfee11853c25) deployed as release 20230201113322 by user" >> ~/app/revisions.log
    ✔ 01 prod-nop_railsapp 0.267s

Gitからソースを取得して設置 → シンボリックリンク作成 → bundle install → yarn install → assets:precompile → db:migrate → db:seed → Unicorn起動か再起動の流れ。

設置ファイル確認

サーバーの中身を確認してみます。

$ ll ~/app/
lrwxrwxrwx 1 railsapp nginx  42  1月 29 20:48 current -> /home/railsapp/app/releases/20230129114813
drwxr-xr-x 7 railsapp nginx 116  1月 29 20:49 releases
drwxr-xr-x 7 railsapp nginx 156  1月 29 20:48 repo
-rw-r--r-- 1 railsapp nginx 324  1月 29 20:49 revisions.log
drwxr-xr-x 8 railsapp nginx  85  1月 29 18:45 shared

$ ll ~/app/current/public/
-rw-r--r-- 1 railsapp nginx 1722  1月 29 20:23 404.html
-rw-r--r-- 1 railsapp nginx 1705  1月 29 20:23 422.html
-rw-r--r-- 1 railsapp nginx 1635  1月 29 20:23 500.html
-rw-r--r-- 1 railsapp nginx    2  1月 29 20:23 _check
-rw-r--r-- 1 railsapp nginx    0  1月 29 20:23 apple-touch-icon-precomposed.png
-rw-r--r-- 1 railsapp nginx    0  1月 29 20:23 apple-touch-icon.png
lrwxrwxrwx 1 railsapp nginx   39  1月 29 20:48 assets -> /home/railsapp/app/shared/public/assets
drwxr-xr-x 2 railsapp nginx  155  1月 29 20:23 auth
drwxr-xr-x 2 railsapp nginx   48  1月 29 20:23 css
-rw-r--r-- 1 railsapp nginx    0  1月 29 20:23 favicon.ico
drwxr-xr-x 3 railsapp nginx   18  1月 29 20:23 images
drwxr-xr-x 2 railsapp nginx   46  1月 29 20:23 js
-rw-r--r-- 1 railsapp nginx 9700  1月 29 20:23 logo.png
drwxr-xr-x 3 railsapp nginx   85  1月 29 20:48 packs
lrwxrwxrwx 1 railsapp nginx   16  2月  2 08:50 robots.txt -> robots.txt,allow
-rw-r--r-- 1 railsapp nginx   26  1月 29 20:23 robots.txt,allow
-rw-r--r-- 1 railsapp nginx   28  1月 29 20:23 robots.txt,disallow
lrwxrwxrwx 1 railsapp nginx   39  1月 29 20:48 system -> /home/railsapp/app/shared/public/system
lrwxrwxrwx 1 railsapp nginx   40  1月 29 20:48 uploads -> /home/railsapp/app/shared/public/uploads

$ ll ~/app/current/tmp/
lrwxrwxrwx 1 railsapp nginx 35  1月 29 20:48 cache -> /home/railsapp/app/shared/tmp/cache
lrwxrwxrwx 1 railsapp nginx 34  1月 29 20:48 pids -> /home/railsapp/app/shared/tmp/pids
lrwxrwxrwx 1 railsapp nginx 37  1月 29 20:48 sockets -> /home/railsapp/app/shared/tmp/sockets
lrwxrwxrwx 1 railsapp nginx 39  1月 29 20:48 webpacker -> /home/railsapp/app/shared/tmp/webpacker

$ ll ~/app/current/tmp/sockets/
srwxrwxrwx 1 railsapp nginx 0  1月 29 20:49 unicorn.sock

currentで最新のソースにシンボリックリンクが貼られるので、
下記をNginxやApacheに設定してあげればOK。
/home/railsapp/app/current/public/
/home/railsapp/app/current/tmp/sockets/unicorn.sock

$ ll ~/app/shared/
drwxr-xr-x 3 railsapp nginx  18  1月 29 18:45 bundle
drwxr-xr-x 2 railsapp nginx 115  1月 29 20:52 log
drwxr-xr-x 5 railsapp nginx  49  1月 29 18:44 public
drwxr-xr-x 2 railsapp nginx   6  1月 29 18:44 storage
drwxr-xr-x 6 railsapp nginx  63  1月 29 18:44 tmp
drwxr-xr-x 2 railsapp nginx   6  1月 29 18:44 vendor

linked_dirsで設定したシンボリックリンクの参照先。

$ ll ~/app/releases/
drwxr-xr-x 16 railsapp nginx 4096  1月 29 20:29 20230129112828
drwxr-xr-x 16 railsapp nginx 4096  1月 29 20:39 20230129113857
drwxr-xr-x 16 railsapp nginx 4096  1月 29 20:42 20230129114213
drwxr-xr-x 16 railsapp nginx 4096  1月 29 20:46 20230129114532
drwxr-xr-x 16 railsapp nginx 4096  1月 29 20:48 20230129114813

$ cat ~/app/revisions.log 
Branch develop (at c67bd48955e274f6d4f25bbb15a5aa67b6e86cdf) deployed as release 20230129114213 by user
Branch develop (at c67bd48955e274f6d4f25bbb15a5aa67b6e86cdf) deployed as release 20230129114532 by user
Branch develop (at c67bd48955e274f6d4f25bbb15a5aa67b6e86cdf) deployed as release 20230129114813 by user

currentの参照先。keep_releasesのデフォルトで過去分が5件残っています。
revisions.logが3件なのは、エラーで失敗したからで、最大5件残ります。

動作確認

ブラウザからアクセス

Nginx設定はこちら
CentOS7にCapistranoでデプロイしたRailsアプリが動く環境を作る

タスク実行

$ cd ~/app/current/
$ bundle exec rails -T
<省略>
rails assets:clean[keep]                 # Remove old compiled assets
rails assets:clobber                     # Remove compiled assets
rails assets:environment                 # Load asset compile environment
rails assets:precompile                  # Compile all the assets named in config.assets.precompile
rails cache_digests:dependencies         # Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)
rails cache_digests:nested_dependencies  # Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)
rails db:create                          # Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to cr...
rails db:drop                            # Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop a...
rails db:environment:set                 # Set the environment value for the database
rails db:fixtures:load                   # Loads fixtures into the current environment's database
rails db:migrate                         # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
rails db:migrate:down                    # Runs the "down" for a given migration VERSION
rails db:migrate:redo                    # Rolls back the database one migration and re-migrates up (options: STEP=x, VERSION=x)
rails db:migrate:status                  # Display status of migrations
rails db:migrate:up                      # Runs the "up" for a given migration VERSION
rails db:prepare                         # Runs setup if database does not exist, or runs migrations if it does
rails db:reset                           # Drops and recreates the database from db/schema.rb for the current environment and loads the seeds
rails db:rollback                        # Rolls the schema back to the previous version (specify steps w/ STEP=n)
rails db:schema:cache:clear              # Clears a db/schema_cache.yml file
rails db:schema:cache:dump               # Creates a db/schema_cache.yml file
rails db:schema:dump                     # Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.sche...
rails db:schema:load                     # Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema...
rails db:seed                            # Loads the seed data from db/seeds.rb
rails db:seed:replant                    # Truncates tables of each database for current environment and loads the seeds
rails db:setup                           # Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the databa...
rails db:structure:dump                  # Dumps the database structure to db/structure.sql
rails db:structure:load                  # Recreates the databases from the structure.sql file
rails db:version                         # Retrieves the current schema version number
<省略>
rails unicorn:decrement                  # Unicornのワーカープロセスを減らす(TTOU)
rails unicorn:graceful                   # Unicorn緩やかな再起動(USR2)
rails unicorn:increment                  # Unicornのワーカープロセスを増やす(TTIN)
rails unicorn:pstree                     # Unicornプロセスの親子関係を確認(pstree)
rails unicorn:restart                    # Unicorn再起動(HUP)
rails unicorn:start                      # Unicorn起動(bundle exec unicorn)
rails unicorn:stop                       # Unicorn停止(QUIT)
rails user:destroy[dry_run]              # ユーザーアカウント削除(削除予定日時以降)
<省略>

作成したタスクを実行してみます。

$ bundle exec rails user:destroy
$ cat log/user_destroy_production.log 
# Logfile created on 2023-01-29 20:52:47 +0900 by logger.rb/v1.4.3
I, [2023-01-29T20:52:47.774195 #6508]  INFO -- : === START user:destroy ===
I, [2023-01-29T20:52:47.774233 #6508]  INFO -- : dry_run: true
D, [2023-01-29T20:52:47.789769 #6508] DEBUG -- : #
I, [2023-01-29T20:52:47.792970 #6508]  INFO -- : count: 0
I, [2023-01-29T20:52:47.796913 #6508]  INFO -- : === END user:destroy ===

$ bundle exec rails user:destroy[false]
$ cat log/user_destroy_production.log
I, [2023-01-29T20:53:17.643146 #6546]  INFO -- : === START user:destroy ===
I, [2023-01-29T20:53:17.643258 #6546]  INFO -- : dry_run: false
D, [2023-01-29T20:53:17.651724 #6546] DEBUG -- : #
I, [2023-01-29T20:53:17.653663 #6546]  INFO -- : count: 0
I, [2023-01-29T20:53:17.655275 #6546]  INFO -- : === END user:destroy ===

cron設定

サーバー再起動時にUnicornが自動起動するようにと、
上記のタスクを起動するようにcronを設定ました。

$ crontab -e
@reboot bash -l -c 'cd ~/app/current/; bundle exec rails unicorn:start'
@reboot bash -l -c 'cd ~/app/current/; rm -f tmp/pids/unicorn.pid; bundle exec rails unicorn:start'
0 10 * * * bash -l -c "sleep $((RANDOM \% 51 + 5)); cd ~/app/current/; bundle exec rails user:destroy[false]"

> sleep $((RANDOM \% 51 + 5))
cronは0秒から実行しようするので、他のバッチと被って負荷が高くなる事があります。
こんな感じでsleepしてから実行すると秒単位で時間をずらせます。
5(0+5)〜55(50+5)秒のいずれかになります。

> \%
crontabからの起動の場合、%で区切られしまうようで、エラーになりました。

0 10 * * * bash -l -c "sleep $((RANDOM % 51 + 5)); cd ~/app/current/; bundle exec rails user:destroy[false]"
メール: Cron <railsapp@prod-servername> bash -l -c 'echo $((RANDOM
/bin/sh: -c: 行 0: 一致する `)' を探索中に予期しないファイル終了 (EOF) です
/bin/sh: -c: 行 1: 構文エラー: 予期しないファイル終了 (EOF) です

# less /var/log/cron
CROND[628]: (railsapp) CMD (bash -l -c 'echo $((RANDOM )
0 10 * * * bash -l -c "sleep $((RANDOM \% 51 + 5)); cd ~/app/current/; bundle exec rails user:destroy[false]"
メール: なし

# less /var/log/cron
CROND[726]: (railsapp) CMD (bash -l -c "sleep $((RANDOM % 51 + 5)); cd ~/app/current/; bundle exec rails user:destroy[false]")

ダブル(“)をシングル(‘)にしても変わらなかった。

> -l
これがない場合

0 10 * * * bash -c "sleep $((RANDOM \% 51 + 5)); cd ~/app/current/; bundle exec rails user:destroy[false]"
bash: bundle: コマンドが見つかりません

TODO: cronの管理はwheneverを使って、Capistranoで設定すれば自動化できて便利
GitHub – javan/whenever: Cron jobs in Ruby

トラブルメモ

`bundle lock –add-platform x86_64-linux` and try again.

00:21 bundler:install
      01 ~/.rvm/bin/rvm default do bundle install --jobs 4 --quiet
      01 Your bundle only supports platforms ["aarch64-linux-musl", "arm64-darwin-20"]
      01 but your local platform is x86_64-linux. Add the current platform to the
      01 lockfile with `bundle lock --add-platform x86_64-linux` and try again.

記載通りにコマンドを実行して、
サーバー側で動くので、Gitにcommit&pushで解消しました。

% bundle lock --add-platform x86_64-linux

コミット内容
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/f347b44ae4b265c8383109658dad1e5f11d98ec5

node-sass: Command failed.

Tasks: TOP => deploy:updated => yarn:install
(See full trace by running task with --trace)
The deploy has failed with an error: Exception while executing on host prod-servername_railsapp: yarn exit status: 1
yarn stdout: yarn install v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
yarn stderr: warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
error /home/railsapp/app/releases/20230129095047/node_modules/node-sass: Command failed.

下記に詳しく書かれています。
error /node_modules/node-sass: Command failedの解決策 – Qiita

webpackerのバージョンアップ(GemとYarn)とnode-sassのインストール。
サーバー側で動くので、Gitにcommit&pushで解消しました。

Mysql2::Error: Specified key was too long; max key length is 767 bytes

00:58 deploy:migrating
      01 ~/.rvm/bin/rvm ruby-3.0.0 do bundle exec rake db:migrate
      01 == 20200506031216 DeviseCreateUsers: migrating ================================
      01 -- create_table(:users, {:comment=>"ユーザー"})
      01    -> 0.0027s
      01 -- add_index(:users, :email, {:unique=>true, :name=>"index_users1"})
      01 rake aborted!
      01 StandardError: An error has occurred, all later migrations canceled:
      01
      01 Mysql2::Error: Specified key was too long; max key length is 767 bytes

下記に詳しく書かれています。
【MySQL】Mysql2::Error: Specified key was too long; max key length is 767 bytes – Qiita

下記を追加して、191に制限。
バリデーションとかで、192以上(255等)で制限してたり、192を超えて使いたい場合は、型を変更する等の対応が必要です。

config/initializer/mysql.rb

require 'active_record/connection_adapters/abstract_mysql_adapter'

module ActiveRecord
  module ConnectionAdapters
    class AbstractMysqlAdapter
      NATIVE_DATABASE_TYPES[:string] = { name: 'varchar', limit: 191 }
    end
  end
end

Capistranoを設定して安全にデプロイできるようにする” に対して1件のコメントがあります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です