以前在公司部署都是用webistrano,图形化界面,部署代码也是sonic写,自己都不带操心的。部署得练练,不然被人一问三不知,可是很羞愧的。
首先做了一个简单的rails3 app:cookbook代码上传至github
在Gemfile中添加 gem ‘capistrano’
读capistarno的wiki getting start
安装完后要准备一些事情:
- 必须使用ssh访问你的服务器
- 远程服务器必须安装了POSIX-compatible shell,“sh”命令必须在默认的系统环境中
- 将你电脑中的public key放在服务器上,保证你不用输入密码来登陆服务器
前两样基本都能满足,第三个 需要你 在终端执行命令
ssh-keygen -t rsa
系统会提示输入passphrase 此处不填,两次回车会在 ~/.ssh 下创建两个文件 id_rsa 和id_rsa.pub。文件用途如下
~/.ssh/id_rsa
- 该用户默认的 RSA 身份认证私钥(SSH-2)。此文件的权限应当至少限制为”600″。
- 生成密钥的时候可以指定采用密语来加密该私钥(3DES)。
- ssh(1) 将在登录的时候读取这个文件。
~/.ssh/id_rsa.pub
- 该用户默认的 RSA 身份认证公钥(SSH-2)。此文件无需保密。
- 此文件的内容应该添加到所有 RSA 目标主机的 ~/.ssh/authorized_keys 文件中。
密钥和公钥创建后把公钥传到要部署的服务器上
scp ~/.ssh/id_rsa.pub yakjuly@yakjuly.com:~/.ssh/authrozied_keys
以后你从本地电脑ssh登陆服务器 就不用输入密码了,系统会根据密钥和公钥对你的身份进行认证。
同理 你把公钥 写到github帐户信息的public sshkeys中 根据 git@github.com:/xxxx/xx.git 下载时 也不用输入密码了。
因为我用github管理代码 因此 服务器上也需要生成一套密钥,以便于下载代码不需要输入密码, 把公钥填到github帐户中,这里有教程。
准备好后 先按照capistrano wiki上的小例子,练下手。
在项目root下创建一个capfile文件,
task :search_libs, :hosts => "yakjuly@www.yakjuly.com" do
run "ls -x1 /usr/lib | grep -i xml"
end
运行
cap search_libs
显示结果
* executing `search_libs'
* executing "ls -x1 /usr/lib | grep -i xml"
servers: ["www.yakjuly.com"]
[yakjuly@www.yakjuly.com] executing command
** [out :: yakjuly@www.yakjuly.com] libwx_baseu_xml-2.6.so.0
** [out :: yakjuly@www.yakjuly.com] libwx_baseu_xml-2.6.so.0.3.1
** [out :: yakjuly@www.yakjuly.com] libxml2.a
** [out :: yakjuly@www.yakjuly.com] libxml2.la
** [out :: yakjuly@www.yakjuly.com] libxml2.so
** [out :: yakjuly@www.yakjuly.com] libxml2.so.2
** [out :: yakjuly@www.yakjuly.com] libxml2.so.2.6.32
** [out :: yakjuly@www.yakjuly.com] libxmlparse.a
** [out :: yakjuly@www.yakjuly.com] libxmlparse.so
** [out :: yakjuly@www.yakjuly.com] libxmlparse.so.1
** [out :: yakjuly@www.yakjuly.com] libxmlparse.so.1.2
** [out :: yakjuly@www.yakjuly.com] libxmltok.a
** [out :: yakjuly@www.yakjuly.com] libxmltok.so
** [out :: yakjuly@www.yakjuly.com] libxmltok.so.1
** [out :: yakjuly@www.yakjuly.com] libxmltok.so.1.2
** [out :: yakjuly@www.yakjuly.com] xml2Conf.sh
command finished in 560ms
看日志就能知道了大概原理了:本地写好部署代码 远程执行 部署 返回日志 结果。
接着看Getting Start,接着写了 role ,set 设置跳板机 gateway,部署多个域名 等方法。 后面还讲了 cap invoke 和cap shell。
当我按照教程执行 cap -T的时候,结果没有出现下面那么多tasks
cap deploy # Deploys your project.
cap deploy:check # Test deployment dependencies.
cap deploy:cleanup # Clean up old releases.
cap deploy:cold # Deploys and starts a `cold' application.
cap deploy:migrate # Run the migrate rake task.
cap deploy:migrations # Deploy and run pending migrations.
cap deploy:pending # Displays the commits since your last deploy.
原因是没有在app的root_path中执行 capify .
这个方法会在app根目录下创建 Capfile和 config/deploy.rb
cap默认的任务列表就可以在这个对这个app执行了
接下来 编辑 config/deploy.rb。 文件中的描述信息很清楚 跟着提示 填内容就行
set :application, "cookbook"
set :repository, "git@github.com:yakjuly/cookbook_example.git"
set :user, "yakjuly"
set :scm, "git"
set :scm_verbose, true
set :branch, "master"
set :deploy_to, "/home/yakjuly/cookbook.yakjuly.com"
set :use_sudo, false
role :web, "yakjuly.com"
role :app, "yakjuly.com"
dreamhost没有sudo权限,这里要把use_sudo设置为false。
dreamhost的mysql数据库只能在cpannel中创建和访问 所以这里也省略role :db
第一次部署最好执行下
cap deploy:setup
会在服务器上创建shared, releases, current文件夹
- release下保存着每次不同代码部署版本的文件夹,例如下面会有 20110330040708 20110330041621 20110330042212 20110330082446
- current指向的是最新的releases的代码 current -> /home/yakjuly/cookbook.yakjuly.com/releases/20110330082446
- shared是每个版本共享的log等文件存放的文件夹
例如:
current下的log文件夹
lrwxrwxrwx 1 yakjuly pg2609356 45 2011-03-30 01:24 log -> /home/yakjuly/cookbook.yakjuly.com/shared/log
这些都做了解后,开始部署吧
cap deploy
日志显示代码部署部分都正常 但是在 `deploy:restart’ 时候出错,因为dreamhost重新启动passenger是通过 touch tmp/restart.txt来触发的。
因此需要修改deploy:restart 添加代码到Capfile最后
namespace :deploy do
desc "Restarting after deployment"
task :restart, :roles => :app do
run "cd #{release_path} && touch tmp/restart.txt"
end
end
由于服务器上某些配置文件和开发环境不同,可以把修改配置文件的部署写在Capfile或者deploy.rb中
desc "change database etc"
task :link_symlink, :roles => :app do
%w(database).each do |config|
run "cd #{release_path} && rm -rf config/#{config}.yml && ln -sf ../../../shared/config/#{config}.yml config/"
end
end
desc "set environment after code update."
task :set_environment, :roles => :app do
run "sed 's/# ENV\\[/ENV\\[/g' #{release_path}/config/environment.rb > #{release_path}/config/environment.temp"
run "mv #{release_path}/config/environment.temp #{release_path}/config/environment.rb"
end
after "deploy:update_code", :link_symlink, :set_environment
写到这里基本上大功告成了。
但是有个小问题需要注意,部署到服务器上的bundle install能够执行顺利,
但是passenger却爆xxx插件没有安装请运行 bundle install,是因为passenger没有找到bundle安装插件的path
需要在app的root目录下 添加 .bundle/config
---
BUNDLE_DISABLE_SHARED_GEMS: "1"
BUNDLE_PATH: /home/yakjuly/.bundler
运行一遍试试吧,部署是不是很简单?
servers: ["yakjuly.com"]
[yakjuly.com] executing command
** [yakjuly.com :: err] From github.com:yakjuly/cookbook_example
** 4065eb6..459fc2e master -> origin/master
** [yakjuly.com :: out] HEAD is now at 459fc2e change title
command finished in 1965ms
copying the cached version to /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501
* executing "cp -RPp /home/yakjuly/cookbook.yakjuly.com/shared/cached-copy /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501 && (echo 459fc2edd6fdbf48458ebebe27a18d776cf65182 > /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/REVISION)"
servers: ["yakjuly.com"]
[yakjuly.com] executing command
command finished in 572ms
* executing `deploy:finalize_update'
* executing "chmod -R g+w /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501"
servers: ["yakjuly.com"]
[yakjuly.com] executing command
command finished in 550ms
* executing "rm -rf /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/log /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/public/system /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/tmp/pids &&\\\n mkdir -p /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/public &&\\\n mkdir -p /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/tmp &&\\\n ln -s /home/yakjuly/cookbook.yakjuly.com/shared/log /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/log &&\\\n ln -s /home/yakjuly/cookbook.yakjuly.com/shared/system /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/public/system &&\\\n ln -s /home/yakjuly/cookbook.yakjuly.com/shared/pids /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/tmp/pids"
servers: ["yakjuly.com"]
[yakjuly.com] executing command
command finished in 562ms
* executing "find /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/public/images /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/public/stylesheets /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/public/javascripts -exec touch -t 201103300915.02 {} ';'; true"
servers: ["yakjuly.com"]
[yakjuly.com] executing command
command finished in 618ms
triggering after callbacks for `deploy:update_code'
* executing `link_symlink'
* executing "cd /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501 && rm -rf config/database.yml && ln -sf ../../../shared/config/database.yml config/"
servers: ["yakjuly.com"]
[yakjuly.com] executing command
command finished in 549ms
* executing `set_environment'
* executing "sed 's/# ENV\\[/ENV\\[/g' /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/config/environment.rb > /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/config/environment.temp"
servers: ["yakjuly.com"]
[yakjuly.com] executing command
command finished in 548ms
* executing "mv /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/config/environment.temp /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501/config/environment.rb"
servers: ["yakjuly.com"]
[yakjuly.com] executing command
command finished in 602ms
* executing `deploy:symlink'
* executing "rm -f /home/yakjuly/cookbook.yakjuly.com/current && ln -s /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501 /home/yakjuly/cookbook.yakjuly.com/current"
servers: ["yakjuly.com"]
[yakjuly.com] executing command
command finished in 550ms
** transaction: commit
* executing `deploy:restart'
* executing "cd /home/yakjuly/cookbook.yakjuly.com/releases/20110330091501 && touch tmp/restart.txt"
servers: ["yakjuly.com"]
[yakjuly.com] executing command
command finished in 548ms