over 3 years ago

本章的作業目標:

  • 用手動的方式將寫好的 Rails 專案 deploy 到遠端 Server 上
  • 改 Capristrano 自動化部署,一個指令完成 Deploy

用手動的方式將寫好的 Rails 專案 deploy 到遠端 Server 上

本機端的前置作業

打開根目錄的 .gitignore ,輸入

.gitignore
...
...
+ /config/database.yml
...
...

這個設定會將 config/database.yml 從版本控制中移除

Gemfile 修改

原本

Gemfile
...
...
- gem 'sqlite3'
+ # gem 'sqlite3'
...
- # gem 'therubyracer', platforms: :ruby
+ gem 'therubyracer', platforms: :ruby
...
+ group :development do
+   gem "sqlite3"
+ end

+ group :production do
+   gem "mysql2"
+ end
...
...

config/initializers/devise.rb 修改

config/initializers/devise.rb
...
...
-  # config.secret_key = '(一堆亂碼)'
+  config.secret_key = '(一堆亂碼)'
...
...

最後將寫好的專案放到你的 github 上 ( 如果要看範例教材在 https://github.com/sdlong/rails101s )

Production 端設定

作業系統版本: Ubuntu 14.04 LTS @linode

我們會在 production 上創建二個帳號
一個是 root ( 擁有最高權限,系統安裝與設定用 )
一個是 apps ( deploy 用,沒有系統異動權限 )

所有系統安裝都是用 root 權限的帳號來設定

現在我們已經進入全新剛建好的 Ubuntu 14.04

系統更新

sudo apt-get update
sudo apt-get upgrade
sudo apt-get autoremove

設定時區

sudo dpkg-reconfigure tzdata

安裝 MySQL

sudo apt-get install mysql-common mysql-client libmysqlclient-dev mysql-server
會要你輸入 mysql 的 root 密碼 ( 這邊以 123456 為範例,後面會有資料庫設定 )

mysql -u root -p => 輸入 root 密碼 ( 本範例是 123456 )

看到這個畫面就代表安裝成功 ( 打 exit 離開 )

安裝需要的套件 ( 含 git )

sudo apt-get install build-essential git-core curl libssl-dev libreadline5 libreadline-gplv2-dev zlib1g zlib1g-dev libmysqlclient-dev libcurl4-openssl-dev libxslt-dev libxml2-dev libffi-dev

安裝 rbenv

sudo git clone git://github.com/sstephenson/rbenv.git /usr/local/rbenv

sudo vi /etc/profile.d/rbenv.sh
檔案裡面寫入:

export RBENV_ROOT=/usr/local/rbenv
export PATH="$RBENV_ROOT/bin:$PATH" 
eval "$(rbenv init -)" 

存檔

修改檔案權限

sudo chmod +x /etc/profile.d/rbenv.sh

安裝 ruby-build

git clone git://github.com/sstephenson/ruby-build.git /tmp/ruby-build
sudo /tmp/ruby-build/install.sh

安裝 ruby ( 本次用 2.3.0 版本 )

rbenv install 2.3.0
rbenv global 2.3.0
rbenv rehash

ruby -v

看到這張圖就代表安裝完成

(PS: 舊圖是 2.1.2, 實際上應該要是 2.3.0 )

安裝 ImageMagick

apt-get install imagemagick

安裝 Passenger

gem install passenger

用 Passenger 安裝 Nginx

passenger-install-nginx-module

  • 第一個選擇 1. Yes: download,
  • 第二個選擇 1. compile and install Nginx for me.
  • 第三個選擇: 安裝到 /opt/nginx (直接按 enter)
安裝 Nginx init script

git clone git://github.com/jnstq/rails-nginx-passenger-ubuntu.git
sudo mv rails-nginx-passenger-ubuntu/nginx/nginx /etc/init.d/nginx
sudo chown root:root /etc/init.d/nginx

設定 Nginx conf

vim /opt/nginx/conf/nginx.conf

/opt/nginx/conf/nginx.conf
...
...
  server {       
       listen 80;
       server_name localhost;
+      root /home/apps/rails101s/public;   # 這行會對應到你的專案資料夾名稱,如果你不是用rails101s,就把 rails101s 改成你的專案名稱
+      passenger_enabled on;     
      
-       #charset koi8-r;
-       #access_log  logs/host.access.log  main;

-       location / {
-           root   html;
-           index  index.html index.htm;
-       }

-       #error_page  404              /404.html;
-       # redirect server error pages to the static page /50x.html
-       #
-       error_page   500 502 503 504  /50x.html;
-       location = /50x.html {
-           root   html;
-       }

-       # proxy the PHP scripts to Apache listening on 127.0.0.1:80
-       #
-       #location ~ \.php$ {
-       #    proxy_pass   http://127.0.0.1;
-       #}

-       # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
-       #
-       #location ~ \.php$ {
-       #    root           html;
-       #    fastcgi_pass   127.0.0.1:9000;
-       #    fastcgi_index  index.php;
-       #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
-       #    include        fastcgi_params;
-       #}

-       # deny access to .htaccess files, if Apache's document root
-       # concurs with nginx's one
-       #
-       #location ~ /\.ht {
-       #    deny  all;
-       #}
    }
...
...

將 nginx server 重開機

sudo /etc/init.d/nginx restart
出現這個畫面,代表 nginx server 安裝成功,可以運作了

連到該 server 的 ip / 網址

root 帳號的系統設定完成,接下來做 apps 帳號的設定


安裝必要的 gem

gem install bundle
gem install execjs

新增 User: apps

sudo adduser apps
輸入密碼與相關資料

切換 User: apps

sudo su - apps

確認 ruby 版本是否為安裝的 2.3.0
ruby -v

若不是 2.3.0 ,可改用 ssh apps@ip 用 apps 登入
再檢查一次版本是否正確,正確才執行下面的動作

ssh-keygen => 連按三個 enter
more ~/.ssh/id_rsa.pub # 把出來的內容貼到 github account setting => ssh_key 上
git clone git@github.com:sdlong/rails101s.git ( 此為範例用,或是你的 git )

設定 config/database.yml

vim ~/rails101s/config/database.yml

config/database.yml
production:
  adapter: mysql2
  encoding: utf8
  database: rails101 
  pool: 5 
  username: root 
  password: "123456" 
  socket: /var/run/mysqld/mysqld.sock 

username 跟 password 的值就是你安裝 MySQL 時設定的值

安裝專案需要的 gem 與 rails rake 執行

cd rails101
bundle install
RAILS_ENV=production rake db:create # 建立 production database
RAILS_ENV=production rake db:migrate # 建立 production database 欄位
RAILS_ENV=production rake assets:precompile # 建立 production assets

檢查是否 deploy 成功

重開 nginx server
sudo /etc/init.d/nginx restart

會發現這個問題

這是因為我們的 config/secret.yml 裡面沒有 production 的密碼

vi config/secrets.yml

把 其中的一行 密碼 貼到 production 那一行,存檔即可

再重開 nginx server
sudo /etc/init.d/nginx restart

Deploy 完成!!


改 Capristrano 自動化部署,一個指令完成 Deploy

我們會發現,每次網站一改版,就要重新 git clone , 設定 database.yml, secret.yml, 跑一系列 rake 指令
要花太多人工的時間,而且很難確保不會在手動執行的過程中手殘造成悲劇

所以我們改用自動化部署,來幫助我們自動處理,而且還有 rollback 的功能,萬一本次的版本炸掉,還能回溯上個版本

前置作業

(本機端)
more ~/.ssh/id_rsa.pub

copy 出來的值

(用 apps 登入 production server )

vim /home/apps/.ssh/authorized_keys
=> 貼上 copy 的值,存檔

以後就可以在開發端用 $ ssh apps@(server.ip) 直接連過去

建立 rails101s/shared/config 資料夾

mkdir ~/rails101s/shared
mkdir ~/rails101s/shared/config

將 rails101s/config 裡的 database.yml 跟 secret.yml 複製到 rails101s/shared/config 資料夾

cp ~/rails101s/config/database.yml ~/rails101s/shared/config/
cp ~/rails101s/config/secrets.yml ~/rails101s/shared/config/

開發端設定

安裝 gem

打開 Gemfile

Gemfile
...
...
group :development do
  gem "sqlite3"
+ gem "capistrano",  "~> 3.1", require: false
+ gem "capistrano-rvm", "~> 0.1.1", require: false
+ gem "capistrano-rails", "~> 1.1", require: false
+ gem "capistrano-rbenv", "~> 2.0", require: false # production server use rbenv
end
...
...

安裝 gem
bundle install

跑 capistrano install
cap install

設定 config/deploy.rb

原本

config/deploy.rb
# config valid only for current version of Capistrano
lock '3.3.5'

- set :application, 'my_app_name'
+ # 你的 application name
+ set :application, 'rails101s' 

- set :repo_url, 'git@example.com:me/my_repo.git'
+ # 你的 git url
+ set :repo_url, 'https://github.com/sdlong/rails101s.git' 

+ # rbenv 的設定
+ set :rbenv_type, :user 
+ set :rbenv_ruby, "2.1.2"
+ set :rbenv_path, "/usr/local/rbenv"
+ 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 deploy_to directory is /var/www/my_app_name
- # set :deploy_to, '/var/www/my_app_name'
+ # deploy 的資料夾位置 (prodution)
+ set :deploy_to, "/home/apps/rails101"

# Default value for :log_level is :debug
- # set :log_level, :debug
+ set :log_level, :debug

# Default value for :linked_files is []
- # set :linked_files, fetch(:linked_files, []).push('config/database.yml')
+ # git clone 完成後會從 shared 資料夾 copy 過去的檔案
+ set :linked_files, %w(config/database.yml config/secrets.yml) 

# Default value for linked_dirs is []
- # set :linked_dirs, fetch(:linked_dirs, []).push('bin', 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
+ # git clone 完成後會從 shared 資料夾 copy 過去的資料夾
+ set :linked_dirs, fetch(:linked_dirs, []).push("bin", "log", "tmp/pids", "tmp/cache", "tmp/sockets", "vendor/bundle", "public/system") 

# Default branch is :master
# ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call

# Default value for :scm is :git
# set :scm, :git

# Default value for :format is :pretty
# set :format, :pretty

# Default value for :pty is false
# set :pty, true


# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }

# Default value for keep_releases is 5
# set :keep_releases, 5

namespace :deploy do

  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
      # Here we can do anything such as:
-     # within release_path do
-     #   execute :rake, 'cache:clear'
-     # end
+     within release_path do
+       execute :rake, 'cache:clear'
+     end
    end
  end

end
設定 Capfile
Capfile
...
...
# require 'capistrano/rvm'
- # require 'capistrano/rbenv'
+ require 'capistrano/rbenv'
# require 'capistrano/chruby'
- # require 'capistrano/bundler'
+ require 'capistrano/bundler' # 會自動幫你跑 bundle install
- # require 'capistrano/rails/assets'
+ require 'capistrano/rails/assets' # 會自動幫你跑 rake assets:precompile
- # require 'capistrano/rails/migrations'
+ require 'capistrano/rails/migrations' # 會自動幫你跑 rake db:migrate
# require 'capistrano/passenger'

...
...
設定 config/deploy/production.rb
config/deploy/production.rb
...
...
- role :app, %w{deploy@example.com}
- role :web, %w{deploy@example.com}
- role :db,  %w{deploy@example.com}
+ # 你設定的 deploy 用帳號 & ip ( 本教材的 ip 是範例 )
+ role :app, %w{apps@106.185.49.108}
+ role :web, %w{apps@106.185.49.108}
+ role :db,  %w{apps@106.185.49.108}
...
- server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value
+ # server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value
...
...
執行 deploy:check

cap production deploy:check
將會做 deploy 前的檢查,並把遠端 (production) 需要的資料夾建立,如果有 error 請檢查錯誤訊息去 debug

執行 deploy 程序

cap production deploy
正式運作自動化 deploy

修改 nginx.conf

由於 capristrano 將專案的位置改到 rails101s/current 所以要將 nginx 上 server 對應的位置修改

sudo vim /opt/nginx/conf/nginx.conf

/opt/nginx/conf/nginx.conf
...
...
    server {
        listen       80;
        server_name  localhost;
-       root /home/apps/rails101s/public;
+       root /home/apps/rails101s/current/public;
        passenger_enabled on;
    }
...
...
重開 nginx, 看看是否 deploy 成功

sudo /etc/init.d/nginx restart

=> 用瀏覽器瀏覽你的網站吧!


以後專案有任何異動,只要 push 到 github ( master 主線 ) 以後
直接輸入 cap production deploy 即可自動跑完 deploy

萬一新版本的專案炸掉,還可以輸入 cap production deploy:rollback 回溯上個版本

production 端的 rails101s 根目錄會有三個資料夾

current <== 現在實際上線運作的版本
releases <== 你過去 deploy 的記錄 ( 預設存五個 , 最新版的 = current )
shared <== 你不想放在 git 上給人看到的檔案(例如 database.yml) / logs / 圖片 ... etc 的放置處,新版本 deploy 完後 capristrano 會自動 copy 一份過去到 current 上

現在根目錄除了這三個資料以外的檔案都沒有用到了,如果嫌太亂可以這些檔案刪除掉

← [ 2.0 ] 8. 撰寫 db:seed 與 自動化重整資料庫程式 Intro →
 
comments powered by Disqus