Ruby on Railsで環境変数を新規に設定したらunicorn:restartでは駄目だった


以前の投稿 (環境変数にパスワードを埋め込んでdeployするまで)

Ruby on Railsで githubなどにcommitしたくないパスワードなどを環境変数に設定してcapistranoでdeployする方法
http://qiita.com/kenjiszk/items/2e45660ce3b46596dfa1

自前で、unicorn起動時に環境変数をよんでから実行していた。

unicorn:restartでは環境変数をよみ直してくれない

unicornにUSR2を送ってみる

unicorn:restartは内部的にUSR2を送ってホットデプロイしているのでそれを観察する

unicornのシグナルに関しての詳細はこちら。
http://qiita.com/kenjiszk/items/7c6edc7f579ab068591a

元のプロセス

pid 237の親に二つ子プロセスがいる状態。

$ pstree -anp; ps aux | grep unicorn
bash,1
  |-sshd,35
  |-nginx,44
  |   `-nginx,45
  `-ruby,237                                                    
      |-{ruby},260
      |-{ruby},261
      |-{ruby},265
      |-ruby,269                                                 
      |   `-{ruby},271
      |-ruby,274                                                 
      |   `-{ruby},276
      `-{ruby},275
app     237  0.5  3.9 519760 159992 ?       Sl   22:37   0:09 unicorn master -c config/unicorn.rb -D -E development                                                    
app     269  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[0] -c config/unicorn.rb -D -E development                                                 
app     274  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[1] -c config/unicorn.rb -D -E development                                                 
app     311  0.0  0.0   8860   644 ?        S+   23:05   0:00 grep --color=auto unicorn

kill -s USR2 237 してみる

親にUSR2を送ってみる
すると新しい親(pid312)が、シグナルが送られたプロセスの子供として生まれる

$ pstree -anp; ps aux | grep unicorn
bash,1
  |-sshd,35
  |-nginx,44
  |   `-nginx,45
  `-ruby,237                                              
      |-{ruby},260
      |-{ruby},261
      |-{ruby},265
      |-ruby,269                                                 
      |   `-{ruby},271
      |-ruby,274                                                 
      |   `-{ruby},276
      |-ruby,312 /path/to/app/shared/bundle/ruby/2.2.0/bin/unicorn -c config/unicorn.rb -D -E development
      |   `-{ruby},315
      `-{ruby},313
app     237  0.5  3.9 585296 159996 ?       Sl   22:37   0:09 unicorn master (old) -c config/unicorn.rb -D -E development                                              
app     269  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[0] -c config/unicorn.rb -D -E development                                                 
app     274  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[1] -c config/unicorn.rb -D -E development                                                 
app     312 54.0  0.5  89600 21940 ?        Rl   23:06   0:01 ruby /path/to/app/shared/bundle/ruby/2.2.0/bin/unicorn -D -E development
app     318  0.0  0.0   8860   644 ?        S+   23:06   0:00 grep --color=auto unicorn

新プロセスが子供を作る

新しい親がスレッド作ったりして色々と頑張り始める

$ pstree -anp; ps aux | grep unicorn
bash,1
  |-sshd,35
  |-nginx,44
  |   `-nginx,45
  `-ruby,237                                              
      |-{ruby},260
      |-{ruby},261
      |-{ruby},265
      |-ruby,269                                                 
      |   `-{ruby},271
      |-ruby,274                                                 
      |   `-{ruby},276
      |-ruby,312 /path/to/app/shared/bundle/ruby/2.2.0/bin/unicorn -c config/unicorn.rb -D -E development
      |   |-{ruby},315
      |   |-{ruby},329
      |   |-{ruby},330
      |   `-{ruby},334
      `-{ruby},313
app     237  0.5  3.9 585296 159996 ?       Sl   22:37   0:09 unicorn master (old) -c config/unicorn.rb -D -E development                                              
app     269  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[0] -c config/unicorn.rb -D -E development                                                 
app     274  0.0  3.7 519760 152916 ?       Sl   22:37   0:00 unicorn worker[1] -c config/unicorn.rb -D -E development                                                 
app     312 96.6  3.9 521744 161428 ?       Rl   23:06   0:11 ruby /path/to/app/shared/bundle/ruby/2.2.0/bin/unicorn -c config/unicorn.rb -D -E development
app     337  0.0  0.0   8860   648 ?        S+   23:06   0:00 grep --color=auto unicorn

入れ替わり

新親が子プロセスを作る終わって、元の親がいなくなり、新親の親はinitになる。

$ pstree -anp; ps aux | grep unicorn
bash,1
  |-sshd,35
  |-nginx,44
  |   `-nginx,45
  `-ruby,312                                                    
      |-{ruby},329
      |-{ruby},330
      |-{ruby},334
      |-ruby,338                                                 
      |   `-{ruby},340
      |-ruby,343                                                 
      |   `-{ruby},345
      `-{ruby},344
app     312 69.2  3.9 521748 161852 ?       Sl   23:06   0:11 unicorn master -c config/unicorn.rb -D -E development                                                    
app     338  0.5  3.8 521748 154628 ?       Sl   23:06   0:00 unicorn worker[0] -c config/unicorn.rb -D -E development                                                 
app     343  0.2  3.8 521748 154608 ?       Sl   23:06   0:00 unicorn worker[1] -c config/unicorn.rb -D -E development                                                 
app     352  0.0  0.0   8860   648 ?        S+   23:06   0:00 grep --color=auto unicorn

USR2だと環境変数はよみ直さない

ということで、自分のコピーを作るだけなので環境変数は新しくしても読み込まないし、環境変数を消してもプロセスには残っている状態になっている。

仕方ないのでstop startする

対応

config/deploy.rbをこんな感じにしました。
今の環境だと、/path/to/secret/yml/env.ymlに環境変数に読み込むものを書いているので、そこのタイムスタンプが起動しているunicornのpidのタイムスタンプよりも新しかったら、unicornをstopして、unicorn_stop_sleep_time秒後にstartするように変更。
ついでに、rubyがバージョンアップした場合にもstop startするようにした。

namespace :deploy do

  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      # unix command execute status;
      # 0 : true
      # 1 : false
      old_env = capture(
        "/usr/bin/test /path/to/secret/yml/env.yml -ot #{fetch(:deploy_to)}/shared/tmp/pids/unicorn.pid; echo $?"
      )
      old_ruby = capture(
        "/usr/bin/test /home/app/.rbenv/versions/#{fetch(:rbenv_ruby)} -ot #{fetch(:deploy_to)}/shared/tmp/pids/unicorn.pid; echo $?"
      )
      if old_env == '0' && old_ruby == '0'
        info 'env.yml and ruby version is old. restat unicorn.'
        invoke 'unicorn:restart'
      else
        info 'env.yml or ruby version is new. stop and start(reload env.yml) unicorn.'
        invoke 'unicorn:stop'
        execute :sleep, fetch(:unicorn_stop_sleep_time)
        invoke 'unicorn:start'
      end
    end
  end

  after :publishing, :restart
end

まとめ

gitにcommitしたくないものをどうやって環境変数に持たせるか、から始まりunicornの再起動まで気を使う事になってきた。
実はもっといい方法がどこかにあるんじゃないかと思いつつもひとまずこれで運用する。