とーますメモ

Ruby on Rails / Goなどの学習メモ

【Sidekiq】Capistranoで独自タスクを書いてみた。

capistrano-sidekiqが微妙だったので、
自分でタスクを書いた。

append :linked_files, "config/database.yml", "config/secrets.yml", "config/sidekiq.yml"

set :sidekiq_pid_path, -> { File.join(shared_path, 'tmp', 'pids', 'sidekiq.pid') }
set :sidekiq_config, ->   { File.join(shared_path, 'config', 'sidekiq.yml') }

namespace :sidekiq do
  task :kill do
    on roles(:app) do
      execute "kill -TERM `cat #{fetch :sidekiq_pid_path}`; true"
    end
  end

  task :restart do
    on roles(:app) do
      invoke 'sidekiq:kill'
      within current_path do
        execute "su - USER_NAME -c 'cd /var/www/shopify_data_manager/current && $HOME/.rbenv/bin/rbenv exec bundle exec sidekiq -C #{fetch :sidekiq_config} --daemon'"
      end
    end
  end
  after  'deploy:finishing', 'sidekiq:restart'
end

namespace :deploy do

  desc 'upload linked_files'
  task :upload do
    on roles(:app) do |host|
      execute :mkdir, '-p', "#{shared_path}/config"
      upload!('config/database.yml',"#{shared_path}/config/database.yml")
      upload!('config/secrets.yml',"#{shared_path}/config/secrets.yml")
      upload!('config/sidekiq.yml',"#{shared_path}/config/sidekiq.yml")
    end
  end

  ...

end


最初は、Sidekiqを起動するコマンドを以下のように書いていた。

execute :bundle, :exec, "sidekiq -e development -C #{fetch :sidekiq_config}"

しかし、これだと何故か動かなくて、
いろいろ調べているうちに、以下のページからヒントを貰い、

monitoring - monitでsidekiqの停止を感知できるが、sidekiqを自動起動できない - スタック・オーバーフロー

ユーザを変更してみたら、動作した。


[参考]
Capistranoでunicornとsidekiqをシンプルにrestartする - Qiita
capistrano-sidekiqを使うのをやめる - Qiita

【Shopifyアプリ】Nginxをリバースプロキシとして設定した場合のTips

自分用メモ

以下のようにした場合、アプリ登録時にエラーになり
redirect_urlにlocalhost:3000が表示される。

server {
  listen 80 default_server;

  location / {
    proxy_pass http://localhost:3000;
  }
}

以下のようにしたら、正常に登録できた。

server {
  listen 80 default_server;

  location / {
    proxy_pass http://localhost:3000;

    proxy_redirect                         off;
    proxy_set_header Host                  $host;
    proxy_set_header X-Real-IP             $remote_addr;
    proxy_set_header X-Forwarded-Host      $host;
    proxy_set_header X-Forwarded-Server    $host;
    proxy_set_header X-Forwarded-For       $proxy_add_x_forwarded_for;
  }
}

というか

以下の設定があるだけでよかった。

proxy_set_header Host                  $host;

【CircleCI】Capistranoでデプロイする設定

まずは、CircleCIからデプロイ先サーバに接続するために秘密鍵を登録する。
詳細は以下。
thoames.hatenadiary.jp

そして以下設定を.circleci/config.ymlに追加。
※「'xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx'」のフィンガープリントは
上記のリンク内の、SSH Permissions設定を行うと出力される。

[Add ssh-agent]箇所では、SSH agent forwardingを行うための設定をしている。
登録した秘密鍵をssh_agentに追加。

以下はコミットされたブランチがマスターブランチのときのみデプロイが走る例。

- add_ssh_keys:
    fingerprints:
      - 'xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx'

- run:
    name: Add ssh-agent
    command: |
      ssh-agent -s > ~/.ssh_agent_conf
      source ~/.ssh_agent_conf
      for _k in $(ls ${HOME}/.ssh/id_*); do
        ssh-add ${_k} || true
      done

- deploy:
    name: Deploy via Capistrano
    command: |
      if [ "${CIRCLE_BRANCH}" != "master" ]; then
        exit 0
      fi
      
      bundle exec cap production deploy


[参考]
CircleCI 2.0 で capistrano デプロイしてみた / マスタカの ChangeLog メモ
CircleCI 2.0を使うようにするだけで、こんなに速くなるとは夢にも思わなかった! | Tokyo Otaku Mode Blog

