# 6.5 生產環境部署
## 概要:
本課時講解如何在 linux 服務器上部署 Rails 項目。
## 知識點:
1. linux
1. ssh
1. rvm
1. nginx
1. puma
1. mina
1. crontab
## 正文
現在,我們完成了一個簡單的 Rails 項目,我們把它部署到一臺 linux 服務器上。
### 6.5.1 Linux 服務器
為什么原則 Linux 服務器,原因很簡單:方便。網絡上有很多 Rails 部署的文章和問題解答,我們這里不做資料大搜羅,只講講部署的思路。
Linux 我們選擇常用的 CentOS 或者 Ubuntu 操作系統。有一些服務器會預制一些軟件,比如 apache,mysql(除了 client 還會默認安裝 server),這里我選擇一臺只安裝了操作系統的云服務器。
### 6.5.2 SSH
#### 6.5.2.1 開發機器連接服務器
在我們安裝,調試和部署環節中,最重要的工具是 ssh。
> SSH 為 Secure Shell 的縮寫,由 IETF 的網絡工作小組(Network Working Group)所制定;SSH 為建立在應用層和傳輸層基礎上的安全協議。SSH 是目前較可靠,專為遠程登錄會話和其他網絡服務提供安全性的協議。利用 SSH 協議可以有效防止遠程管理過程中的信息泄露問題。SSH最初是UNIX系統上的一個程序,后來又迅速擴展到其他操作平臺。SSH在正確使用時可彌補網絡中的漏洞。SSH客戶端適用于多種平臺。幾乎所有UNIX平臺—包括HP-UX、Linux、AIX、Solaris、Digital UNIX、Irix,以及其他平臺,都可運行SSH。(百度百科)
我們現在自己的開發機器上,創建 ssh:
~~~
ssh-keygen -t rsa
~~~
這樣,在 `~/.ssh/` 目錄下創建了兩個文件:id_rsa(私鑰),id_rsa.pub(公鑰)。公鑰放置在我們管理的服務器上,私鑰是我們連接服務器的關鍵,如果有必要,需要在其他地方做一個備份,如果開發機器損壞或丟失,而服務器又無法連接的話,會造成巨大的損失和時間浪費。當然,一般云服務器會提供應急的 web 管理界面,如果出現剛才講述的情形,我們重新創建一份私鑰和公鑰,并且替換服務器上的公鑰即可。
現在,我們在服務器上創建一個部署項目的賬號,deploy:
~~~
useradd deploy
~~~
注意,我們登錄這個賬號,并且也創建一份 ssh 的公鑰和私鑰,為什么?因為我們的開發機器需要連接github,bitbucket 這種代碼倉庫,它也是要通過 ssh 連接的。所以我們連接的形式是:
> 開發機器 ---ssh---> 服務器 ---ssh---> 代碼倉庫
現在,我們把公鑰傳遞到服務器上:
~~~
scp ./ssh/id_rsa.pub deploy@domain:/~/.ssh/authorized_keys
~~~
`authorized_keys` 是公鑰在服務器上的新名字,這個名字可以改掉。
為了避免每次登陸服務器都輸入密碼(也是防止密碼被暴力破解),我們配置下服務器的 sshd。這個文件通常在 `/etc/ssh/sshd_config`:
~~~
AuthorizedKeysFile .ssh/authorized_keys [1]
PermitEmptyPasswords no [2]
PermitRootLogin no [3]
PasswordAuthentication no [4]
~~~
[1] 這是一種適合多用戶的配置,比如,多個開發者登陸服務器,sshd 會校驗每個登陸賬戶下的 .ssh/authorized_keys。
[2] 禁止空密碼訪問,這是默認的
[3] 禁止 root 訪問,當我們開通服務器時,這個選項默認是 yes,這樣我們可以使用 root 登陸。當設置完 ssh 后,建議第一時間關閉它。
[4] 不使用密碼校驗,這是 ssh 會自動讀取、開發機器上的私鑰校驗,如果成功匹配,則自動登陸服務器。
設置完后,重啟 sshd 服務:
~~~
/etc/init.d/sshd restart
~~~
這時,我不建議立刻退出當前的 shell,建議新開一個終端窗口進行登陸測試。
#### 6.5.2.2 服務器連接代碼倉庫
從服務器連接代碼倉庫,比如 github 或者 bitbucket,還是國內的 gitcafe,原理都是一樣,需要把 公鑰粘貼到賬戶的 “SSH Keys” 中,然后使用命令行測試,這里給出常用的測試命令:
~~~
ssh -T git@github.com
ssh -T git@bitbucket.org
ssh -T git@gitcafe.com
~~~
如果提示成功,說明你可以正常的使用 ssh 形式連接代碼倉庫了。
### 6.5.3 RVM
在我們第一章的講解中,已經在本地安裝了 RVM,服務器的安裝是相同的步驟,只是要注意的是,我們已經使用 deploy 用戶安裝了 ssh,也用這個賬號來安裝 rvm,并且正常運行 ruby。
### 6.5.4 Nginx
[Nginx](http://nginx.org/) 是目前應用最廣的 web 服務器之一。關于 linux 的論述也有很多,我們這里只關注它和 Rails 項目的部署。
我們下載目前的 stable 版本,1.8.0,安裝之后,我們為 Rails 項目建立一個配置,這個配置通常放置在 `sites-enabled` 中方便維護,不過要確保,該目錄內的配置已經加載到 nginx 中:
`/.../nginx/conf/nginx.conf`
~~~
http {
include ../sites-enabled/*.conf;
}
~~~
Nginx 和 Rails 的通信有兩種方式,tcp 和 socket。現在我們使用 socket 通信。
為了更多的收集配置方法,我在 [這里](https://github.com/liwei78/rails4-puma-mina-nginx-deploy) 建立了一個代碼倉庫,大家可查看各種配置方式。在 [這里](https://github.com/liwei78/linux-doc) 還有其他的一些配置方式摘要。
### 6.5.5 Puma
[puma](http://puma.io),[unicorn](http://unicorn.bogomips.org/),[passenger](https://www.phusionpassenger.com/) 是常用的 Rails Server,這里我們使用 [puma](https://github.com/puma/puma)。
~~~
gem 'puma'
~~~
安裝這之后,我們有兩個命令,`puma` 和 `pumactl`。當 `rails s` 時,自動使用的是puma 啟動,為了在服務器上啟動,我們增加配置文件 `config/puma.rb`。
在服務器啟動 puma,使用 `pumactl` 命令,來進行 `start/stop/restart` 操作。
~~~
pumactl -F config/puma.rb start/stop/restart
~~~
### 6.5.6 Mina
為了方便部署新開發的代碼,我們需要自動部署工具,常用的是 [capistrano](https://github.com/capistrano/capistrano) 和 [mina](http://mina-deploy.github.io/mina/)。這里我們使用 mina 來部署代碼。
mina 的代碼在 [這里](https://github.com/liwei78/rails-practice-code/blob/master/chapter_6/shop/config/deploy.rb)。
我們先 `mina setup` 必備的部署目錄,以及需要的 `public/assets`,`log`,`tmp` 等目錄。
然后只需 `mina deploy` 即可部署最新的代碼。同時,在 deploy 中包裝了 puma 啟動的命令,使用時為 `mina puma:start/stop/restart`。
### 6.5.7 Crontab
如果有一些需要定期執行的 rake,或者定期清理 log,tmp,過期緩存等,需要執行 crontab 操作,為了方便編寫該語法,可以使用 [whenever](https://github.com/javan/whenever)。
~~~
wheneverize .
[add] writing `./config/schedule.rb'
~~~
編輯完 `schedule.rb` 后,運行 `whenever` 查看結果,并將命令粘貼到 `crontab -e` 中。
說明:
本章目的是介紹部署思路,如果有部署問題,可以搜索到很多解決方案,而且,[Ruby China 社區](https://ruby-china.org/topics) 有大量經驗分享,這是國內質量最高的 Ruby 社區,其中有很多經驗貼。
如果有問題通過搜索無法解決,可以在 Ruby 社區發帖詢問,發帖時,請仔細閱讀 [本帖](https://ruby-china.org/topics/24325)。
- 寫在前面
- 第一章 Ruby on Rails 概述
- Ruby on Rails 開發環境介紹
- Rails 文件簡介
- 用戶界面(UI)設計
- 第二章 Rails 中的資源
- 應用 scaffold 命令創建資源
- REST 架構
- 深入路由(routes)
- 第三章 Rails 中的視圖
- 布局和輔助方法
- 表單
- 視圖中的 AJAX 交互
- 模板引擎的使用
- 第四章 Rails 中的模型
- 模型的基礎操作
- 深入模型查詢
- 模型中的關聯關系
- 模型中的校驗
- 模型中的回調
- 第五章 Rails 中的控制器
- 控制器中的方法
- 控制器中的邏輯
- 第六章 Rails 的配置及部署
- Assets 管理
- 緩存及緩存服務
- 異步任務及郵件發送
- I18n
- 生產環境部署
- 常用 Gem
- 寫在后面