CapistranoでUnicorn + nginx in Ubuntuにデプロイしたら環境変数が適用されない問題解決メモ


CapistranoでVagrantにデプロイした際、なぜか設定したはずの環境変数が適用されなかった。それはserviceコマンドの挙動が原因だった。という話です。

# 経緯


おなじみ[Railscasts#335](http://railscasts.com/episodes/335-deploying-to-a-vps)で紹介された方法で、いったんデプロイには成功した。


しかしその後、[Raiscasts#337](http://railscasts.com/episodes/337-capistrano-recipes)を参考にconfig/recipesにCapistranoの設定を分割してからVagrantで作った環境にデプロイしたところ、環境変数が読み込まれなかった。

**大問題**である。

環境変数には、他人には見られたくないAmazon S3のパスワードなどが入っている。[asset_sync](https://github.com/rumblelabs/asset_sync)や[fog](https://github.com/fog/fog)を使っているので、アプリケーションにはどうしても環境変数の設定が必要。これらを本番環境で動くサーバにセットせねばならない。

選択肢として、application.ymlにS3のパスワードなどを書いて、本番環境に置くという方法もある。だができれば本番環境上で作業したくない。全部Capistranoですませたい。どうすればよいか？

### 余談
ちなみに、複数サーバにCapistranoでデプロイするのはとても簡単。GithubのCapistrano Wikiにやり方が書いてある。
https://github.com/capistrano/capistrano/wiki/2.x-Multistage-Extension
以前はプラグインとして提供されていたらしいcapistrano-extはすでにcapistrano内に入っている。 なので、

```ruby:deploy.rb
set :stages, %w(production vagrant)
set :default_stage, "vagrant"
require "capistrano/ext/multistage"
```

とするだけで、複数ステージにデプロイ可能。

config/deployディレクトリを作って

```ruby:config/deploy/production.rb
server "1xx.xxx.xxx.xx", :web, :app, :db, primary: true
set :user, "katryo"
set :port, 10022 #22から変更した
set :deploy_to, "/home/#{user}/apps/#{application}"
```

```ruby:config/deploy/vagrant.rb
server "localhost", :web, :app, :db, primary: true
set :user, "vagrant"
set :port, 2222
set :deploy_to, "/home/#{user}/apps/#{application}"

ssh_options[:keys] = [
  "#{ENV['HOME']}/.ssh/id_rsa",
  "#{ENV['HOME']}/.vagrant.d/insecure_private_key"
]
```

とdeployディレクトリに各サーバの設定を別々に書けばよい。参考:
 http://d.hatena.ne.jp/okinaka/20120520/1337476743

set :deploy_toが重複していて気持ち悪いけど、読み込みのタイミング上、production.rbとvagrant.rbのuserが読み込まれてからdeploy_toを設定する必要があるのでしかたなく2回同じ文を書いた。

# 設定したはずの環境変数がなぜ適用されない？

Capistranoでは、

```ruby:config/deploy.rb
ENV.update YAML.load(File.read(File.expand_path('../application.yml', __FILE__)))
set :default_environment, {
  "AWS_ACCESS_KEY_ID" => ENV["AWS_ACCESS_KEY_ID"],
  "AWS_SECRET_ACCESS_KEY" => ENV["AWS_SECRET_ACCESS_KEY"]
}
```

のように:default_environmentにsetすれば、シェルスクリプトを実行するrunの際に環境変数をセットできる。だから、開発環境の環境変数を引き継いで実行できる……はずだ。

この記事の環境変数の項でもそれについては説明した。 http://qiita.com/items/f410916d5314dad2de96 

実際に、前回のデプロイでは環境変数の引き継ぎに成功した。なぜ今回に限って引き継ぎに失敗するのか？


前回の手法をもういちど試したところ、引き継ぎには成功。
前回と今回の違いはどこか？　recipesにCapistranoの設定を分割したことか？　色々考え、調べたところ、原因が判明した。


# 原因

```
# storyblogはアプリケーション名
$ service unicorn_storyblog start
```

が原因だった。

**service hoge startは環境変数をほぼ引き継がない!!!**

serviceで起動した場合、環境変数はLANG, PATH, TERMの3つだけを適用する、らしい。"service /etc/init.d 違い"あたりで検索したところ、情報がいろいろ出てきた。

これらの記事を参考。
http://d.hatena.ne.jp/amari3/20111223/1324656530
http://linux.just4fun.biz/?%E9%80%86%E5%BC%95%E3%81%8DUNIX%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%2F%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9(%E3%83%87%E3%83%BC%E3%83%A2%E3%83%B3)%E3%81%AE%E8%B5%B7%E5%8B%95%E3%83%BB%E5%86%8D%E8%B5%B7%E5%8B%95%E3%83%BB%E5%81%9C%E6%AD%A2%E3%83%BB%E7%8A%B6%E6%85%8B%E5%8F%96%E5%BE%97

# 解決方法

なので、[Raiscasts#337](http://railscasts.com/episodes/337-capistrano-recipes)のCapistrano設定コードを書きかえ、

```ruby:config/recipes/unicorn.rb
run "service unicorn_#{application} #{command}"
```
となっている箇所を

```ruby:config/recipes/unicorn.rb
run "/etc/init.d/unicorn_#{application} #{command}"
```
と書きかえ。

nginxに関しても

```ruby:config/recipes/nginx.rb
run "#{sudo} service nginx #{command}"
```

となっているところを

```ruby:config/recipes/nginx.rb
run "#{sudo} /etc/init.d/nginx #{command}"
```
と書きかえた。


```
$ capistrano vagrant unicorn:stop
$ capistrano vagrant unicorn:start
```

としたら、見事環境変数を読み込んでくれた。やった！！！！ 半日悩んだ問題が解決した。

ちなみに最後のunicorn停止と起動に関して、再起動の

```
$ capistrano vagrant unicorn:restart
```

ではダメだった。Unicornはrestartの際、環境変数を引き継いで再起動するらしいのでそれが原因……なのかも。


ちょっと違うけど、参考。/etc/init.dからの起動時に環境変数を指定する方法 http://qiita.com/items/83bb3fb5cb7f46484d4b