蒼時弦也
蒼時弦也
資深軟體工程師
發表於

Capistrano to Vagrant 自動部署心得

之前寫過一篇關於 Vagrant + Capistrano + GitLab 的自動化部署介紹。

不過當時因為一些問題,卡著沒有繼續完成測試。 最近因為某些原因,需要一個 Nightly-like (不一定會每日更新,取決于 commit) 的環境,所以只好硬著頭皮把全部的問題解決了⋯⋯

關於安裝與建制的部分就不多做討論,讓我們直接「切入核心」來討論 cap deploy 失敗的主要原因吧!

首先,來看看本次環境的設定(基本上跟上次差不多)

  • Ubuntu 13.10 (Server)
    • GitLab
    • GitLab CI
    • VMs * GitLab CI Runner#1 * Nightly Server

那麼,主要會發生問題的部分其實大多是在 CI Runner 跟 Nightly Server 上。 首先,我們要確定兩個環境都有正確可運作的 Ruby 版本。 (這邊是用 RVM 進行處理)

因為是跑 Rails 所以需要對應的 JS 套件,我選用的是 Node.JS (但是預設版本非常舊)所以採用第三方套件安裝較新的版本。

sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodejs

在安裝 JS 相關套件的時候,就不會發生錯誤。 假設使用的是 MySQL 的話,則要一並安裝對應的 Library 上去。

sudo apt-get install libmysqlclient-dev

至於使用的 Capistrano Gem 則有一些改變。

1  # Capistrano Deploy
2  gem 'capistrano'
3  gem 'capistrano-Rails'
4  gem 'capistrano3-puma'
5  gem 'rvm1-capistrano3', require: false

關於官方的 capistrano-bundler 會選擇安裝在 shared 目錄,一直導致安裝失敗。 因此不使用(也會和 rvm1-capistrano3 衝突)

這次使用 Puma 作為 Web Server 所以加入了 Puma 的部分(主要是自動啟動伺服器的關係) 而 rvm1-capistrano3 目前是 Host 在 rvm 的 Github 下,雖然 Capistrano 官方也有一套 rvm 用的外掛,但是就是不會切換 Ruby 版本,所以只好改為這套。

註:Capfile 請記得更改去 require 對應的套件。

到這邊,就剩下 Shell Script 的部分。 不過在這之前,我們得先做一下簡易的 Setup 讓 Nightly Server 正常運作。

(以下操作是在 GitLab-Runner 上)

git clone [email protected]:my-repo
cd my-repo
git checkout develop
bundle install
cap nightly deploy:check # nightly 是我另外在 config/deploy 新增的 nightly.rb 檔案
cap nightly puma:config

基本上,應該要 deploy:check 正常,以及 puma:config 上傳正確的檔案才能夠順利運作。 (puma:config 會自動在遠端產生 shared/puma.rb 設定檔,請確定跟預期的設定相同)

然後強烈建議先跑過 rvm1:install:gems 這個指令。

cap nightly rvm1:install:gems

然後把一些相依的 Gem 問題都解掉。

註:雖然可以在 config/deploy.rb 裡面加入 before :deploy, "rvm1:install:gems" 但是似乎會召喚 rspec 出來跑,即使沒有安裝(反而會出錯)

rvm1:install:Ruby 也可以跑看看,確定程式預期的 Ruby 版本跟我們安裝的是相同的。 (一般來說用 rvm install 2.0.0 就可以裝到對應的版本)

註:rvm1:install:Ruby 似乎因為 rvm install . 有問題,而無法自動安裝 Ruby

到目前為止,就剩下一些設定了! 以下建議 Rails 使用者打開(但是要預先設定好檔案)

1# Default value for :linked_files is []
2set :linked_files, %w{config/database.yml}
3
4# Default value for linked_dirs is []
5set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}

可以先編輯 shared/config/database.yml 設定好資料庫的連接。 (建議用 MySQL / Postgresql 因為 SQLte 每次都會重設⋯⋯)

最後是撰寫 CI 的測試 Shell Script 了! (這邊只是參考,因為目前系統還有部分沒有整併 Script 的版本,所以暫時將測試部分分離出來)

GitLab CI 中只要這樣設定即可:./script/gitlab_ci

然後我們產生一個名為 gitlab_ci 的檔案。

1touch script/gitlab_ci
2chmod +x script/gitlab_ci

要確定有給予執行全縣,不然在 GitLab CI Runner 上會跑不起來。 (script/ 目錄是 Rails 放置一些 Shell Script 或者直接執行的程式用的目錄)

 1#!/usr/bin/env bash
 2
 3# 使用 RVM 切換到對應版本
 4# -- 因為我 Deploy 到 Heroku 有在 Gemfile 裡面指定版本
 5rvm use .
 6
 7# 安裝 Gems
 8# -- 沒有 without development 是因為 capistrano 在這個 group 裡面
 9bundle install --without production
10
11# 進行測試
12bundle exec rake db:create RAILS_ENV=test
13bundle exec rake db:migrate RAILS_ENV=test
14bundle exec rake spec RAILS_ENV=test
15
16# 進行 Nightly 的 Deploy
17# -- 我只希望對 "develop" branch 實行,所以透過 GitLab CI 的環境變數判斷
18if [ "$CI_BUILD_REF_NAME" == "develop" ]; then
19bundle exec cap nightly rvm1:install:gems # 預先安裝 Gems
20bundle exec cap nightly deploy # 發佈(同時也會 restart puma 不過 env 不會改變,要注意)
21fi
22
23exit 0

只後只要 develop branch 有變動,就可以自動地將最新版本的程式發佈到 Nightly Server 上面了! (只是建議 Ruby 版本變更等情況,最好預先跑過 rvm1:install:gems 不然會吃到一次 Faild 的 Test 喔 XD)

目前 GitLab 還不支援 Success Script 所以只能先這樣土炮一下了 XD

註: Puma 預設是 Unix Socket 建議搭配 Nginx 使用,還有 Port Forward 轉出來給 Host 主機處理。