【CircleCI】CapistranoでデプロイするためのSSH Permissions設定

前提として既にデプロイ先のサーバでは、共通鍵の設定が終わっている前提。

以下参考。
thoames.hatenadiary.jp


SSH Permissionsの箇所に秘密鍵を登録することでCircleCI側からデプロイできるようになるが、何回「Add SSH Key」を押して登録しようとしてみても「Failed」と表示されて、「なぜFaildedなのか」が全くわからない状況に陥った。。。

色々と調べてみると、Chrome開発者ツールのNetworkタブを開き且つ[XHR]を選択している状態で「Add SSH Key」を押していると「ssh-key」という名前でリクエストが飛び、そのレスポンスを見ればなぜ失敗しているかが分かる。

自分の場合以下のレスポンスが返ってきた。

{"message":"it looks like this key is encrypted: we don't support password-protected keys"}

要は暗号化されている秘密鍵は受け入れない。とのこと。
なので、秘密鍵を以下のように復号化して登録してやれば良い。

openssl rsa -in <秘密鍵>  -out <復号化したい秘密鍵名>

上記のコマンドを実行し、出力された<復号化したい秘密鍵名>の中身をそのままコピーすればすんなり通った。


[参考]
How to Decrypt an RSA Private Key Using OpenSSL on NetScaler

【Rails】CapistranoでBitbucketからcloneしデプロイするまで試してみた

【環境】
Ubuntu + Rbenv + Rails + Puma + MySQL


1)SSH周りの設定

前提

公開リポジトリの場合は、Capistranoの設定は簡単だが、BitbucketのPrivateリポジトリからcloneする場合は、SSH認証が絡んでくるため、設定が少し複雑になる。

ちなみにGithubのPrivateリポジトリを使用する場合は、「Personal Access Token」を使用すれば、すごい簡単にPrivateリポジトリからcloneできる。

BitbucketでSSH認証を行う方法としては

① SSH agent forwardingを使用する
② デプロイするサーバで秘密鍵・公開鍵を作り、公開鍵をBitbucketに登録する

がある。

①の「SSH agent forwarding」については以下のサイトが詳しい。
SSH agent forwardingまとめ - Code Life

②を使用する場合は、サーバが増えるたびに鍵が増えていき管理が手間になるため
①をここでは推奨する。

以降の説明では①の「SSH agent forwarding」を用い、
Capistranoを使用したデプロイを行う手順を説明していく。

[参考]
Capistrano 3.x で GitHub(プライベートリポジトリ)からソースコードを取得する3種類の方法について - Qiita
Capistrano3でgithubのプライベートリポジトリを簡単にデプロイする方法 · polidog lab++
ssh-agentを利用して、安全にSSH認証を行う - Qiita
capistrano3でssh agent forwarding - Qiita
capistranoでデプロイする時のssh-key周りのTips - Qiita

Capistrano3とBitbucketを使ってRailsアプリをデプロイ | EasyRamble
(②の方法で対応する場合)

ローカルで秘密鍵・公開鍵を作成

$ cd ~/.ssh
$ ssh-keygen -t rsa

ずっとエンターを押し続けていれば、「id_rsa (秘密鍵)」と「id_rsa.pub (公開鍵)」ができる。

[参考]
gitHubでssh接続する手順~公開鍵・秘密鍵の生成から~ - Qiita

ssh-agentに秘密鍵を登録

$ ssh-add -K ~/.ssh/id_psa

Bitbucket側に公開鍵を登録

表示された内容をコピペ

$ cat ~/.ssh/id_rsa.pub | pbcopy

Bitbucketの設定の「SSH Keys」から「Add Key」で設定

f:id:Thoames1212:20180410024005p:plain

2)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
$ bundle install --path vendor/bundle

3)Capistranoのデフォルトファイル作成

例)development, staging, produtionの3つの環境を作成

$ bundle exec cap install STAGES=development,staging,production
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/development.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
create Capfile
Capified

Capistranoファイルの設定

設定するファイルは

① Capfile
② deploy.rb
③ development.rb(開発環境へデプロイするため。staging環境ならstaging.rbにする)

を設定する。

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"
install_plugin Capistrano::SCM::Git

