Hi,本周第一天没什么事,所以就先分享一下我研究自动化代码部署与回滚软件的经验。这个软件有什么用途?主要是解决自动进行代码的部署,避免手动部署时出现错误,节省时间,同时在出现问题的时候,能回滚到之前的版本(或者你指定的版本),我在gitlab里找到了这样的软件,名为capistrano。下面就先给大家介绍一下。

文章结构

一、介绍

二、要求的环境

三、安装

四、命令行测试

五、代码部署(结合git)

六、代码部署(结合svn)

七、代码回滚

八、总结

九、namespace

一、介绍

Capistrano是一种在多台服务器上运行脚本的开源工具,它主要用于部署web应用。它自动完成多台服务器上新版本的同步更新,包括数据库的改变。Capistrano最初由Jamis Buck用Ruby开发,并用RubyGems部署渠道部署。现在Capistrano不仅限于应用Ruby on Rails的 web应用框架,而且可以用于部署用其他框架的web应用程序,比如用PHP开发的。Capistran最初是用来应用于bash指令行。现在Ruby on Rails框架的用于也可以使用它的新特性,例如,对当前web应用部署改变使其更新版本,或者使其回滚到之前的旧版本。

二、要求的环境

1、Ruby一定要1.9.x;

2、server端与client端一定要进行ssh信任或者client端统一一个相同的密码;

三、安装

gem install capistrano

四、命令行测试

root@ubuntu:/tmp# cat capfile
task :du, :hosts => "ubuntu.hadoop.com" do
run "df -h"
end

在ubuntu.hadoop.com(本机)机器上运行df –h命令查看磁盘空间

root@ubuntu:/tmp# cap du
* 2013-06-25 13:34:48 executing `du'
* executing "df -h"
servers: ["ubuntu.hadoop.com"]
[ubuntu.hadoop.com] executing command
** [out :: ubuntu.hadoop.com] Filesystem               Size  Used Avail Use% Mounted on
** [out :: ubuntu.hadoop.com] /dev/mapper/ubuntu-root   39G  3.3G   33G  10% /
** [out :: ubuntu.hadoop.com] udev                     489M  4.0K  489M   1% /dev
** [out :: ubuntu.hadoop.com] tmpfs                    199M  336K  199M   1% /run
** [out :: ubuntu.hadoop.com] none                     5.0M     0  5.0M   0% /run/lock
** [out :: ubuntu.hadoop.com] none                     498M     0  498M   0% /run/shm
** [out :: ubuntu.hadoop.com] /dev/sda1                228M   51M  166M  24% /boot
command finished in 981ms

可以看到类似使用python的fabric,但capistrano比fabric多了一个代码回滚功能。

需要注意的是如果你的client机器的ssh端口不是默认22的话,你还想操作的话,需要添加

ssh_options[:port] = 50020#ssh port

如果不添加的话,就会出现connection failed for: ip (Errno::ECONNREFUSED: Connection refused - connect(2))

如果你在使用iptables的机器上使用capistrano,只需要开启ssh端口就可以正常的使用capistrano。

五、代码部署(结合git)

测试环境

主机名                 ip          状态      ruby
ubuntu.hadoop.com   192.168.56.102  server      1.9.3
server.hadoo.com        192.168.56.101  client      1.9.3

1、进入tmp目录,然后创建capi目录

cd /tmp
mkdir capi
cd capi

2、capistrano部署我的应用

capify .

这将产生两个文件,一个是capfile,这个是Capistrano需要的主要文件,就像make自动产生makefile,rake自动产生Rakefile一样,Capistrano默认寻找并加载capfile文件,默认产生的rapfile非常小,它所做的事就是加载“config/deploy.rb";第二个文件是"config/deploy.rb",这个文件包含你的应用程序部署所需的设置。Ralis的所有设置文档都放在config目录下,通常,你不需要管capfile文件,只需要把精力放在config/deploy.rb的设置和优化上。如果你的Capistrano用于非Rails环境,你可能只有一个capfile文件,而没有config/deploy.rb这个文件。

3、修改config/deploy.rb文件

set :application, "test"
set :scm, :git
set :repository,  "ssh://git@192.168.1.250/data/gitrepo/jsonLib.git"
set :deploy_to, "/tmp/result"
set :normalize_asset_timestamps, false
# set :scm, :git # You can set :scm explicitly or Capistrano will make an intelligent guess based on known version control directory names
# Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`
role :web, "192.168.56.101"                          # Your HTTP server, Apache/etc
role :app, "192.168.56.101"                          # This may be the same as your `Web` server
role :db,  "192.168.56.101", :primary => true # This is where Rails migrations will run
#role :db,  "your slave db-server here"

我的修改内容如上

主要是从192.168.1.250里获取git库,然后应用部署到192.168.56.102机器的/tmp/result目录。

set :application, "test"

