AWSはこれで大丈夫｜unicorn + nginx + capistrano + slackistrano のコマンド一覧

AWSデプロイマスターになって、Herokuで消耗する過去に訣別しよう―。

この記事は単なる一本のログです。
だけれども上から下まで通すだけでAWSにアプリをデプロイすることができます。
コマンドの途中途中で必要なファイルの記述は混ぜてあります。
ただ環境ごとにエラーが出る可能性があるので、何かあったら教えてほしいです。

それでは以下より、「Tomajax」という仮想のRailsアプリを
30分位でデプロイしてみます。あまり親切な解説はないのでご勘弁。


---
**【注意事項】**                          
1. [＊]が先頭にあるコマンドはローカルで実行してください
2. コピペする際に'=begin'と'=end'は外してください
3. EC２インスタンスを作成する際はlinuxにしてください
4. 以下に進む前にAWSのVPCとEC2は作成しておきましょう
   参考動画：[AWS講座 - VPC/EC2インスタンスの作成から接続まで](https://youtu.be/TDaLNHOL-h4)
5. デプロイが終わったらSlack通知に挑戦してみましょう
   参考動画：[AWS講座 - capistranoデプロイのSlack通知設定](https://youtu.be/Vff-Qhv2Kj8)


```ruby:
# connect to ec2
*[ ~ ] $: mv Downloads/tomajax.pem .ssh/
*[ ~ ] $: cd .ssh/
*[ .ssh ] $: chmod 600 tomajax.pem
*[ .ssh ] $: ssh -i tomajax.pem ec2-user@54.92.121.123

-----------------------------------------
# add user
[ec2-user|~]$ sudo adduser tomajax
[ec2-user|~]$ sudo passwd tomajax
[ec2-user|~]$ sudo visudo
[ec2-user|~]$ sudo su - tomajax

-----------------------------------------
# enable to connect as new user
*[ ~ ] $: cd .ssh/
*[ .ssh ] $: ssh-keygen -t rsa
[tomajax|~]$ mkdir .ssh
[tomajax|~]$ chmod 700 .ssh
[tomajax|~]$ cd .ssh
[tomajax|.ssh]$ touch authorized_keys
[tomajax|.ssh]$ chmod 600 authorized_keys
[tomajax|.ssh]$ sudo vi authorized_keys
[tomajax|.ssh]$ exit

-----------------------------------------
# install plugins
[tomajax|~]$ sudo yum install \
git make gcc-c++ patch \
openssl-devel \
libyaml-devel libffi-devel libicu-devel \
libxml2 libxslt libxml2-devel libxslt-devel \
zlib-devel readline-devel \
mysql mysql-server mysql-devel \
ImageMagick ImageMagick-devel \
epel-release

-----------------------------------------
# install nodejs
[tomajax|~]$ sudo yum install nodejs npm --enablerepo=epel

-----------------------------------------
# install rbenv
[tomajax|~]$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
[tomajax|~]$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
"
[tomajax|~]$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
[tomajax|~]$ source .bash_profile
[tomajax|~]$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
[tomajax|~]$ rbenv rehash

-----------------------------------------
# install ruby 2.1.3
[tomajax|~]$ rbenv install -v 2.1.3
[tomajax|~]$ rbenv global 2.1.3
[tomajax|~]$ rbenv rehash
[tomajax|~]$ ruby -v

-----------------------------------------
# add gems
*[ tomajax ] $: vi Gemfile
=begin[Gemfile]
  group :production, :staging do
    gem 'unicorn'
    gem 'capistrano',          require: false
    gem 'capistrano-rails',    require: false
    gem 'capistrano-rbenv',    require: false
    gem 'capistrano-bundler',  require: false
    gem 'capistrano3-unicorn', require: false
    gem 'slackistrano',        require: false
  end
=end
*[ tomajax ] $: bundle

-----------------------------------------
# add unicorn config file
*[ tomajax ] $: touch config/unicorn.conf.rb
*[ tomajax ] $: vi config/unicorn.conf.rb
=begin[config/unicorn.conf.rb]
  # set lets
  $worker  = 2
  $timeout = 30
  $app_dir = "/var/www/tomajax/current"
  $listen  = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir
  $pid     = File.expand_path 'tmp/pids/unicorn.pid', $app_dir
  $std_log = File.expand_path 'log/unicorn.log', $app_dir
  # set config
  worker_processes  $worker
  working_directory $app_dir
  stderr_path $std_log
  stdout_path $std_log
  timeout $timeout
  listen  $listen
  pid $pid
  # loading booster
  preload_app true
  # before starting processes
  before_fork do |server, worker|
    defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
    old_pid = "#{server.config[:pid]}.oldbin"
    if old_pid != server.pid
      begin
        Process.kill "QUIT", File.read(old_pid).to_i
      rescue Errno::ENOENT, Errno::ESRCH
      end
    end
  end
  # after finishing processes
  after_fork do |server, worker|
    defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
  end
=end

-----------------------------------------
# set config for capistrano
*[ tomajax ] $: bundle exec cap install
*[ tomajax ] $: vi Capfile
=begin[Capfile]
  # Load DSL and set up stages
  require 'capistrano/setup'
  # Include default deployment tasks
  require 'capistrano/deploy'
  # Include tasks from other gems included in your Gemfile
  require 'capistrano/rbenv'
  require 'capistrano/bundler'
  require 'capistrano/rails/assets'
  require 'capistrano/rails/migrations'
  # Include slack notifier
  # require 'slackistrano'
  # Load custom tasks from `lib/capistrano/tasks` if you have any defined
  Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
=end
*[ tomajax ] $: vi lib/capistrano/tasks/unicorn.cap
=begin[lib/capistrano/tasks/unicorn.cap]
  namespace :unicorn do
    task :environment do
      set :unicorn_pid,    "#{current_path}/tmp/pids/unicorn.pid"
      set :unicorn_config, "#{current_path}/config/unicorn.conf.rb"
    end
    def start_unicorn
      within current_path do
        execute :bundle, :exec, :unicorn, "-c #{fetch(:unicorn_config)} -E #{fetch(:rails_env)} -D"
      end
    end
    def stop_unicorn
      execute :kill, "-s QUIT $(< #{fetch(:unicorn_pid)})"
    end
    def reload_unicorn
      execute :kill, "-s USR2 $(< #{fetch(:unicorn_pid)})"
    end
    def force_stop_unicorn
      execute :kill, "$(< #{fetch(:unicorn_pid)})"
    end
    desc "Start unicorn server"
    task start: :environment do
      on roles(:app) do
        start_unicorn
      end
    end
    desc "Stop unicorn server gracefully"
    task stop: :environment do
      on roles(:app) do
        stop_unicorn
      end
    end
    desc "Restart unicorn server gracefully"
    task restart: :environment do
      on roles(:app) do
        if test("[ -f #{fetch(:unicorn_pid)} ]")
          reload_unicorn
        else
          start_unicorn
        end
      end
    end
    desc "Stop unicorn server immediately"
    task force_stop: :environment do
      on roles(:app) do
        force_stop_unicorn
      end
    end
  end
=end
*[ tomajax ] $: vi config/deploy/production.rb
=begin[config/deploy/production.rb]
  server   '127.0.0.1',
    user:  'tomajax',
    roles: %w{app db web},
    ssh_options: {
      keys: [
        # for ec2
        File.expand_path('~/.ssh/tomajax'),
        # for github
        File.expand_path('~/.ssh/id_rsa')
      ],
      forward_agent: true,
      auth_methods: %w(publickey)
    }
=end
*[ tomajax ] $: vi config/deploy.rb
=begin[config/deploy.rb]
  # config valid only for current version of Capistrano
  lock '3.4.0'
  set :rbenv_ruby,    '2.1.3'
  set :application,   'tomajax'
  set :repo_url,      'git@github.com:Hogeo/tomajax.git'
  set :branch,        'master'
  set :deploy_to,     '/var/www/tomajax'
  set :linked_dirs,   fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
  set :keep_releases, 3
  # set values for slackistrano deployment notifier
  # set :slack_webhook,      'https://hooks.slack.com/services/T02B5F7S3/B0ATNSDB6/ERhof0moz0987uLtiXXXXXX'
  # set :slack_icon_url,     'https://s3-ap-northeast-1.amazonaws.com/tomajax/images/tomato3_small.png'
  # set :slack_username,     'Tomajax'
  # set :slack_msg_starting, "#{ENV['USER'] || ENV['USERNAME']} による #{fetch :branch} ブランチの #{fetch :rails_env, 'production'} 環境へのデプロイが始まります。"
  # set :slack_msg_finished, "#{ENV['USER'] || ENV['USERNAME']} による #{fetch :branch} ブランチの #{fetch :rails_env, 'production'} 環境へのデプロイが成功しました！！"
  # set :slack_msg_failed,   "#{ENV['USER'] || ENV['USERNAME']} による #{fetch :branch} ブランチの #{fetch :rails_env, 'production'} 環境へのデプロイが失敗しました..."
  namespace :deploy do
    desc 'Restart application'
    task :restart do
      invoke 'unicorn:restart'
    end
    desc 'Create database'
    task :db_create do
      on roles(:db) do |host|
        with rails_env: fetch(:rails_env) do
          within current_path do
            execute :bundle, :exec, :rake, 'db:create'
          end
        end
      end
    end
    desc 'Run seed'
    task :seed do
      on roles(:app) do
        with rails_env: fetch(:rails_env) do
          within current_path do
            execute :bundle, :exec, :rake, 'db:seed'
          end
        end
      end
    end
    after :publishing, :restart
    after :restart,    :clear_cache do
      on roles(:web), in: :groups, limit: 3, wait: 10 do; end
    end
    after :finished,   :cleanup
  end
=end

-----------------------------------------
# add secret_key_base
*[ tomajax ] $: rake secret
*[ tomajax ] $: vi config/secrets.yml
=begin[config/secrets.yml]
  production:
    secret_key_base: c013ghj7bc1b87xxx0099ace86ca58a9ca000ce3d0000000a4ee86acad7a4ba4f189823xxxxx635326a9b17ecf8fe047a293aa05562be4fec6c544aa4e963xxx
=end

-----------------------------------------
# push to remote repository
*[ tomajax ] $: git add .
*[ tomajax ] $: git commit -m 'set environment for deployment'
*[ tomajax ] $: git push origin master

-----------------------------------------
# install nginx
[tomajax|~]$ sudo yum install nginx
[tomajax|~]$ cd /etc/nginx/conf.d/
[tomajax|conf.d]$ sudo touch tomajax.conf
[tomajax|conf.d]$ sudo vi tomajax.conf
=begin[/etc/nginx/conf.d/tomajax.conf]
  # log directory
  error_log  /var/www/tomajax/current/log/nginx.error.log;
  access_log /var/www/tomajax/current/log/nginx.access.log;
  # max body size
  client_max_body_size 2G;
  upstream app_server {
    # for UNIX domain socket setups
    server unix:/var/www/tomajax/current/tmp/sockets/.unicorn.sock fail_timeout=0;
  }
  server {
    listen 80;
    server_name 127.0.0.1;
    # nginx so increasing this is generally safe...
    keepalive_timeout 5;
    # path for static files
    root /var/www/tomajax/current/public;
    # page cache loading
    try_files $uri/index.html $uri.html $uri @app;
    location @app {
      # HTTP headers
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://app_server;
    }
    # Rails error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/tomajax/current/public;
    }
  }
=end

-----------------------------------------
# make dir for application
[tomajax|~]$ sudo mkdir /var/www
[tomajax|~]$ cd /var
[tomajax|var]$ chown tomajax www
[tomajax|var]$ sudo chown tomajax www

-----------------------------------------
# install bundler
[tomajax|var]$ cd
[tomajax|~]$ gem install bundler

-----------------------------------------
# change settings for production at database.yml
*[ tomajax ] $: vi config/database.yml
=begin[config/database.yml]
  production:
    <<: *default
    database: tomajax_production
    username: root
=end

-----------------------------------------
# change settings for mysql & create database
[tomajax|~]$ mysql --help
[tomajax|~]$ sudo vi /etc/my.cnf
[tomajax|~]$ sudo service mysqld start
[tomajax|~]$ mysql -u root -p
[mysql]> CREATE DATABASE tomajax_production;
[mysql]> SHOW DATABASES;
[mysql]> QUIT;

-----------------------------------------
# remove ec2-user & start to deploy
[tomajax|~]$ sudo userdel -r ec2-user
[tomajax|~]$ sudo service nginx start
[tomajax|~]$ exit
*[ tomajax ] $: bundle exec cap production deploy

```