require "capistrano/rbenv"
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"

require 'capistrano/puma'
install_plugin Capistrano::Puma

# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }

development.rb(ユーザはroot)

role :app, %w{root@xxx.xxx.xxx.xxx}
role :web, %w{root@xxx.xxx.xxx.xxx}
role :db,  %w{root@xxx.xxx.xxx.xxx}

server 'xxx.xxx.xxx.xxx,
user: 'root',
roles: %w{web app db},
ssh_options: {
  user: 'root', # overrides user setting above
  keys: %w(/Users/hogehoge/.ssh/id_rsa),
  forward_agent: true,                                           # ssh agent forwardを使用するのでtrue
  auth_methods: %w(publickey)
}

deploy.rb

set :application, "SampleApp"
set :repo_url, "git@bitbucket.org:nutrisan/sample.git"

# Default branch is :master
ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp

# Default deploy_to directory is /var/www/my_app_name
set :deploy_to, "/var/www/sample_app"

# Default value for :pty is false
set :pty, true

# Default value for :linked_files is []
append :linked_files, "config/puma.rb", "config/database.yml", "config/secrets.yml"

# Default value for linked_dirs is []
append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system"

# Default value for keep_releases is 5
set :keep_releases, 5

# migrate setting
set :migration_role, :db
set :conditionally_migrate, false

set :rbenv_type, :user
set :rbenv_ruby, '2.3.1'

set :rails_root, 'web'

set :bundle_without, nil    # (default: %w{development test}.join(' ') )
set :bundle_flags, nil      # (default: '--deployment --quiet')

# for puma
set :puma_conf, "#{shared_path}/config/puma.rb"


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

before 'deploy:starting', 'deploy:upload'
namespace :deploy do

  # below task must run before linked_files task.
  desc 'upload linked_files'
  task :upload do
    on roles(:app) do |host|
      execute :mkdir, '-p', "#{shared_path}/config"
      upload!('config/puma.rb',"#{shared_path}/config/puma.rb")
      upload!('config/database.yml',"#{shared_path}/config/database.yml")
      upload!('config/secrets.yml',"#{shared_path}/config/secrets.yml")
    end
  end

  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
      within release_path do
        execute :rm, '-rf', release_path.join('tmp/cache')
      end
    end
  end

  desc "Restart Application"
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      invoke 'puma:restart'
    end
  end
end

タスクの追加

$ bundle exec cap -T

デプロイタスクの詳細は以下が詳しい。
Capistrano3のデプロイフレームワークの使い方 - Qiita

Pumaについて

pumaには、pumaコマンドとpumactlコマンドがあるが
基本的にできることに差はないが、pumactlはデフォルトでconfig/puma.rbを読み込んでくれたり
startだけでなく、stopやrestartといったコマンドも使用できるためpumactlを使うのが良いだろう。
※ちなみにstateファイルはpumactl使用時に使用される。

「gem 'capistrano3-puma'」を入れることによって
設定ファイルのpuma.rbがリモートの「shared/puma.rb」に自動作成される。
またCapistranoのdeploy.rbに設定するpuma関連の設定はすべてこのファイル内に設定される。

しかしこのshared/puma.rbではなく、Railsのconfig/puma.rbを使用したい場合は、
以下のように書くと良いっぽい。

set :puma_conf, "#{shared_path}/config/puma.rb"

※この設定を使用すると、deploy.rb内の設定は使用されなくなる。

[bindについて]

サーバーをどのように接続するかをURIで指定できます。 シンプルにTCPで接続する場合tcp://0.0.0.0:80、またWebサーバーの前段にnginxをなどを置き、そこからUNIX Socket経由で接続する場合はunix:///var/run/puma.sockのように指定します。

by RackサーバーのPumaについて調べてみる - ゆーじのろぐ

[puma.rbの設定例]
puma/config.rb at master · puma/puma · GitHub


[参考]
Pumaの起動におけるpumaコマンドとpumactlコマンドの違い - Qiita
Digesting pumactl - Ruby Journal
Ruby on Rails 5の上手な使い方 現場のエンジニアが教えるRailsアプリケーション開発の ... - 太田智彬, 株式会社リクルートテクノロジーズ, 宗像亜由美, 寺下翔太, 手塚亮 - Google ブックス

4) 実行

$ bundle exec cap development deploy