是告诉Capistrano我们的应用程序被"调用"了

set :scm, :git

默认启动svn,而不是git,如果使用的话,需要set :scm, :git开启。

set :repository,  "ssh://git@192.168.1.250/data/gitrepo/jsonLib.git"

然后我们需要告诉Capistrano我们的源代码在哪里,这个地址你的本地主机和服务器都可以到达。

set :deploy_to, "/tmp/result"

我们需要告诉Capistran我们的应用放在服务器的哪里,如果不加的话,默认为"/u/apps/#{application}"。

set :normalize_asset_timestamps, false

如果不添加这句话,在deploy:update的时候会出现

*** [err :: 192.168.56.101] find: `/tmp/result_svn/releases/20130625071724/public/p_w_picpaths'
*** [err :: 192.168.56.101] : No such file or directory
*** [err :: 192.168.56.101] find: `/tmp/result_svn/releases/20130625071724/public/stylesheets': No such file or directory
*** [err :: 192.168.56.101] find: `/tmp/result_svn/releases/20130625071724/public/javascripts': No such file or directory

原因是

Capistrano default behavior is to 'touch' all assets files. (To make sure that any cache get the deployment date). Assets are p_w_picpaths, stylesheets, etc.
If your PHP application is not using these directories, capistrano complains in such an ugly way.
To disable asset timestamps updates, simply add:

app,web,db是Capistrano需要的三种角色:

web:你的服务器软件运行的地方;

app:你的应用层运行的地方;

db:迁移运行的地方;

4、部署目录结构

cap deploy:setup

会在192.168.56.101创建/tmp/result目录,然后在这个目录里创建releases与shared目录

root@ubuntu:/tmp/capi# cap deploy:setup
* 2013-06-25 15:26:47 executing `deploy:setup'
* executing "sudo -p 'sudo password: ' mkdir -p /tmp/result /tmp/result/releases /tmp/result/shared /tmp/result/shared/system /tmp/result/shared/log /tmp/result/shared/pids"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 781ms
* executing "sudo -p 'sudo password: ' chmod g+w /tmp/result /tmp/result/releases /tmp/result/shared /tmp/result/shared/system /tmp/result/shared/log /tmp/result/shared/pids"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 40ms

5、检查

