AWSデプロイマスターになって、Herokuで消耗する過去に訣別しよう―。
この記事は単なる一本のログです。
だけれども上から下まで通すだけでAWSにアプリをデプロイすることができます。
コマンドの途中途中で必要なファイルの記述は混ぜてあります。
ただ環境ごとにエラーが出る可能性があるので、何かあったら教えてほしいです。
それでは以下より、「Tomajax」という仮想のRailsアプリを
30分位でデプロイしてみます。あまり親切な解説はないのでご勘弁。
【注意事項】
- [*]が先頭にあるコマンドはローカルで実行してください
- コピペする際に'=begin'と'=end'は外してください
- EC2インスタンスを作成する際はlinuxにしてください
- 以下に進む前にAWSのVPCとEC2は作成しておきましょう
参考動画:AWS講座 - VPC/EC2インスタンスの作成から接続まで - デプロイが終わったらSlack通知に挑戦してみましょう
参考動画:AWS講座 - capistranoデプロイのSlack通知設定
# 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