nginxとunicorn上で動いているrailsアプリをcapistranoでデプロイする

この記事の続きです

(今回の記事は実際に試してから時間が経っているため色々と漏れがあるかもしれません)

今回の目標

nginxとunicorn上で動いているrailsアプリをcapistranoでデプロイできること

capistranoとは

Capistrano is a remote server automation tool.

It supports the scripting and execution of arbitrary tasks, and includes a set of sane-default deployment workflows.

Capistrano can be used to:

  • Reliably deploy web application to any number of machines simultaneously, in sequence or as a rolling set
  • To automate audits of any number of machines (checking login logs, enumerating uptimes, and/or applying security patches)
  • To script arbitrary workflows over SSH
  • To automate common tasks in software teams.
  • To drive infrastructure provisioning tools such as chef-solo, Ansible or similar.

Capistrano is also very scriptable, and can be integrated with any other Ruby software to form part of a large r tool.

Capistranoはリモートサーバの自動化ツール

  • Webアプリケーションのデプロイが出来る
  • ログチェックなどの監査が出来る
  • SSH経由で動く
  • タスクの自動化
  • chef-soloなどのインフラプロビジョニングツールを実行できる

ふむ、ログのチェックとかセキュリティパッチ当てたりとかは聞いたことなかったな〜

$ bundle exec cap production deployのようにコマンド一発でデプロイできます

capコマンドを実行する

capistranocapistrano-rails を導入(Gemfileに書いてbundle install

導入後$ bundle exec cap installコマンドを叩くと必要なファイル群を作成してくれます

├── Capfile
├── config
│   ├── deploy
│   │   ├── production.rb
│   │   └── staging.rb
│   └── deploy.rb
└── lib
    └── capistrano
            └── tasks

githubを参考に設定(そのままコピペしました。必要に応じて修正すべきだと思います)

# Capfile
+ require 'capistrano/rails'

# config/deploy.rb
+ set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system', 'public/uploads')
+ set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')

続いてconfig配下のファイルにリポジトリやデプロイ先のサーバの設定を記述します

# config/deploy.rb
- set :application, 'my_app_name'
- set :repo_url, 'git@example.com:me/my_repo.git'
+ set :application, 'application_name'
+ set :repo_url, 'git@github.com:hogehoge/fugafuga.git'

# config/deploy/production.rb
- server 'example.com', user: 'deploy', roles: %w{app db web}, my_property: :my_value
+ server 'xx.xx.xx.xx', user: 'ubuntu', roles: %w{app db web}, my_property: :my_value

- set :ssh_options, {
-   keys: %w(/home/rlisowski/.ssh/id_rsa),
-   forward_agent: false,
-   auth_methods: %w(password)
- }
+ set :ssh_options, {
+   keys: %w(~/.ssh/oooooootuka.pem),
+   forward_agent: false,
+   auth_methods: %w(publickey)
+ }

設定終了。すわ!capコマンドを叩いたら対象サーバの/var/wwwディレクトリの権限が無いと怒られた

mkdir stderr: mkdir: cannot create directory '/var/www': Permission denied

そもそもwwwディレクトリ自体が無かったため作成して権限付与

ubuntu@ip-xx-xx-xx-xx:/var$ sudo mkdir www
ubuntu@ip-xx-xx-xx-xx:/var$ sudo chown ubuntu:ubuntu www

再度capコマンドを叩くが今度は別のエラーで怒られる

DEBUG [5687b546]        /usr/bin/env: bundle: No such file or directory

見て欲しいのと違うパスを見に行ってしまっている様子。rbenvを使っているので capistrano-rbenv をインストール

githubを参考に設定追加(バージョン以外コピペ)してcapリベンジ

# Capfile
-# require 'capistrano/rbenv'
+  require 'capistrano/rbenv'

# config/deploy.rb
+ set :rbenv_type, :user
+ set :rbenv_ruby, '2.2.2'
+ set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
+ set :rbenv_map_bins, %w{rake gem bundle ruby rails}
+ set :rbenv_roles, :all # default value

sqlite3がGemfileにありませんよと怒られる。Gemfileでgroup指定しているのが原因かと思い、外しても状況は変わらずで悩んでいたら、pushするのを忘れていました(・ω<)

Gem::LoadError: Specified 'sqlite3' for database adapter, but the gem is not loaded. Add `gem 'sqlite3'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord).

masterにpushするのもなんなので$ be cap production deploy BRANCH=hogehogeのようにブランチを指定してデプロイできるようにしてそこからpushする

# config/deploy.rb
+ set :branch, ENV['BRANCH'] || :master

push後、capコマンドが通ることを確認

unicorn, nginx連携する

下準備として、nginxやunicornで今までホームディレクトリに仮置きしていたアプリを見ていたので/var/www配下を見に行くようにする

# config/nginx.conf
- server unix:/home/ubuntu/my_new_application/tmp/sockets/.unicorn.sock fail_timeout=0;
+ server unix:/var/www/my_new_application/current/tmp/sockets/.unicorn.sock fail_timeout=0;

- root /home/ubuntu/my_new_application/public;
+ root /var/www/my_new_application/current/public;

- root /home/ubuntu/my_new_application/public;
+ root /var/www/my_new_application/current/public;

capistrano-unicorn-nginx を導入

Capistrano tasks for automatic and sensible unicorn + nginx configuraion.

Goals of this plugin:

  • automatic unicorn and nginx configuration for Rails apps
  • no manual ssh to the server required
  • zero downtime deployments enabled
  • support for single node as well as cluster deployments

Specifics:

  • generates nginx config file on the server (web role)
  • generates unicorn initializer and config files (app role) application is started automatically after server restart
  • capistrano tasks for server management, example: unicorn:restart see below for all available tasks
  • automatic load balancing setup when there are multiple app nodes

capistrano-unicorn-nginx works only with Capistrano 3!

unicorn + nginx環境で最適化したcapistranoタスクだよ☆みたいな感じ

プラグインの目的:

  • Railsアプリのための設定の自動化
  • 手動SSHは不要
  • 中断時間がない
  • 複数環境へのデプロイもサポートしている

仕様:

  • nginxの設定ファイルを生成
  • サーバ再起動後にunicornの初期化とconfigファイルの生成を自動的に始める
  • unicorn:restartなどのサーバ管理タスクが使える
  • 複数ノードの時負荷を分散してくれる?

capistrano3でのみ動作する!


Capfileやconfig配下の設定ファイルを修正

# Capfile
+ require 'capistrano/unicorn_nginx'

# config/nginx.conf
- server unix:/var/www/my_new_application/current/tmp/sockets/.unicorn.sock fail_timeout=0;
+ server unix:/tmp/unicorn.my_new_application_production.sock fail_timeout=0;

# config/unicorn.rb
- listen '/var/www/my_new_application/current/tmp/sockets/.unicorn.sock' # by default Unicorn listens on port 8080
+ listen '/tmp/unicorn.my_new_application_production.sock' # by default Unicorn listens on port 8080

上記対応で、capコマンドを叩いた後にunicornとnginxを再起動してくれるようになりました


今回は一度動作させることを確認した後でcapistranoデプロイするという手順を踏みましたが、configファイルを自動生成してくれるらしいので、最初からcapistrano-unicorn-nginxを使ったほうが良かったのかなと思ったりしました。