root@ubuntu:/tmp/capi# cap deploy:check
* 2013-06-25 15:29:04 executing `deploy:check'
* executing "test -d /tmp/result/releases"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 819ms
* executing "test -w /tmp/result"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 25ms
* executing "test -w /tmp/result/releases"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 26ms
* executing "which git"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 26ms
You appear to have all necessary dependencies installed

没有问题继续下一步更新

还得注意,如果你使用ssh模式的git,你需要把客户端与服务端的ssh key都传到服务器里,否则更新失败。

6、更新

root@ubuntu:/tmp/capi# cap deploy:update
* 2013-06-25 15:29:22 executing `deploy:update'
** transaction: start
* 2013-06-25 15:29:22 executing `deploy:update_code'
executing locally: "git ls-remote ssh://git@192.168.1.250/data/gitrepo/jsonLib.git HEAD"
command finished in 219ms
* executing "git clone -q ssh://git@192.168.1.250/data/gitrepo/jsonLib.git /tmp/result/releases/20130625072923 && cd /tmp/result/releases/20130625072923 && git checkout -q -b deploy ed8339e65d263fb9076b8f6168073765540bc4c4 && (echo ed8339e65d263fb9076b8f6168073765540bc4c4 > /tmp/result/releases/20130625072923/REVISION)"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 1151ms
* 2013-06-25 15:29:24 executing `deploy:finalize_update'
* executing "chmod -R -- g+w /tmp/result/releases/20130625072923 && rm -rf -- /tmp/result/releases/20130625072923/public/system && mkdir -p -- /tmp/result/releases/20130625072923/public/ && ln -s -- /tmp/result/shared/system /tmp/result/releases/20130625072923/public/system && rm -rf -- /tmp/result/releases/20130625072923/log && ln -s -- /tmp/result/shared/log /tmp/result/releases/20130625072923/log && rm -rf -- /tmp/result/releases/20130625072923/tmp/pids && mkdir -p -- /tmp/result/releases/20130625072923/tmp/ && ln -s -- /tmp/result/shared/pids /tmp/result/releases/20130625072923/tmp/pids"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 41ms
* 2013-06-25 15:29:24 executing `deploy:create_symlink'
* executing "sudo -p 'sudo password: ' rm -f /tmp/result/current && sudo -p 'sudo password: ' ln -s /tmp/result/releases/20130625072923 /tmp/result/current"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 60ms
** transaction: commit

没有错误,去192.167.56.101查看文件,确认都正常的复制过去了。

需要注意,服务端与客户端的ssh key都需要添加到git server里。

同时如果你的git有分支的话,你可以设置更新分支,设置需要在配置文件里设置,内容为

set :branch, "master"

这样就会更新master分支

root@server:/tmp/result# ll
total 16
drwxrwxr-x  4 root root 4096 Jun 25 15:29 ./
drwxrwxrwt 32 root root 4096 Jun 25 15:30 ../
lrwxrwxrwx  1 root root   35 Jun 25 15:29 current -> /tmp/result/releases/20130625072923/
drwxrwxr-x  3 root root 4096 Jun 25 15:29 releases/
drwxrwxr-x  5 root root 4096 Jun 25 15:26 shared/
root@server:/tmp/result# cd current
root@server:/tmp/result/current# ll
total 100
drwxrwxr-x 6 root root  4096 Jun 25 15:29 ./
drwxrwxr-x 3 root root  4096 Jun 25 15:29 ../
-rwxrwxr-x 1 root root   172 Jun 25 15:29 build_sh*
-rwxrwxr-x 1 root root   749 Jun 25 15:29 ckHashMap.h*
-rw-rw-r-- 1 root root  1740 Jun 25 15:29 CStrUtils.cpp
-rw-rw-r-- 1 root root   586 Jun 25 15:29 CStrUtils.h
drwxrwxr-x 8 root root  4096 Jun 25 15:29 .git/
lrwxrwxrwx 1 root root    22 Jun 25 15:29 log -> /tmp/result/shared/log/
drwxr-xr-x 2 root root  4096 Jun 25 15:29 public/
-rw-rw-r-- 1 root root    41 Jun 25 15:29 REVISION
drwxr-xr-x 2 root root  4096 Jun 25 15:29 tmp/

六、代码部署(结合svn)

测试环境

主机名                 ip          状态      ruby
ubuntu.hadoop.com   192.168.56.102  server      1.9.3
server.hadoo.com        192.168.56.101  client      1.9.3

1、进入tmp目录,然后创建capi_svn

cd /tmp
mkdir capi_svn
cd capi_svn

2、capistrano部署我的应用

capify .
root@ubuntu:/tmp/capi_svn# capify .
[add] writing './Capfile'
[add] making directory './config'
[add] writing './config/deploy.rb'
[done] capified!

3、修改config/deploy.rb文件

set :application, "test_svn"
set :scm, :subversion
set :repository,  "https://192.168.1.56/svn/sgol/trunk/0-sgol_server"
set :scm_username, "denglei"
set :scm_password, "123456"
set :deploy_to, "/tmp/result_svn"
set :normalize_asset_timestamps, false
# set :scm, :git # You can set :scm explicitly or Capistrano will make an intelligent guess based on known version control directory names
role :web, "192.168.56.101"                          # Your HTTP server, Apache/etc
role :app, "192.168.56.101"                          # This may ber
role :db,  "192.168.56.101", :primary => true # This is where Rails migrations will run
#role :db,  "your slave db-server here"

4、部署目录结构

cap deploy:setup

会在192.168.56.101创建/tmp/result目录,然后在这个目录里创建releases与shared目录

root@ubuntu:/tmp/capi_svn# cap deploy:setup
* 2013-06-25 15:19:29 executing `deploy:setup'
* executing "sudo -p 'sudo password: ' mkdir -p /tmp/result_svn /tmp/result_svn/releases /tmp/result_svn/shared /tmp/result_svn/shared/system /tmp/result_svn/shared/log /tmp/result_svn/shared/pids"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 783ms
* executing "sudo -p 'sudo password: ' chmod g+w /tmp/result_svn /tmp/result_svn/releases /tmp/result_svn/shared /tmp/result_svn/shared/system /tmp/result_svn/shared/log /tmp/result_svn/shared/pids"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 36ms

5、环境检查

root@ubuntu:/tmp/capi_svn# cap deploy:check
* 2013-06-25 15:21:03 executing `deploy:check'
* executing "test -d /tmp/result_svn/releases"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 1050ms
* executing "test -w /tmp/result_svn"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 21ms
* executing "test -w /tmp/result_svn/releases"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 22ms
* executing "which svn"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 28ms
You appear to have all necessary dependencies installed

没有问题

还有一个需要注意的,在进行更新前,需要在client里对svn先co一下,否则会出现

Error validating server certificate for 'https://192.168.1.56:443':
- The certificate is not issued by a trusted authority. Use the
fingerprint to validate the certificate manually!
- The certificate hostname does not match.
Certificate information:
- Hostname: yx
- Valid: from Fri, 14 Jan 2011 12:31:10 GMT until Mon, 11 Jan 2021 12:31:10 GMT
- Issuer: yx
- Fingerprint: b2:b2:26:5d:5a:76:cd:d2:46:e4:a6:31:d9:dc:c7:2b:2a:3a:eb:46
(R)eject, accept (t)emporarily or accept (p)ermanently?

错误,选择p然后yes,之后你的用户名与密码即可。

6、更新

root@ubuntu:/tmp/capi_svn# cap deploy:update
* 2013-06-25 15:21:38 executing `deploy:update'
** transaction: start
* 2013-06-25 15:21:38 executing `deploy:update_code'
executing locally: "svn info https://192.168.1.56/svn/sgol/trunk/0-sgol_server --username denglei --password **** --no-auth-cache  -rHEAD"
command finished in 691ms
* executing "svn checkout -q --username denglei --password **** o-auth-cache  -r2446 https://192.168.1.56/svn/sgol/trunk/0-sgol_server /tmp/result_svn/releases/20130625072139 && (echo 2446 > /tmp/result_svn/releases/20130625072139/REVISION)"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 7259ms
* 2013-06-25 15:21:46 executing `deploy:finalize_update'
* executing "chmod -R -- g+w /tmp/result_svn/releases/20130625072139 && rm -rf -- /tmp/result_svn/releases/20130625072139/public/system && mkdir -p -- /tmp/result_svn/releases/20130625072139/public/ && ln -s -- /tmp/result_svn/shared/system /tmp/result_svn/releases/20130625072139/public/system && rm -rf -- /tmp/result_svn/releases/20130625072139/log && ln -s -- /tmp/result_svn/shared/log /tmp/result_svn/releases/20130625072139/log && rm -rf -- /tmp/result_svn/releases/20130625072139/tmp/pids && mkdir -p -- /tmp/result_svn/releases/20130625072139/tmp/ && ln -s -- /tmp/result_svn/shared/pids /tmp/result_svn/releases/20130625072139/tmp/pids"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 100ms
* 2013-06-25 15:21:46 executing `deploy:create_symlink'
* executing "sudo -p 'sudo password: ' rm -f /tmp/result_svn/current && sudo -p 'sudo password: ' ln -s /tmp/result_svn/releases/20130625072139 /tmp/result_svn/current"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
command finished in 89ms
** transaction: commit

没有问题,192.168.56.101查看,文件都正常复制过去没有问题

root@server:/tmp/result_svn# pwd
/tmp/result_svn
root@server:/tmp/result_svn# ll
total 16
drwxrwxr-x  4 root root 4096 Jun 25 15:21 ./
drwxrwxrwt 32 root root 4096 Jun 25 15:21 ../
lrwxrwxrwx  1 root root   39 Jun 25 15:21 current -> /tmp/result_svn/releases/20130625072139/
drwxrwxr-x  3 root root 4096 Jun 25 15:21 releases/
drwxrwxr-x  5 root root 4096 Jun 25 15:19 shared/
root@server:/tmp/result_svn# cd current
root@server:/tmp/result_svn/current# ll
total 80
drwxrwxr-x 19 root root 4096 Jun 25 15:21 ./
drwxrwxr-x  3 root root 4096 Jun 25 15:21 ../
drwxrwxr-x  3 root root 4096 Jun 25 15:21 config/
drwxrwxr-x  4 root root 4096 Jun 25 15:21 controller/
drwxrwxr-x  7 root root 4096 Jun 25 15:21 data/
drwxrwxr-x  4 root root 4096 Jun 25 15:21 docs/
drwxrwxr-x  3 root root 4096 Jun 25 15:21 lib/
lrwxrwxrwx  1 root root   26 Jun 25 15:21 log -> /tmp/result_svn/shared/log/
drwxrwxr-x 17 root root 4096 Jun 25 15:21 logs/
drwxrwxr-x  3 root root 4096 Jun 25 15:21 model/
drwxrwxr-x  5 root root 4096 Jun 25 15:21 plugins/
drwxr-xr-x  2 root root 4096 Jun 25 15:21 public/
-rw-rw-r--  1 root root    5 Jun 25 15:21 REVISION
drwxrwxr-x  3 root root 4096 Jun 25 15:21 server1001/
drwxrwxr-x  6 root root 4096 Jun 25 15:21 .svn/

在顺便说一下,如果你想要指定版本升级的话,可以使用cap -s revision=2449 deploy:update

revision后添加版本后即可

七、代码回滚

1、为了做测试,我新部署个应用,然后用本机测试

root@ubuntu:/tmp/check# ll
total 8
drwxrwxr-x  2 root root 4096 Jun 25 11:05 ./
drwxrwxrwt 16 root root 4096 Jun 25 14:09 ../
root@ubuntu:/tmp/check# capify .
[add] writing './Capfile'
[add] making directory './config'
[add] writing './config/deploy.rb'
[done] capified!
root@ubuntu:/tmp/check# cat config/deploy.rb
set :application, "test"
set :repository,  "/tmp/svn"
set :deploy_to, "/tmp/result"
set :normalize_asset_timestamps, false
# set :scm, :git # You can set :scm explicitly or Capistrano will make an intelligent guess based on known version control directory names
# Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`
role :web, "192.168.56.102"                          # Your HTTP server, Apache/etc
role :app, "192.168.56.102"                          # This may be the same as your `Web` server
role :db,  "192.168.56.102", :primary => true # This is where Rails migrations will run
#role :db,  "your slave db-server here"

2、然后在/tmp/svn(这个目录为上面config/deploy.rb里定义的)里创建个文件为1,内容也是1

root@ubuntu:/tmp/check# echo "1">/tmp/svn/1
root@ubuntu:/tmp/check# cat /tmp/svn/1
1

3、然后先部署目录结构

root@ubuntu:/tmp/check# cap deploy:setup
* 2013-06-25 15:33:17 executing `deploy:setup'
* executing "sudo -p 'sudo password: ' mkdir -p /tmp/result /tmp/result/releases /tmp/result/shared /tmp/result/shared/system /tmp/result/shared/log /tmp/result/shared/pids"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 997ms
* executing "sudo -p 'sudo password: ' chmod g+w /tmp/result /tmp/result/releases /tmp/result/shared /tmp/result/shared/system /tmp/result/shared/log /tmp/result/shared/pids"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 45ms

查看/tmp/result目录里内容

root@ubuntu:/tmp/check# ll /tmp/result/
total 16
drwxrwxr-x  4 root root 4096 Jun 25 15:33 ./
drwxrwxrwt 17 root root 4096 Jun 25 15:17 ../
drwxrwxr-x  2 root root 4096 Jun 25 15:33 releases/
drwxrwxr-x  5 root root 4096 Jun 25 15:33 shared/

4、然后进行更新

root@ubuntu:/tmp/check# cap deploy:update
* 2013-06-25 15:35:01 executing `deploy:update'
** transaction: start
* 2013-06-25 15:35:01 executing `deploy:update_code'
* executing "cp -R /tmp/svn /tmp/result/releases/20130625073501 && (echo  > /tmp/result/releases/20130625073501/REVISION)"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 945ms
* 2013-06-25 15:35:02 executing `deploy:finalize_update'
* executing "chmod -R -- g+w /tmp/result/releases/20130625073501 && rm -rf -- /tmp/result/releases/20130625073501/public/system && mkdir -p -- /tmp/result/releases/20130625073501/public/ && ln -s -- /tmp/result/shared/system /tmp/result/releases/20130625073501/public/system && rm -rf -- /tmp/result/releases/20130625073501/log && ln -s -- /tmp/result/shared/log /tmp/result/releases/20130625073501/log && rm -rf -- /tmp/result/releases/20130625073501/tmp/pids && mkdir -p -- /tmp/result/releases/20130625073501/tmp/ && ln -s -- /tmp/result/shared/pids /tmp/result/releases/20130625073501/tmp/pids"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 36ms
* 2013-06-25 15:35:02 executing `deploy:create_symlink'
* executing "sudo -p 'sudo password: ' rm -f /tmp/result/current && sudo -p 'sudo password: ' ln -s /tmp/result/releases/20130625073501 /tmp/result/current"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 49ms
** transaction: commit

然后在查看更新情况

root@ubuntu:/tmp/check# ll /tmp/result/
total 16
drwxrwxr-x  4 root root 4096 Jun 25 15:35 ./
drwxrwxrwt 17 root root 4096 Jun 25 15:17 ../
lrwxrwxrwx  1 root root   35 Jun 25 15:35 current -> /tmp/result/releases/20130625073501/
drwxrwxr-x  3 root root 4096 Jun 25 15:35 releases/
drwxrwxr-x  5 root root 4096 Jun 25 15:34 shared/

可以看到已经有了一个current指向正确的版本了,然后看看里面都有什么内容

root@ubuntu:/tmp/check# cat /tmp/result/current/1
1

可以看到已经有我之前追加到/tmp/svn/1里的内容了

5、再/tmp/svn/1里添加一个内容为2,需要覆盖修改

root@ubuntu:/tmp/result/current# echo "2">/tmp/svn/1
root@ubuntu:/tmp/result/current# cat /tmp/svn/1
2

6、然后在更新

root@ubuntu:/tmp/check# cap deploy:update
* 2013-06-25 15:36:28 executing `deploy:update'
** transaction: start
* 2013-06-25 15:36:28 executing `deploy:update_code'
* executing "cp -R /tmp/svn /tmp/result/releases/20130625073628 && (echo  > /tmp/result/releases/20130625073628/REVISION)"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 1251ms
* 2013-06-25 15:36:29 executing `deploy:finalize_update'
* executing "chmod -R -- g+w /tmp/result/releases/20130625073628 && rm -rf -- /tmp/result/releases/20130625073628/public/system && mkdir -p -- /tmp/result/releases/20130625073628/public/ && ln -s -- /tmp/result/shared/system /tmp/result/releases/20130625073628/public/system && rm -rf -- /tmp/result/releases/20130625073628/log && ln -s -- /tmp/result/shared/log /tmp/result/releases/20130625073628/log && rm -rf -- /tmp/result/releases/20130625073628/tmp/pids && mkdir -p -- /tmp/result/releases/20130625073628/tmp/ && ln -s -- /tmp/result/shared/pids /tmp/result/releases/20130625073628/tmp/pids"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 71ms
* 2013-06-25 15:36:30 executing `deploy:create_symlink'
* executing "sudo -p 'sudo password: ' rm -f /tmp/result/current && sudo -p 'sudo password: ' ln -s /tmp/result/releases/20130625073628 /tmp/result/current"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 53ms
** transaction: commit

在查看一下/tmp/result里的最新版本里1的内容

root@ubuntu:/tmp/check# cat /tmp/result/current/1
2

可以看到已经更新为2了

7、在继续对/tmp/svn/1里修改内容为3,覆盖修改(此步骤主要是想测试连续回滚的时候,恢复那个版本)

root@ubuntu:/tmp/check# echo "3">/tmp/svn/1
root@ubuntu:/tmp/check# cat /tmp/svn/1
3

在继续更新

root@ubuntu:/tmp/check# cap deploy:update
* 2013-06-25 15:37:11 executing `deploy:update'
** transaction: start
* 2013-06-25 15:37:11 executing `deploy:update_code'
* executing "cp -R /tmp/svn /tmp/result/releases/20130625073711 && (echo  > /tmp/result/releases/20130625073711/REVISION)"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 890ms
* 2013-06-25 15:37:12 executing `deploy:finalize_update'
* executing "chmod -R -- g+w /tmp/result/releases/20130625073711 && rm -rf -- /tmp/result/releases/20130625073711/public/system && mkdir -p -- /tmp/result/releases/20130625073711/public/ && ln -s -- /tmp/result/shared/system /tmp/result/releases/20130625073711/public/system && rm -rf -- /tmp/result/releases/20130625073711/log && ln -s -- /tmp/result/shared/log /tmp/result/releases/20130625073711/log && rm -rf -- /tmp/result/releases/20130625073711/tmp/pids && mkdir -p -- /tmp/result/releases/20130625073711/tmp/ && ln -s -- /tmp/result/shared/pids /tmp/result/releases/20130625073711/tmp/pids"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 42ms
* 2013-06-25 15:37:12 executing `deploy:create_symlink'
* executing "sudo -p 'sudo password: ' rm -f /tmp/result/current && sudo -p 'sudo password: ' ln -s /tmp/result/releases/20130625073711 /tmp/result/current"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 56ms
** transaction: commit

查看结果

root@ubuntu:/tmp/check# cat /tmp/result/current/1
3

也是正确的。

8、测试回滚

root@ubuntu:/tmp/check# cap deploy:rollback
* 2013-06-25 15:37:42 executing `deploy:rollback'
* 2013-06-25 15:37:42 executing `deploy:rollback:revision'
* executing "sudo -p 'sudo password: ' ls -x /tmp/result/releases"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 980ms
* executing "sudo -p 'sudo password: ' rm /tmp/result/current; sudo -p 'sudo password: ' ln -s /tmp/result/releases/20130625073628 /tmp/result/current"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 94ms
* 2013-06-25 15:37:43 executing `deploy:restart'
* 2013-06-25 15:37:43 executing `deploy:rollback:cleanup'
* executing "if [ `readlink /tmp/result/current` != /tmp/result/releases/20130625073711 ]; then sudo -p 'sudo password: ' rm -rf /tmp/result/releases/20130625073711; fi"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 65ms

查看结果

root@ubuntu:/tmp/check# cat /tmp/result/current/1
2

已经回滚到之前的版本

9、测试连续回滚

也就是说在回滚后继续回滚

root@ubuntu:/tmp/check# cap deploy:rollback
* 2013-06-25 15:38:09 executing `deploy:rollback'
* 2013-06-25 15:38:09 executing `deploy:rollback:revision'
* executing "sudo -p 'sudo password: ' ls -x /tmp/result/releases"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 987ms
* executing "sudo -p 'sudo password: ' rm /tmp/result/current; sudo -p 'sudo password: ' ln -s /tmp/result/releases/20130625073501 /tmp/result/current"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 49ms
* 2013-06-25 15:38:10 executing `deploy:restart'
* 2013-06-25 15:38:10 executing `deploy:rollback:cleanup'
* executing "if [ `readlink /tmp/result/current` != /tmp/result/releases/20130625073628 ]; then sudo -p 'sudo password: ' rm -rf /tmp/result/releases/20130625073628; fi"
servers: ["192.168.56.102"]
[192.168.56.102] executing command
command finished in 66ms
root@ubuntu:/tmp/check# cat /tmp/result/current/1
1

可以从结果了解到,使用回滚的时候,默认都是按照更新的时间来回滚(比如你第一个更新为1,第二次更新为2,第三次更新为3的时候,想回滚,你只能使用rollback回滚到第二次,值为2的,不知直接回滚到第一次,值为1的,如果还想回滚到1,就在回滚一次,也就是在第3次,值为3的时候,连续回滚2次)

在深入一下,默认的回滚是到之前的版本,如果你想回滚到指定的版本,可以使用

cap -s previous_release=/tmp/result_svn/releases/20130627023154 deploy:rollback

其中previous_release为你在client里release的路径加上你想回滚的版本

八、总结

从上面的介绍与实例,大家可以很方便的理解capistrano的用途,可以配置crontab或者puppet实现自动化的部署更新代码,简化运维人员的工作量、减少部署错误、增加自己的时间。

九、namespace

在简单的讲一下namespace,就是同一个任务不同的规则,具体如下

root@server:~/capistrano# cat Capfile
namespace :command do
task :hostname, :hosts => "127.0.0.1" do
run "hostname"
end
task :ip, :hosts => "127.0.0.1" do
run "ifconfig"
end
end
root@server:~/capistrano# cap -vT
cap command:hostname #
cap command:ip       #
cap invoke           # Invoke a single command on the remote servers.
cap shell            # Begin an interactive Capistrano session.
Extended help may be available for these tasks.
Type `cap -e taskname' to view it.

可以看到command任务有hostname与ip这2个不同的规则,下面分别运行一下看看

root@server:~/capistrano# cap command:ip
* 2013-07-30 10:07:05 executing `command:ip'
* executing "ifconfig"
servers: ["127.0.0.1"]
[127.0.0.1] executing command
** [out :: 127.0.0.1] eth0      Link encap:Ethernet  HWaddr 08:00:27:66:7a:7a
** [out :: 127.0.0.1] inet addr:192.168.56.101  Bcast:192.168.56.255  Mask:255.255.255.0
** [out :: 127.0.0.1] inet6 addr: fe80::a00:27ff:fe66:7a7a/64 Scope:Link
** [out :: 127.0.0.1] UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
** [out :: 127.0.0.1] RX packets:2821 errors:0 dropped:0 overruns:0 frame:0
** [out :: 127.0.0.1] TX packets:1161 errors:0 dropped:0 overruns:0 carrier:0
** [out :: 127.0.0.1] collisions:0 txqueuelen:1000
** [out :: 127.0.0.1] RX bytes:211437 (211.4 KB)  TX bytes:183757 (183.7 KB)
** [out :: 127.0.0.1]
** [out :: 127.0.0.1] eth1      Link encap:Ethernet  HWaddr 08:00:27:29:f6:9a
** [out :: 127.0.0.1] inet6 addr: fe80::a00:27ff:fe29:f69a/64 Scope:Link
** [out :: 127.0.0.1] UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
** [out :: 127.0.0.1] RX packets:28 errors:0 dropped:0 overruns:0 frame:0
** [out :: 127.0.0.1] TX packets:81 errors:0 dropped:0 overruns:0 carrier:0
** [out :: 127.0.0.1] collisions:0 txqueuelen:1000
** [out :: 127.0.0.1] RX bytes:9576 (9.5 KB)  TX bytes:26118 (26.1 KB)
** [out :: 127.0.0.1]
** [out :: 127.0.0.1] lo        Link encap:Local Loopback
** [out :: 127.0.0.1] inet addr:127.0.0.1  Mask:255.0.0.0
** [out :: 127.0.0.1] inet6 addr: ::1/128 Scope:Host
** [out :: 127.0.0.1] UP LOOPBACK RUNNING  MTU:16436  Metric:1
** [out :: 127.0.0.1] RX packets:504 errors:0 dropped:0 overruns:0 frame:0
** [out :: 127.0.0.1] TX packets:504 errors:0 dropped:0 overruns:0 carrier:0
** [out :: 127.0.0.1] collisions:0 txqueuelen:0
** [out :: 127.0.0.1] RX bytes:71762 (71.7 KB)  TX bytes:71762 (71.7 KB)
** [out :: 127.0.0.1]
command finished in 941ms
root@server:~/capistrano# cap command:hostname
* 2013-07-30 10:07:11 executing `command:hostname'
* executing "hostname"
servers: ["127.0.0.1"]
[127.0.0.1] executing command
** [out :: 127.0.0.1] server.hadoop.com
command finished in 978ms

从结果可以看出namespace,就是把不同的规则都统一的挂到一个任务下。

在namespace里运行命令可以使用run与system,但这2个区别,可以从下面的结果看到

root@ubuntu:/tmp/caphub/test/config/deploy# cat ec2.rb
namespace :world do
task :hostname, :hosts => "192.168.56.101" do
run "hostname"
run "ifconfig"
system("ifconfig")
end
end

运行

root@ubuntu:/tmp/caphub/test/config/deploy# cap ec2 world:hostname
triggering load callbacks
* 2013-07-30 11:59:23 11:59:23 == Currently executing `uptodate'
* 2013-07-30 11:59:23 11:59:23 == Currently executing `uptodate:git'
* 2013-07-30 11:59:23 11:59:23 == Currently executing `ec2'
triggering start callbacks for `world:hostname'
* 2013-07-30 11:59:23 11:59:23 == Currently executing `multiconfig:ensure'
* 2013-07-30 11:59:23 11:59:23 == Currently executing `world:hostname'
* executing "hostname"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
** [out :: 192.168.56.101] server.hadoop.com
command finished in 975ms
* executing "ifconfig"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
** [out :: 192.168.56.101] eth0      Link encap:Ethernet  HWaddr 08:00:27:66:7a:7a
** [out :: 192.168.56.101] inet addr:192.168.56.101  Bcast:192.168.56.255  Mask:255.255.255.0
** [out :: 192.168.56.101] inet6 addr: fe80::a00:27ff:fe66:7a7a/64 Scope:Link
** [out :: 192.168.56.101] UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
** [out :: 192.168.56.101] RX packets:9888 errors:0 dropped:0 overruns:0 frame:0
** [out :: 192.168.56.101] TX packets:8763 errors:0 dropped:0 overruns:0 carrier:0
** [out :: 192.168.56.101] collisions:0 txqueuelen:1000
** [out :: 192.168.56.101] RX bytes:830795 (830.7 KB)  TX bytes:1496795 (1.4 MB)
** [out :: 192.168.56.101]
** [out :: 192.168.56.101] eth1      Link encap:Ethernet  HWaddr 08:00:27:29:f6:9a
** [out :: 192.168.56.101] inet addr:192.168.8.229  Bcast:192.168.8.255  Mask:255.255.255.0
** [out :: 192.168.56.101] inet6 addr: fe80::a00:27ff:fe29:f69a/64 Scope:Link
** [out :: 192.168.56.101] UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
** [out :: 192.168.56.101] RX packets:94100 errors:0 dropped:0 overruns:0 frame:0
** [out :: 192.168.56.101] TX packets:18954 errors:0 dropped:0 overruns:0 carrier:0
** [out :: 192.168.56.101] collisions:0 txqueuelen:1000
** [out :: 192.168.56.101] RX bytes:71655678 (71.6 MB)  TX bytes:1413729 (1.4 MB)
** [out :: 192.168.56.101]
** [out :: 192.168.56.101] lo        Link encap:Local Loopback
** [out :: 192.168.56.101] inet addr:127.0.0.1  Mask:255.0.0.0
** [out :: 192.168.56.101] inet6 addr: ::1/128 Scope:Host
** [out :: 192.168.56.101] UP LOOPBACK RUNNING  MTU:16436  Metric:1
** [out :: 192.168.56.101] RX packets:1355 errors:0 dropped:0 overruns:0 frame:0
** [out :: 192.168.56.101] TX packets:1355 errors:0 dropped:0 overruns:0 carrier:0
** [out :: 192.168.56.101] collisions:0 txqueuelen:0
** [out :: 192.168.56.101] RX bytes:183369 (183.3 KB)  TX bytes:183369 (183.3 KB)
command finished in 63ms
eth0      Link encap:Ethernet  HWaddr 08:00:27:dc:ff:20
inet addr:192.168.8.104  Bcast:192.168.8.255  Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fedc:ff20/64 Scope:Link
UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
RX packets:33300 errors:0 dropped:0 overruns:0 frame:0
TX packets:535 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3383618 (3.3 MB)  TX bytes:106195 (106.1 KB)
eth1      Link encap:Ethernet  HWaddr 08:00:27:af:1e:13
inet addr:192.168.56.102  Bcast:192.168.56.255  Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:feaf:1e13/64 Scope:Link
UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
RX packets:10153 errors:0 dropped:0 overruns:0 frame:0
TX packets:8767 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:935274 (935.2 KB)  TX bytes:1437233 (1.4 MB)
lo        Link encap:Local Loopback
inet addr:127.0.0.1  Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING  MTU:16436  Metric:1
RX packets:440 errors:0 dropped:0 overruns:0 frame:0
TX packets:440 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:78000 (78.0 KB)  TX bytes:78000 (78.0 KB)

从上面可以看到使用system更符合我们的要求。

而且run不能调用 cap命令,比如使用run调用cap git deploy:check来进行git的检测

* executing "cap git deploy:check"
servers: ["192.168.56.101"]
[192.168.56.101] executing command
*** [err :: 192.168.56.101] sh: 1: cap: not found
command finished in 29ms
failed: "sh -c 'cap git deploy:check'" on 192.168.56.101

如果使用就会出现上面的结果,但使用system就没有问题。