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/images'
*** [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 images, 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就没有问题。