Offical Site: http://capistranorb.com/
Github: https://github.com/capistrano/capistrano
原文 https://ruby-china.org/topics/18616
Offical Site: http://capistranorb.com/
Github: https://github.com/capistrano/capistrano
Capistrano 3.1 相对于之前的2.x有着很大不同,本想用自动化发布,应该是分分种搞定的事情,没想到找文档,看说明,花了一天也没看出个什么,于是晚上花时间把2.x和3.1的代码过了下,做了个对比,总算搞明白了里面的一些机制。
unicorn 4.8.2 rails 4.1.0 ruby 2.1.1 capistrano 3.1
在Gemfile
中添加Capistrano和其它用到的插件
group :development do gem 'capistrano' gem 'capistrano-bundler' gem 'capistrano-rails' gem 'capistrano-rbenv' # Add this if you're using rvm # gem 'capistrano-rvm' end
$ cap install
会生成如下目录文件,Capfile
用来配置Capistrano,deploy.rb
是一些共用task的定义,而production.rb/staging.rb
用来定义具体的stage的tasks。
├── Capfile ├── config │ ├── deploy │ │ ├── production.rb │ │ └── staging.rb │ └── deploy.rb └── lib └── capistrano └── tasks
安装完成之后,通过 cap -vT
来查看当前项目的可执行任务列表。
cap bundler:install # Install the current Bundler environment cap deploy # Deploy a new release cap deploy:check # Check required files and directories exist cap deploy:check:directories # Check shared and release directories exist cap deploy:check:linked_dirs # Check directories to be linked exist in shared cap deploy:check:linked_files # Check files to be linked exist in shared cap deploy:check:make_linked_dirs # Check directories of files to be linked exist in shared ... cap install # Install Capistrano, cap install STAGES=staging,production
这些命令其中就包括 刚刚执行的cap install
,其它用到的,后面再讲。
Capfile
里开启要用到的一些插件require 'capistrano/setup' require 'capistrano/deploy' require 'capistrano/rbenv' require 'capistrano/bundler' require 'capistrano/rails/assets' require 'capistrano/rails/migrations' Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }
###
本文件中用来配置共用变量。
# config valid only for Capistrano 3.1 lock '3.1.0' set :application, 'appname' set :deploy_user, 'ares' set :scm, :git set :repo_url, '[email protected]:lanvige/railsapp.git' # rbenv set :rbenv_type, :user set :rbenv_ruby, '2.1.1' set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec" set :rbenv_map_bins, %w{rake gem bundle ruby rails} # how many old releases do we want to keep, not much set :keep_releases, 5 # files we want symlinking to specific entries in shared set :linked_files, %w{config/database.yml config/application.yml config/secrets.yml} # dirs we want symlinking to shared set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system} namespace :deploy do after :finishing, 'deploy:cleanup' end
Stage
关于Stage,详见:
一个很重要的配置是Role、Server(User)以及其对应关系,为了方便,Cap3中提供了多种配置形式,各有不同的侧重,但用途都是一样的,见下面。
# 以role为中心的写法 role :app, %w{[email protected], [email protected]} role :web, %w{[email protected]} role :db, %w{[email protected]} # 以server为中心的写法,上面的写法可以用以下写法代替: server 'example.com', user: 'deploy', roles: %w{web app db} server 'example.local', user: 'deploy', roles: %w{app} # 如果要对某服务器配置SSH等更多时,也可以用这种写法: server 'example.com', user: 'user_name', roles: %w{web app}, ssh_options: { user: 'user_name', # overrides user setting above keys: %w(/home/user_name/.ssh/id_rsa), forward_agent: false, auth_methods: %w(publickey password) # password: 'please use keys' }
Stage示例
set :stage, :test set :branch, 'develop' server '192.168.1.1', user: 'ares', roles: %w{web app db} set :deploy_to, "/home/#{fetch(:deploy_user)}/apps/appname" # dont try and infer something as important as environment from # stage name. set :rails_env, :test # number of unicorn workers, this will be reflected in # the unicorn.rb and the monit configs set :unicorn_worker_count, 5 # whether we're using ssl or not, used for building nginx # config file set :enable_ssl, false
$ cap production deploy --dry-run $ cap production deploy
输入服务器用户密码后就deploy就进行了。不想每次都输密码,ssh-copy-id可能是你想要的。
运行多次deploy之后会生成这样的目录结构:
. ├── current -> /home/ares/apps/appname/releases/20140325071623 ├── releases │ ├── 20140325065734 │ ├── 20140325071310 │ ├── 20140325071623 │ └── 20140325074922 ├── repo │ ├── branches │ ├── config │ ├── description │ ├── FETCH_HEAD │ ├── HEAD │ ├── hooks │ ├── info │ ├── objects │ ├── packed-refs │ └── refs ├── revisions.log └── shared ├── bin ├── bundle ├── config ├── log ├── public ├── tmp └── vendor
$ cap production deploy:rollback
Rollback其实就是把current目录指向到releases里上次发布的目录。
Cap Flow
系统默认包含下面的这些Task,Task是有顺序的,在每个Task之前和之后可以通过before
, after
添加自定义的Task。更多Flow介绍,见这里
在这些Flow之外也有一些常用的Task:
对应Cap 2.x中的 deploy:setup。
check不属于deploy flow,它的目的主要是在服务器上创建所需要的目录(主要是shared, release),然后就是对应的linked_dir & linked_files操作。
新的系统中,核心的deploy task是幂等(idempotent)的,所以像cap deploy:cold
这样的预执行命令(创建目录结构)就不再被需要了。
dry-run主要是保证每一个命令都能被执行到,但不会在服务器上产生任何改动。
$ cap production deploy —dry-run
Cap中有和Rails一样的运行环境(Environment
)的概念(Cap中叫作Stage
,默认建了2个Stage,staging
, production
),就是不同环境下对应不同的服务器。
deploy.rb
中定义着公用的变量,对应到不同的Stage,可以定义一些专有的变量,同时也可以覆写deploy.rb中的公用变量。
注:Stage名字默认对应Rails的environment名字(development
, test
, production
)。可通过设置进行映射。
set :rails_env, :test
linked_files
& linked_dirs
Capistrano使用Shared
目录来管理那些在不同Release
中共用的文件,最主要的一个shared/config
中包含每个发布所需要的配置文件
database.yml
,secret.yml
这样的敏感文件。对于这些文件最好的做法就是从Git中过滤掉,然后每个开发者和服务器都单独配置。 在尝试使用SQLite3进行Cap测试通过后,将DB换成MySQL,然后又出错了。错误是数据库不存在,一直以为是在创建数据库时未指定RAILS_EVN
,后来发现migrations在执行前也没有运行db:create
来创建数据库。
在运行deploy前,自己手工创建数据库,然后deploy就能正常运行了。猜想:create属于一次性操作,所以没有将其作为task放入deploy中。
在deploy.rb和stage文件中,我们可以设置变量的值。但有时,值会在运行时才被确定,这样就可以通过ask来设定。
ask :branch, ‘my_default_branch’
这样在branch变量第一次被使用时,会有输入提示,就可以动态设置该值了。
角色的目的是让Task可以运行在不同的机器上。更多
一个线上程序中有着多种服务器,像DB Server, APP server, Web Server,在不同的Server上要运行不同的部署方案。Cap也把这些也考虑到了,可以通过创建不同的Role来对这些服务器进行归类,为Task指定Role来运行。
如何自定义taskdoc
可以在发布进行之前做一些准备工作,比如,创建linked_files、Unicorn、Nginx的配置及创建Service的工作。
现行的作法是,定制一个task,在Deploy之前进行,在服务器创建目录,然后从本地将文件预先upload!)到服务器的相应目录(主要是shared/config
)。
Capistrano 3 推荐使用 passwordless sudo。这样非root用户也可以直接使用sudo命令,而不必通过PTY来输入密码。Guide:
其实就是在系统里,给指定用户赋上某些指令的sudo权限。在Ubuntu下,修改 /etc/sudoers
来添加要使用的命令。
ares ALL=NOPASSWD:/usr/sbin/service, /bin/ln #也可以将所有程序都设置为不要密码,不过太不安全,不建议 #ares ALL=(ALL) NOPASSWD: ALL
PTY就是让用户在当前Terminal中执行任务时,可以进行交互。比如说执行sudo任务时,可以远程输入密码。 更多
ps :试着启用pts,但输入密码后无反应。
每次运行cap都要输入密码,可以将本地的ssh公钥存到server上,就可以省下很多时间。
ssh-copy-id就是这么一个将本机的公钥复制到远程机器的authorized_keys文件的工具,其也能让你拥有远程机器的home, ~./ssh , 和 ~/.ssh/authorized_keys的权利。
首先本地机器上要创建ssh key
$ ssh-keygen
$ ssh-copy-id [email protected]
Mac OSX 上 ssh-copy-id不是默认安装的,可通过Homebrew进行安装
$ brew install ssh-copy-id