当前位置: 首页 > 工具软件 > Capistrano > 使用案例 >

使用 Capistrano —— Rails应用快速部署工具

魏泰
2023-12-01


"我鼓励你成为一个拥有三种美德的程序员:懒散,急躁还有傲慢。" -- Larry Wall, Perl语言之父。

对于大部分的程序员来说,部署应用是可以偷懒的。部署到一个集群--或者甚至在一台机器上--工作会十分重复和累人。使用Capistrano,一个ruby部署工具,可以让我们部署到远程服务器的工作变得简单,只需运行已定义好的任务即可。

Ruby程序员的工具箱包含很多可以减轻它们工作的工具,可以说ruby程序员是最懒惰的。就算替你完成这些烦人的工作还不够,ruby程序员甚至图谋使用一种语言(ruby)来构建他们的工具。不是使用bash,make,PHP, Perl来集成开发,而是只用ruby。

Capistrano致力于在任何的机器上运行远程命令。如果你需要连接到6台服务器上,并发布更新包,或者当你发现某些地方不对,而需要做回滚操作,却没有快速的方法去实现,那么你就需要想想如何偷懒了。

Capistrano以recipes来对任务分组,并且默认recipe,对于需要运行迁移和重启Rails服务器的时候,是显得十分的有用,这个我们在稍后会探讨它的。但是,Capistrano的核心并非是针对Rails的。你可以针对你的recipe,构建任务,并调整Rails的recipe去适应任何的语言或者框架。

让我们探讨Capistrano是如何实现Rails的部署,还有如何构建我们的任务,如何使用一条命令实现把你的应用推送到20台服务器上。

Capistrano和Rails

就像Rails,Capistrano越来越多的被用于部署到各种版本的Linux,并且在Leopard中已被默认安装,你就不需要再独立安装它。如果你需要安装它,就如其他的Ruby gem包一样,使用如下命令:

sudo gem install -y capistrano
Capistrano有两个主要命令:cap,这个命令被用于查看和运行任务; capify,用于在Capistrano中建立Rails项目。假设你已经有一个项目,复制它,并在项目跟目录中运行capify命令:


cd path/to/project capify .
这个命令会创建两个文件:Capfile和config/deploy.rb。Capfile是Capistrano里面相当于Makefile,用于make和Rakefile到Rake。Capistrano期望有一个Capfile,同时里面并包含任务或者包含一个Ruby文件。

在这个例子中,Capfile只包含config/deploy.rb,之后你会发现这个是十分有趣的事情。deploy文件里面包含一些你在运行cap命令前,需要注意的设置,

set :application, "set your application name here"
set :repository,  "set your repository location here"
如果你不熟悉ruby语法,你会发现这看起来十分像配置文件。但是,因为在ruby中调用函数的时候,不需要使用括号,文件里面的每一行其实就是调用set()函数:


set(:application, "your-app-name")
使用你的应用的名字替代:application变量,不要包含空格--这会创建一个部署目录。 使用你的版本管理URL目录替代:repository(在这个例子中,我们使用SVN)

如果你的SVN需要用户名和密码,请按如下配置:

set :scm_username, "svn-username" 
set :scm_password, "svn-password"
接着,取消注释并配置部署目录。如果你的部署服务器上没有部署的目录,Capistrano会帮你创建它:


set :deploy_to, "/path/to/doc/root/www/#{application}"
这里,我们使用我们之前设置的目标部署目录的application变量。这写全部是ruby的标准语法,在所有的Capistrano脚本中适用,这样可以使我们的工作更有效,而不是混杂各种令人头晕的语法在里面。

最后,我们需要配置部署的服务器信息。你可以添加很多你需要部署的服务器,你只需遵循SSH可以理解的命名规则:

role :app, "app-server-1", "app-server-2", "app-server-3"
role :web, "192.168.1.123"
role :db,  "db-server-1", :primary => true
如果你只是想测试一下Capistrano,你可以把你的工作站配置到部署地址; 这样,你就无需考虑服务器之间的跳转:


role :app, "me@my-local-ip"
现在,我们可以告诉Capistrano为我们建立部署路径的配置:


cap deploy:setup
当你运行这个命令,Capistrano开始为你展示它所做的。这样一来,可以方便我们调试Capfile,并可以消除你的疑虑知道它在做什么动作。每当你连接到一台服务器,系统会需要你提供密码,然后Capistrano就会运行一连串的命令。

