聚會時間公告: 因應COSCUP 2011, Kalug 8月份休會一次

三月 18, 2015

小惡魔AppleBOY
AppleBOY
is about »

tag cloud

» Ruby Deploy With Capistrano 碰到 SSH Connection Closed

CapistranoLogo

Ruby 開發環境最常用的 Deploy 工具就是 Capistrano,讓開發者可以快速部署程式碼,在部署進行中,由於大量的 js 及 css 需要處理,所以花最長的時間就是 assets:precompile,執行 cap deploy 就會發現卡在底下錯誤訊息

** [whenever:update_crontab] exception while rolling back: Net::SSH::Disconnect, connection closed by remote host *** [deploy:update_code] rolling back * executing “rm -rf /home/deploy/nami/releases/20150317135422; true” servers: [“xxxxx.tw”] ** [deploy:update_code] exception while rolling back: Net::SSH::Disconnect, connection closed by remote host

遇到這問題顧名思義就是 ssh timeout,造成原因就是由於 assets:precompile 執行時間過長,所以 Client 端的 ssh 就斷線,要解決這其實不難,請在 Server 端的 sshd 設定檔加入底下參數

ClientAliveInterval 120
ClientAliveCountMax 3

我們來看看 ClientAliveInterval 跟 ClientAliveCountMax 分別代表什麼意思,ClientAliveInterval 以上面例子來說,就是如果 120 秒內沒有收到 Client 端任何訊息,則 Server 會透過加密通道發送 Requerst 並且等待 Client 回應,而 ClientAliveCountMax 的用途就是,如果 120 秒沒收到回應,則繼續發送 Request 的次數,所以看到上面設定,就可以知道 120 * 3 秒後都沒有收到 Client 回應,則 SSH Server 就會強迫斷線,也就是會看到 Net::SSH::Disconnect。SSH 的設定檔位置為 /etc/ssh/sshd_config,完成後請記得重新啟動 sshd。

伺服器設定完成後,我們來看看 Client 端也要設定,請打開 /etc/ssh/ssh_config 輸入底下參數

ServerAliveInterval 120

讓 Client 端,每 120 秒可以送 response 給 Server 端,這樣就可以保持 ssh 連線。

參考:SSH Connection Closed While Deploying With Capistrano

三月 19, 2014

小惡魔AppleBOY
AppleBOY
is about »

tag cloud

» Using Capistrano to deploy current branch

CapistranoLogo

Capistrano 是一套用 Ruby 語言所寫的 Deploy Tool,可以用來管理多台伺服器自動化流程,在 Rails 專案內都會使用這套 Deploy Tool,也方便管理遠端機器。這次有個問題是,假設我們在 Staging 或 Production 設定檔分別定義了 :branch 變數如下

set :branch, "master"
set :env, "production"

這時候可以透過底下指令來 Deploy 到遠端伺服器

$ bundle exec cap production deploy

假設這次想要 deploy 不同 branch 到 Production Server,就必須修改 production.rb 設定檔,每次不同 branch 就要改一次,會比較麻煩,要解決此問題只需要將上述程式碼改成可以用 command line 方式管理

set :branch, fetch(:branch, "master")
set :env, fetch(:env, "production")

將指令換成

$ bundle exec cap -S branch="my-branch" production deploy

也就可以達成目的了。多人同時在開發專案時,一定會有很多 feature 或 issue branch,開發者會希望目前在哪個 Branch,程式碼 commit 後,就直接用 cap deploy,將現在的 Branch 程式碼 Deploy 到伺服器,方便其他人測試,要達成此功能,請修改 deploy.rb 加入底下程式碼

# Figure out the name of the current local branch
def current_git_branch
  branch = `git symbolic-ref HEAD 2> /dev/null`.strip.gsub(/^refs\/heads\//, '')
  branch
end

# Set the deploy branch to the current branch
set :branch, fetch(:branch, current_git_branch)

完成後,請將 config/deploy/*.rb 內的 set :branch 全部拿掉,這樣切到任何 Branch,就直接下 cap deploy 即可,,當然也可以透過 command line 方式指定 Branch 來 Deploy。最後附上 Capistrano 的目錄架構圖

├── Capfile
├── config
│   ├── deploy
│   │   ├── production.rb
│   │   └── staging.rb
│   └── deploy.rb
└── lib
    └── capistrano
            └── tasks

參考文章:

四月 25, 2013

小惡魔AppleBOY
AppleBOY
is about »

tag cloud

» Fabric 管理多台 Linux 機器的 command tool

python-logo-master-v3-TMpython-logo-master-v3-TM

相信 Administrator 管理過兩台以上的 Linux Server 都一定會找 tool 讓多台機器同時執行指令,這也應用在 Deploy 任何 application 到多台機器或者是同時更新系統套件…等,網路上有蠻多套 command line tool 像是 capistranoFabricpsshdsh…等都,本篇會以 Python 所推的 Fabric 來做介紹。另外 Ruby 所寫的 capistrano tool 也是不錯的選擇,這兩套其實大同小異,可以將 Deploy 的邏輯寫成單一 file 再透過 task 定義來決定執行的工作。當然你也可以透過此 tool 來管理 local 端動作,但是這有點多此一舉,因為基本的 Shell 就可以完成了,如果熟悉 Python 則選 fabric,如果喜歡寫 Ruby 則可以試試看 capistrano。

安裝方式(Installation)

如果是 CentOS 系列可以透過 yum 套件管理,UbuntuDebian 則是透過 aptitude 方式安裝。

Yum

# install python pip tool and fabric command
yum -y install python-pip
pip-python install fabric

APT

# install python easy_install
aptitude -y install python-pip
# install fabric command
pip install fabric

安裝 capistrano 可以透過 Ruby gem。

$ gem install capistrano

基本介紹

Fabric 可以透過 command line 或者是讀取 fabfile.py 檔案方式來執行,fabfile.py 務必放在執行 fab command 的目錄底下,也就是的命令列所在位置 。假設目前在 /home/appleboy 目錄下,就必須將 fabfile.py 存放在 /home/appleboy。

簡易設定 /home/appleboy/fabfile.py,內容

def hello():
    print("Hello world!")

該目錄底下執行

$ fab hello
Hello world!

Done.

如果不透過 fabfile.py 檔案的話,你直接打 fab 會得到 Couldn’t find any fabfiles!,看到這訊息沒關係,一樣可以用指令方式來達成上面的結果。學習 fabric 前,有一個很必要的條件,就是必需熟悉 Linux command 及 Shell script 用法,個人推薦鳥哥的網站,把基礎文件都看過後,就沒有任何 Linux 系統可以難倒你。如何用 fab command 直接得到上述的結果呢?

$ fab -p xxxx -H localhost -- 'echo "Hello world!";'

上述指令會產生下面結果

[localhost] Executing task '<remainder>'
[localhost] run: echo "Hello world!";
[localhost] out: Hello world!
[localhost] out:
Done.
Disconnecting from localhost... done.

執行 fab 就像是透過 ssh 登入機器,需要帳號及密碼,執行當下就必須提供使用者帳號及密碼,如果沒給參數,預設就是執行該 command 的使用者,-p 則是給密碼,這樣就不會詢問密碼了,-H 是指定要對哪個 host 執行該命令,也許同時 3 台機器,-H 請改寫成 -H web1,web2,web3。要換其他使用者直接加上 -u 參數

$ fab -u deploy -p xxxx -H localhost -- 'echo "Hello world!";'

接下來聊聊該如何寫 fabfile.py,fab 有分 local 端或 Host 端執行,如果只用在 local 端就跟寫 Shell script 沒啥不同,fabric 提供了 local function 執行 local command。對於專案而言,你可以建立 fabfile.py 設定檔,裡面寫入

from fabric.api import local

def prepare_deploy():
    local("git add -p && git commit")
    local("git push")

執行 fab prepare_deploy 會將專案已修改的 commit 到 server,當然你也可以拆開來執行

from fabric.api import local

def clone():
    local("git clone git@github.com:appleboy/minify-tool.git")

def commit():
    local("git add -p && git commit")

def push():
    local("git push")

def prepare_deploy():
    commit()
    push()

大家可以依照專案需求來定義工作項目,好讓團隊所有的成員都可以使用。

錯誤處理

看到上面例子,可以知道透過 fab clone 來初始化專案,執行後,發現多了 minify-tool 目錄,但是再執行同樣指令一次呢?會發現出現底下錯誤訊息

[localhost] local: git clone git@github.com:appleboy/minify-tool.git
fatal: destination path 'minify-tool' already exists and is not an empty directory.

Fatal error: local() encountered an error (return code 128) while executing 'git clone git@github.com:appleboy/minify-tool.git'

Aborting.

程式就停止了,但是如果底下有必須執行的工作,該怎麼辦,必須要 import with_statement 模組,將程式碼改成底下

from __future__ import with_statement
from fabric.api import local, settings, abort
from fabric.contrib.console import confirm

def clone():
    with settings(warn_only=True):
        result = local("git clone git@github.com:appleboy/minify-tool.git")
    if result.failed and not confirm("Tests failed. Continue anyway?"):
        abort("Aborting at user request.")

會發現畫面還是會出現錯誤訊息,最後跳出 confirm 視窗鍵入 Y,結果會得到 Done!,鍵入 N 則得到 Aborting 訊息。

[localhost] local: git clone git@github.com:appleboy/minify-tool.git
fatal: destination path 'minify-tool' already exists and is not an empty directory.

Warning: local() encountered an error (return code 128) while executing 'git clone git@github.com:appleboy/minify-tool.git'

Tests failed. Continue anyway? [Y/n] y

Done.

接著來定義 deploy 工作內容

def deploy():
    code_dir = 'minify-tool'
    with cd(code_dir):
        run("git pull")

上面多了二個函式,就是 cd 和 run,cd 很直覺,就跟 Linux command 一樣,run 跟 local 不同的地方就是 run 是用來管理遠端機器。

定義 Host

最前面有提到可以用 -H 方式定義,那也可以直些寫在 fabfile.py 設定檔

env.hosts = ['127.0.0.1']
env.hosts = ['localhost']
env.hosts = ['web1']

上面寫法都正確,host name 可以直接在 /etc/hosts 檔案內定義,將程式碼改為底下

env.hosts = ['my_server']

def deploy():
    code_dir = 'minify-tool'
    with settings(warn_only=True):
        if run("test -d %s" % code_dir).failed:
            run("git clone git@github.com:appleboy/minify-tool.git %s" % code_dir)
    with cd(code_dir):
        run("git pull")

如果沒有定義 env.hosts,你也可以執行

$ fab -H web1 deploy

這次先介紹到這裡,或許之後有機會來介紹進階用法,當然可以先參考看看 fabric document

support:

biggo.com.tw

biggo.sg

A Django site.