Capistrano で覚えておくアレの個人的なメモ


## 順番おしえてけろ

そういうのないやで。

ふつうにデプロイする時って `bundle exec cap production deploy` とかする。これしてもどの Task が走ってるかはよくわかんない。自前で Task とか足すときに最初から入ってる奴らの順番わからないと腹立たしい。

「このタスク実行するとどういう子タスクが走るんや」っての多分あるんだけど、よくわかんなかったので困った。

```shell
bundle exec cap production deploy --trace
```

こうするとまあなんかそれっぽいものが見える。（このままだと deploy 実行してしまうのでいろいろアレだけど）

### ちなみに

http://capistranorb.com/documentation/getting-started/flow/

に普通のやつは全部書いてある。けど手元の設定でどういうアレになるかは手元の設定ファイルが知ってるので、手元の設定ファイルに聞いたほうが良いと思うんだけど、違うんだろうか。

ちゃんと Deploy flow を把握して、更に中のタスクとか Plugin がどのタスクにフックしてるかとか理解していれば要らないと思う。けどぱっと見れれば便利だし、あればいちいちドキュメントを参照する手間も省けるのに。（実はあるのかもしれないけど、そういうコマンドみたいなものはドキュメントには見当たらなかった。コードは読んでない）

## config アップロードしろや

`config/database.yml` とか最初ないので、困る。あと shared_dir とかもないけど、これは自動で作ってくれるっぽいんだけど、まあそのへんの話。

`deploy:check` というのが最初の方に実行されて、この中にある `deploy:check:make_linked_dirs` で linked_files に設定されているファイルを配置するディレクトリが shared に作られる。つまり mkdir される。

```ruby
namespace :deploy do

  task :push_config do
    next unless any? :linked_files
    on release_roles :all do
      fetch(:linked_files).each do |file|
        unless test "[ -f #{shared_path.join file} ]"
          upload! file, "#{shared_path.join file}"
        end
      end
    end
  end
  before 'deploy:check:linked_files', 'deploy:push_config'

end
```

これでアップロードしてくれる。shared_path は Pathname のインスタンス。サーバー上にファイルがある時はアップロードしない（と思う）

http://ruby-doc.org/stdlib-2.1.0/libdoc/pathname/rdoc/Pathname.html

### 最初っていつなの

http://capistranorb.com/documentation/getting-started/flow/ 曰く、deploy という処理の流れ (Flow) の一番最初に `deploy:starting` という Task が書いてある。

https://github.com/capistrano/capistrano/blob/master/lib/capistrano/tasks/deploy.rake

を見る感じ、`deploy:starting` が `deploy:check` と `deploy:set_previous_revision` を実行している。で、`deploy:check` 内部で linked_dirs が不在の場合は mkdir が走ってる。 `linked_files` が不在のときはエラー出す感じになっている。

```
deploy:starting
  -> deploy:check
    -> #{scm}:check
    -> deploy:check:linked_dirs
    -> deploy:check:make_linked_dirs
    -> deploy:check:linked_files
```

こんな感じ。scm ってのは git とかが入る。上で書いた `deploy:push_config` は `deploy:check:linked_files` の前に実行するアレにしている。なんでかっていうと、`deploy:check:linked_files` が linked_files の存在確認をする Task だから、存在確認される前にアップロードしないと「ないやで」っていわれて死ぬ。

### 素朴な疑問

`deploy` ってのは Task じゃないのか。じゃあなんなのか。コードは読んでない。

## 環境変数

環境変数は敵である。正直未だによくわかってないし、上手いつきあい方がわからない。sudo すると bundle は消えるし、ruby のバージョンは変わる。まあこの辺の問題はなんとなく解決できるし本題じゃないんだけど。

Capistrano でリモートで実行するコマンドに環境変数を渡す場合、:default_environment を使う。んだけど、これ deploy.rb とか deploy/\<stage\>.rb とかに書く必要がある。両方リポジトリに乗るじゃん！

なのでこんな風にするのを見つけた。http://qiita.com/katryo/items/eea29e8733947a9bbf5a

```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"]
}
```

おおー、なるほど。ローカルの application.yml を環境変数に突っ込んで実行するわけだ。サーバー上にいろいろ置きたくない時は捗るやつだ。あと多分 figaro 使ってんのかも。

いちいちリスト書くのがめんどいのとローカルに環境変数置いとくほうがセキュリティ的に不安な気がしたので、普通に figaro 入れてサーバーに application.yml 配置しました。

### systemd

CentOS 7 使ってるので systemd で Unicorn をいろいろアレしてて、最初は EnvironmentFile= を利用していた。これだと .yml は読めない。で、dotenv 使うか悩んだけど、dotenv って README がめっちゃこう、「俺は開発環境用なんだぜ！」って匂いがしているので production で使わない方がいいのかなと思って figaro にした。根本的には一緒なのかもしれない。

ちなみに unicorn を systemd で起動するのは多分あんまりメジャーじゃない。capistrano 使うなら capistrano-unicorn とか使ったほうが丸いんだと思う。

```config/deploy.rb
set :pty, true

namespace :unicorn do
  task :stop do
    on roles(:web) do
      execute :sudo, :systemctl, :stop, :unicorn
    end
  end

  task :restart do
    on roles(:web) do
      if test "[ -f #{shared_path.join('tmp', 'pids', 'unicorn.pid')} ]"
        execute :sudo, :systemctl, :restart, :unicorn
      else
        invoke 'unicorn:start'
      end
    end
  end

  task :start do
    on roles(:web) do
      execute :sudo, :systemctl, :start, :unicorn
    end
  end
end
```

PID ファイルのパスは多分なんか設定を読む感じにした方がいいと思う。あとこの restart で本当に restart できるかといわれるとかなり疑問。この辺は restart の具体的な処理の話で Capistrano あんま関係ないので割愛するけど。

## Pty ってなんぞ

http://quanon.hateblo.jp/entry/2012/12/27/163537 に書いてあった。

けど、なんでデフォルトで false なのかよくわからない。調べたけど英語の記事読むの辛かった。みんな true にしてるけど、なぜ false なのかを書いてる人あんまいない気がするし俺もよくわかってない。

ちなみにこの辺に絡むらしい。 http://h3poteto.hatenablog.com/entry/2015/05/23/193119

## 結論

普通に勉強不足ですね。プロセス周りよくわかってないのヤバイと思う。