执行完deploy:setup命令后,部署路径就会创建了一些新增的目录,运行cap命令去推送新版本,执行回滚和其他动作:

myapp/
      releases/ shared/log shared/pids shared/system
接着,我们开始部署应用。Capistrano会自动检查源代码并发布,同时创建一个叫做current的symlink链接:


cap deploy:cold
执行完这个命令后,让我们来看看发布目录:


# current@ -> /www/captest/myapp/releases/20080614144520
这个一个"cold"发布,意思是表示只执行一次的任务。之后如果我们需要再发布应用,你只需使用部署任务:


cap deploy

当你执行完deploy:cold或者deploy命令后,查看一下部署目录,你会发现你的源代码会按照Capistrano的方式被发布出去。

部署任务替代了登录服务器,获取源代码,设置数据库和重启服务器。任务只需运行很短时间,我们能就现在可以享受懒惰的感觉了!

深入知识

我们只需运用deploy:setup , deploy:cold, deploy命令就可以发布应用。recipe里面其实包含了很多东西,让我们来看看所有可用的任务:

cap -Tv

和rake -T很相像,这个命令会列出所有的任务和任务相关的文档。如果你已经运行过几次deploy,我们就可以尝试一下rollback或者rollback_code任务。

每次你执行回滚的时候,Capistrano会把symlink指向前一次发布的目录。回滚操作可以重复执行,直到你找到了你想要的稳定版本:

cap deploy:rollback_code

属于你自己的任务

当你使用Capistrano应用到你的rails项目中,你就会发现他是如何让你变得更懒惰。使用Rails特有命令的任务同样可以包含任何的命令在里面。

当你运行Capistrano任务,例如deploy,你会很多SSH命令和回应会回显出来。如果你需要发布到几台服务器上,你看到来自多台服务器的回应,因为Capistrano可以在多台服务器上运行任务,只要你需要发布到多少台服务器都可以。

它的用处是非常广的——检查硬盘空间,从集群中复制实时数据和运行维护计划——那么我们应该如何构建我们自己的任务呢?

Capistrano的任务是通过如下的语法来定义的:

desc "Short description here..."
task :name_of_function, :roles => :servers do
        # tasks is in here...
end
Ruby的优雅语法让所有事情都变得十分简单,那么让我们来单独讨论它。第一行是一些解释说明,这些说明会在你运行命令时被输出(同样在你的项目的跟目录下):


cap -Tv
Ruby支持在调用函数的时候,不使用括号,所以第二行实际上是调用了Capistrano的任务函数.

第一个参数是新任务的名字(name_of_function)。第二个参数是指定执行任务的服务器集合;这个可以是:server,:app,:db或者其他服务器的集合。

任务第一部分由do开始,这个是一个匿名函数,它是表示任何在do和end之间的任务都会被执行。你可能在javascript函数中也遇到过匿名函数。

一个非常简单的任务'df -h'将会被执行,用于检查服务器的磁盘使用情况。这个任务不会修改服务器上的任何配置,所以你可以大胆的去运行它:

desc "Check disk space"
task :diskspace, :roles => :servers do
        run 'df -h'
end
run函数只会简单的在服务器上运行命令。你可以使用sudo来替代它,使用sudo在远程服务器上实行命令:
desc "Who hasn't been cleaning out their home directories?"
task :home_disk_usage, :roles => :servers do
        sudo 'du -sh /home/*'
end
如果你就如上一节提到的一样,capified你的项目,你甚至可以添加你自己自定义的任务到标准的Rails recipe上,并修改Rails recipe的行为。这样可以让你的Capistrano按照你的意思去工作,这样的好处就在于当你忘记了某些命令如何运行。

在capified之后的Rails项目中添加你自己的任务,只需按照上面提到的任务语法,把它们添加到 config/deploy.rb中。当你添加了以恶搞任务,运行runcap -Tv命令检查你的任务是否存在,并运行其他任务。

Tasks可以被其他Task调用就如函数一样,所以复杂的Tasks可以切分成多个简单的tasks并按照“DRY”原则设计你的Capistrano recipes。Tasks可以通过rails函数调用实现互相调用:

task :home_disk_usage, :roles => :servers do
        vhosts_disk_usage
        run "ls /home/"
end
你可能需要自定义的任务知道你的项目是在哪个路径上。这就用到了我们在开头提到的配置变量,并通过ruby语法来定义:


run "tar czf ~/snapshot.tgz #{release_path}"
如果你需要其他变量,你可以像之前的语法一样去set:


set :foo, "bar"

或者,你可以通过set函数提示用户输入变量,但是用法有一点点不同:

set(:deploy_version) do
        Capistrano::CLI.ui.ask "What version is this? "
end

变量使用方法是一样的,不管是用那个方式去set他们。

所有的这些都离不开ruby,所以你会发现Capistrano更像一个框架而并非是一个独立的应用或脚本。如果Ruby对于你来说是一件新鲜的事情, 请继续学习吧——你很会就能熟悉它。

最后,就像DRY原则一样,尽量保持代码整洁。所有的Rails recipes可以在deploy 命名空间中找到,当你运行runcap -Tv的时候你就会发现的。命名空间允许你把任务组合在一起,这可以通过namespace命令包含你的这些任务:

namespace :our_tasks do
  desc "The default task"
  task :default do
    restart
end
  
  desc "Empty logs"
  task :empty_logs do
        # ...
  end
end
当你运行runcap -Tv,你可以看到任务已经被组合在一起:


cap our_tasks            # The default task
cap our_tasks:empty_logs # Empty logs

定制Rails recipe

创建Capistrano任务很简单,但是我们之前使用的Rails recipe已经包含了90%我们需要的东西。在这个例子中,更好的方式是定制recipe而不是创建就一个。我们可以通过覆盖特定的任务,实现对某些行为的定制。

我在尝试使用Capistrano来运行makefile的时候发现这个特性。在这里我完成了大部分的代码管理,数据库版本控制和安装配置。我们可以在不需要提交或编辑文件的场合使用这个方法。所以通过capistrano来部署是相当诱人的。

当你读到这里并想:"这是酷毙了,但是我们还没打算迁移到Rails"。定制化会很适合你,因为你可以覆盖执行rails命令相关的任务。

第一,尝试在非Rails项目中使用cap,但是请确保有一个config/目录,这样capify可以放置它的deploy.rb文件。当capify运行完毕后,你可以开始尝试运行各种我们上面提到的cap deploy任务。

但是,当Rails服务器不存在或者Rakefile不存在时候,Capistrano就会发生错误。

这是因为其中一个任务deploy:restart,会尝试重启rails服务器。另外一个任务会尝试运行runrake db:migrate。你的项目很可能不支持这两个任务,所以你需要添加如下的代码到config/deploy.rb,覆盖他们:

desc "Do nothing"
deploy.task :restart, :roles => :app do
  # ...do what you like here... 
end

这个很直观,这段代码是在deploy 命名空间中覆盖了restart任务,和所有包含在任务里面的命令(所有包含在do和end之间的代码)都可以被编辑。你可能需要重启Apache服务器而不是rails服务器:

desc "Do nothing"
deploy.task :restart, :roles => :app do
        sudo '/etc/init.d/restart'
end
当你运行cap命令 deploy:cold,rails迁移命令会创建对应的数据库。我们可以按照我们实际需要覆盖它:
deploy.task :migrate, :roles => :app do
        run "make data"
end

结论

Capistrano提供给我们相当简洁的方法去发布应用。它还能在其他关于远程服务器的领域中使用,例如监视,随意的任务,创建一次性备份和其他。

这些要归功于Ruby的优雅简洁,Capistrano可以推广到很多地方。Rails recipe可以被其他non-rails应用所提到,还可以使用小小的ruby知识就能添加一个新的recipes

最后,要让所有事情变得更迅速,使用SSH认证登录远程服务器。如果你需要把认证文件放在其他地方,你只需添加如下代码到deploy.rb文件:

ssh_options[:keys] = "/path/to/identity_file"
通过这个方式,你可以通过cap命令完全发布你的应用——现在你就是真正的懒人了。

Dan Frost是3ev的技术总监,一个在英国布莱顿的web应用开发公司。在PHP,java和其他领域,担当开发者角色和架构师角色的生涯中,他编写了关于云计算,Rails和Web 2.0的技术文章。

 类似资料: