module Heaven
# Top-level module for providers.
module Provider
# The capistrano provider.
class Capistrano < DefaultProvider
.....
def execute
return execute_and_log(["/usr/bin/true"]) if Rails.env.test?
unless File.exist?(checkout_directory)
log "Cloning #{repository_url} into #{checkout_directory}"
execute_and_log(["git", "clone", clone_url, checkout_directory])
end
Dir.chdir(checkout_directory) do
log "Fetching the latest code"
execute_and_log(%w{git fetch})
execute_and_log(["git", "reset", "--hard", sha])
deploy_command = [cap_path, environment, "部署的 cap 指令"]
log "Executing capistrano: #{deploy_command.join(" ")}"
execute_and_log(deploy_command)
end
end
end
end
end
前言
目前所在的公司裡頭是直接在本地端的 terminal 跑
cap staging deploy
指令。 capistrano 作為自動部署化的工具非常方便,但難免會遇到幾個問題:對一家新創來說,越穩定的開發效率和流程,就越能夠專注在產品當中。所以我們希望做到幾件事:
逐漸厭倦了在 terminal 打指令,ssh key 手動加的日子。於是打算自己研究有沒有更流暢的部署流程。
之前在 Sudo 裡頭,幸好有 @ocowchun 跟 @henry 兩位懶工,devops 做得非常完整,才能夠專注在開發功能,而不是一堆繁複的設定當中。(雖然才剛開發完就關閉服務了…)
目前覺得最合適的解決方案是搭配
hubot-deploy
以及heaven
來幫助部署。但 heaven 的文件實在寫的有夠爛。
看了老半天,甚至看了一下 source code 才知道到底該怎麼設定。於是決定將整個設定流程分享給大家,希望能夠減少其他 devops 們走歪路的時間。
主要流程
hubot 接收到部署指令後,會發送 github deployment,同時會觸發
deployment
這個事件,這時 github 就會發送 POST 給在 webhook 設置的 url(這邊接收者為heaven
),heaven 接收到請求之後,就會開始部署,再一一回傳我們想要知道的部數狀況。hubot-deploy
hubot-deploy 能夠用 slack 對 slack-bot 下指令的方式建立 github 的 deployment event。
heaven
是一個 Rails 的 application。主要有一個
/events
負責接收從 github deployment 傳來的 deployment 與 payload。設定步驟
heaven
的文件寫得不明所以hubot-deploy
也是草草帶過。幾乎只能靠著他們提供的流程圖,不斷的試錯與通靈。設定 hubot-deploy
利用 yeoman 產生 hubot,並且選擇
adapter
為slack
。在
package.json
中加入hubot-deploy
,或者 runnpm install hubot-deploy --save-dev
在
external-scripts.json
裡頭加入hubot-deploy
。到
apps.json
中設定想要部署的 repos 有哪些:這些資料在 hubot 送出 deployment 時會一併塞入 payload 當中。像是這樣:
特別要注意的是,provider 的欄位之後會送給 heaven,所以 provider 的值必須是 heaven 有的(之後會提到),或是自己實作 Provider。
這樣子我們的 hubot 就算設定完成了。先部署到 heroku 上測試看看,部署到 heroku 很簡單:
部署成功後,比較重要的變數有幾個:
HUBOT_GITHUB_TOKEN
: GITHUB_TOKEN,到個人帳號 > settings > personal access tokens 設定。設定好權限,因為 hubot 只是用來建立 repo 的 deployment,勾選 repo 即可。HUBOT_SLACK_TOKEN
: 你的 slack-bot token。可以到這裡設定全域變數可以到 heroku 的 dashboard 或是直接用 command line 設定:
測試一下是否成功。在你設定的頻道中輸入
hubot deploy:version
其中的
hubot
要跟你的機器人名稱相同,例如機器人的名稱為 tripmomo,那麼我就要輸入tripmomo deploy:version
。成功的話 hubot 會回應你目前的版本訊息。
確認 hubot 有送出 deployment 事件。輸入
hubot deploy app to statging
輸入
curl -H "Authorization: token YOUR_GITHUB_TOKEN" https://api.github.com/repos/my-github/my-repo/deployments
看看 deployment 是否建立成功。如果成功會回傳:更多 deployment API 可以到 github deployment API 看看。
設定 heaven
到 heaven 將 repo clone 下來。
設定全域變數
DEPLOYMENT_PRIVATE_KEY
: 因為 heaven 是用 ssh 登入,需要 private key。如果 server 在 ec2 上,也可以用 pem 的方式來設定。GITHUB_CLIENT_ID
: 到個人設定頁面 > OAuth application 產生GITHUB_CLIENT_SECRET
: 到個人設定頁面 > OAuth application 產生DATABASE_URL
: heaven 會建立資料庫紀錄 deploymentGITHUB_TOKEN
: heaven 會使用 gist 來當作 stdout stderr。所以在設定 token 時記得把gist
打勾勾。補充說明
DEPLOYMENT_PRIVATE_KEY
:原始檔案長這樣要修改成:
既然公開,這組 private key 當然報廢了
設定 Gemfile
因為 heaven 的動作會是拉下最新的 repo 後,執行
cap ... deploy
的指令,所以capistrano 的版本必須跟要部署的那個版本相同。同時,也要注意任何 asset 相關的 gem 也要一併放入 heaven。舉例來說,如果我的 Capfile 有用到那麼就要將這些 gem 加入 heaven 的 Gemfile 當中。因為 heaven 會將要部署的 repo 抓下來之後,進去資料夾輸入
cap staging ... deploy
的指令,所以如果沒有安裝相對應的 gem,heaven 就沒辦法部署了。串接 github deployment
routes.rb
中修改application/json
部署
如果是部署到 heroku 的話,因為 heaven 要開 redis 跟 resque。記得加入相對應的 add-on 以及
REDIS_URL
。同時別忘記了要建立資料庫
heroku run rake db:migrate
。hubot-deploy 常用指令
hubot deploy:version
目前版本hubot deploy repo
: 根據apps.json
deploy 指定的 repo name。hubot deploy repo/branch
:將指定 repo 的某一個 branch 部署到預設的 environment 中。可設定HUBOT_DEPLOY_DEFAULT_ENVIRONMENT
來決定hubot deploy repo/branch to staging
:將指定 repo 中的 branch 部署到staging
筆記
heaven 的文件雖然不明所以,但是程式碼跟測試寫得蠻完整的,熟悉 ruby 的開發者甚至可以將整個 heaven 架設好,修改一下程式碼,加上 routes,直接建立 UI 一鍵部署。
OptionParser::AmbiguousOption: ambiguous option: -s
:不確定是不是 Capistrano 更新之後指令有變動。解決方法是到lib/heaven/provider/capistrano.rb
修改deploy_command
因為 heaven 在部署時會使用 gist 當作 stdout 跟 stderr,在設定 GITHUB_TOKEN 的時候一定要記得把 gist 的 scope 打勾
Net::SSH::AuthenticationFailed: Authentication failed for user apps@staging.tripmoment.com
:SSH private_key 設定有誤。先確定這組 ssh key 是否已經加入 github,再來確定將passphrase
拿掉,並且將 ssh private key 變成一行加上 \n。ArgumentError: Could not parse PKey: no start line
沒有將 SSH private key 的 passphrase 移除後記
通常在公司裡頭,開發團隊人數不多的話,devops 都是由後端兼任的,前端比較少接觸。不過用「我是前端,我不需要管 devops」這種藉口搪塞自己不去學習好像也說不太過去,畢竟開發一個健全的系統絕對不可能只有前端而已。
這篇文章試著將文件中沒有提到或是省略的步驟整合起來,heaven 跟 hubot-deploy 的文件中有太多沒有提到的細節,導致整合起來時需要花不少時間試錯。希望能夠節省大家踩雷跟翻原始碼的時間。
這篇文章還有許多 devops 的細節沒有詳述,畢竟建立一套完整的 devops pipeline 需要時間,自己對於 CI/CD 的設定也還不夠熟悉。
參考資源: