使用GitLab CI + Capistrano部署CakePHP应用程序

使用GitLab CI + Capistrano部署CakePHP应用程序

摘要:本文描述了如使用GitLab CI + Capistrano部署CakePHP应用程序。


 

目录

1. 问题
2. 解决方法
3. 安装和设置GitLab CI Runner
4. 安装和配置Capistrano
    4.1 安装Ruby
    4.2 安装Capistrano
    4.3 在项目中配置Capistrano
    4.4 用户的验证和授权
    4.5 其它工具和设置
5. 部署
6. 小结
A. 参考资料


 

1. 问题

作为软件开发人员,除了写代码,还有很多事情需要我们操心。比如,开发的应用程序总是要部署到某个环境中,在开发的过程中要经常部署到开发(DEV)环境,便于整个团队对代码进行集成和测试,以后又要部署到UAT/Staging环境,通过最后的质量验证步骤,才可以部署到生产(Production)环境。在一个敏捷开发过程中,持续集成通常要求自动化构建和部署,减少人为的介入,同时又要针对不同的环境采用不同的设置,这个过程会面临各种细致的问题,比如,如何保证安全性和保护一些秘密(用户名和密码等),如何协调部署中变化的部分(比如程序代码)和不变的部分(比如用户输入的数据),需要采取什么样的工具,这就是本文要讨论的。

2. 解决方法

在之前的文章中我们介绍过Travis CI,这是一个轻量的持续集成工具。在本文中,我们要介绍另一个持续集成工具GitLab CI,之所以采用它,因为这是和我采用的源码控制GitLab密切集成的。它能够随时监视代码的提交,针对每次提交进行构建和部署。

另外一个我们要介绍的工具Capistrano,是用Ruby开发的远程服务器自动化和部署工具,可以部署Ruby on Rails应用,也可以部署用其它各种语言开发的应用。从这个工具,我们可以看到,在一个自由的环境中,随着需要,可以激发出各种创新的欲望,催生出适用的工具。这个工具对我来说是更为陌生,又可以说是相当复杂,主要是缺乏很好的向导类文章,所以我看了很多介绍文章(参考资料[5]-[11]),才能有个大致的概念。需要注意的是,2013年6月1日发布了Capistrano version 3,这和之前的Capistrano version 2有很大的变化,概念和流程类似,但是写法很不同,因为 Capistrano 3抛弃了Capistrano 2自己的DSL,而采用了Rake (Ruby Make)的DSL。所以在读介绍文章的时候,要特别注意,比如参考资料[5]其实用的就是Capistrano 2。至今Capistrano 3已经发布将近2年了,应该相当成熟了,适用也比较广泛了,而且现在也有很多插件,可以进一步扩展功能。在本文中我们会采用Capistrano 3。

对于文章开始提出的问题,我们要做的,就是用GitLab CI在每次提交代码的时候,启动任务,用Capistrano 3进行应用程序的构建和部署。下面我们就来详细介绍进行配置的各个步骤。

3. 设置GitLab CI

首先要在GitLab创建账号,创建代码库,上传项目代码。然后用相同的账号登录GitLab CI,针对某个代码库启用持续集成。这些步骤因为是写这篇文章之前做的,没有记录和截图,所以无法详述具体的操作步骤了,但应该不是难事。

GitLab CI中,进入代码库相应的Runners页面,如下图所示:

GitLab CI Runner

这里会列出所有的Runners,一开始这里是空的,可以按照说明的步骤和链接来安装Runner。Runner可以在安装在任何机器上,我觉得应该是在一台一直运行的机器,比如DEV服务器,这样才可以在提交代码时随时进行部署。我因为用的是AWS的Ubuntu 14.04,所以采用了GitLab Runner Omnibus Package for Linux,说明如下图所示。注意在 Register your runner instance with a GitLab CI Coordinator 这一步时需要用到上面提到的URL和registration token。

安装GitLab CI Runner using Omnibu Package for Linux

但是在写这篇文章的过程中,发现Runner已经更新成了另一个用Go写的gitlab-ci-multi-runner,这个的功能更为强大,支持多种操作系统(Linux、Mac、Windows),可以运行多任务,支持Docker,等等,可见参考资料[2][24],安装说明相关的部分如下:

Install using official GitLab repositories (1)

Install using official GitLab repositories (2)

然后配置要运行的任务,如下图所示:

GitLab CI Deployment Job

要记得,GitLab CI Multi Runner运行的用户是gitlab_ci_multi_runner,后面4.4一节中的设置要针对此用户进行。

最后,还有一个设置,如下图所示,在Settings中,要清除Allow run builds on shared runners这个设置,否则就会使用GitLab CI上共享的runner来部署,导致部署失败,见参考资料[25]:

clear Allow run builds on shared runners

4. 安装和配置Capistrano

Capistrano需要安装到GitLab CI Runner所在的机器上,这样才可以由Runner调用Capistrano进行部署。jadb/capcake是Capistrano的一个插件(可以认为是对Capistrano的扩展),专门用来部署CapePHP应用程序的,下面都是采用jadb/capcake来进行。

4.1 安装Ruby

因为Capistrano是用Ruby开发的,所以必须要安装Ruby,这可以参考Installing Ruby。因为我用的是Ubuntu,所以最简单的就是用apt-get

me@localhost $ sudo apt-get update
me@localhost $ sudo apt-get install ruby-full

这样在我的 Ubuntu 14.04 Vagrant 虚拟机上,安装的是稳定的 1.9.3 版本,这足够了:

me@localhost $ ruby -v
ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-linux]

4.2 安装Capistrano

有不同的方法安装Capistrano,可以参考Capistrano的Installation文档。我们按照jadb/capcake的安装说明,在项目的根目录中,创建Ruby的包配置文件Gemfile:

source 'https://rubygems.org'
gem 'capistrano', '~> 3.4.0'  # not 3.0.0
gem 'capcake', '~> 3.0.0'

然后运行:

me@localhost $ bundle

这样就安装了Capistrano和capcake ,用下面的命令可以看到Capistrano的版本:

me@localhost $ cap -v
Capistrano Version: 3.4.0 (Rake Version: 10.4.2)

4.3 在项目中配置Capistrano

这时候需要对项目做一些准备,可以参考Capistrano文档中的Preparing Your Application,这包括,把项目代码提交到源码管理中,把项目中包含机密信息(密码、秘钥等)的文件移出项目,等等。

然后在项目中初始化Capistrano:

me@localhost $ cd my-project
me@localhost $ cap install

这会创建如下的目录和文件:

├── Capfile
├── config
│   ├── deploy
│   │   ├── production.rb
│   │   └── staging.rb
│   └── deploy.rb
└── lib
    └── capistrano
            └── tasks

Capfile是Capistrano的基本配置,引入了各项任务,包括lib/capistrano/tasks目录下的任务:

# Load DSL and Setup Up Stages
require 'capistrano/setup'

# Includes default deployment tasks
require 'capistrano/deploy'

require 'capistrano/composer'
require
'capistrano/cakephp' # require 'capistrano/cakephp/assets' # require 'capistrano/cakephp/migrations' # Loads custom tasks from `lib/capistrano/tasks' if you have any defined. Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }

deploy.rb是共用的设置,比如应用程序的名称,源码库的地址、分支、以及要部署的目录等:

set :application, 'my-project'
set :repo_url, 'git@gitlab.com:my_account/my_project.git'
set :branch, 'master'

set :deploy_to, '/var/www/my-project'
# set :scm, :git

# set :format, :pretty
# set :log_level, :debug
# set :pty, true

# set :linked_files, %w{config/database.yml}
# set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
set :linked_dirs, fetch(:linked_dirs) + %w{tmp/logs webroot/files}

set :repo_tree, 'app'

namespace :composer do
    desc 'Composer update'
    task :change_dir do
        on roles(:web) do
            execute "cd #{release_path}/ && composer update"
        end
    end

    before 'install', 'change_dir'
end

其中,

:deploy_to为要部署的目录,缺省为/var/www/#{fetch(:application)},即/var/www目录下以:application设置的应用程序名称的子目录

:scm是源码控制的工具,Capistrano本身支持Git/Mercurial/Subversion。

:linked_dirs是要链接(symlink)到部署的目录下的目录,比如日志目录、上传文件的目录等等,相应的,:linked_files是要链接的文件。

:repo_tree是要部署的子目录。在要部署的代码不是整个项目的根目录,而只是项目根目录下的一个子目录时,用该设置指定要部署的子目录。对于CakePHP应用程序,通常app目录是自己写代码的目录。

更多关于变量的说明可以参考Configuration文档

最后的一段代码composer:change_dir任务,是为了应对composer:install这项任务的一个问题,详情可见参考资料[20]。

而production.rb (和 staging.rb)是针对具体某个环境的设置:

set :stage, :production

# Simple Role Syntax
# ==================
# Supports bulk-adding hosts to roles, the primary
# server in each group is considered to be the first
# unless any hosts have the primary property set.
# role :app, %w{example.com}
# role :web, %w{example.com}
# role :db,  %w{example.com}

# Extended Server Syntax
# ======================
# This can be used to drop a more detailed server
# definition into the server list. The second argument
# is something that quacks like a hash and can be used
# to set extended properties on the server.
server 'my-server.com', roles: %w{web app}, my_property: :my_value

这里,首先是声明是针对生产环境(:production)的。然后有两种方法设置要部署的服务器,前一种是简单的方法(注释掉的三行),后一种是扩展的服务器设置(最后一行),可以设置地址,角色以及其它属性,采用其中一种即可。

4.4 用户的验证和授权

这一节的内容对通常的开发人员最为陌生,也是本文中最复杂的部分,要特别注意。

这里需要在最终要部署的服务器上创建适当的用户,并给予该用户足够的权限,可以参考Capistrano文档中的Authentication & Authorisation。记得,要在每台要进行部署的服务器上都要做下面的步骤。

首先登录服务器,创建进行部署操作的用户deployer:

me@my-server.com $ sudo adduser deployer
Adding user `deployer' ...
Adding new group `deployer' (1001) ...
Adding new user `deployer' (1001) with group `deployer' ...
Creating home directory `/home/deployer' ...
Copying files from `/etc/skel' ...
Enter new UNIX password: ********
Retype new UNIX password: ********
passwd: password updated successfully
Changing the user information for deployer
Enter the new value, or press ENTER for the default
  Full Name []:
  Room Number []:
  Work Phone []:
  Home Phone []:
  Other []: Is the information correct? [Y/n]
me@my-server.com $ sudo
passwd -l deployer
passwd: password expiry information changed.

第一个命令创建一个标准的用户,拥有用户目录(home directory),可以使用shell,因此可以登录服务器。第二个命令锁住了用户的密码,这样就使得用户无法输入密码,从而无法用密码进行登录,要登录可以使用秘钥(SSH key)。

下面要为deployer用户验证(Authentication)设置秘钥,这主要用于从开发人员的机器(或者GitLab CI Runner所在的机器)登录到要部署的服务器上进行部署。

4.4.1 从GitLab CI Runner所在的机器到要部署的服务器的用户验证

首先需要创建自己使用的秘钥。如果在执行SSH相关的命令时遇到“Could not open a connection to your authentication agent.”这样的错误提示,请按照参考资料[16][17]进行设置。在本地的开发机器上执行如下命令:

me@localhost $ cd ~/.ssh
me@localhost $ ssh-keygen -t rsa -f me@my_email_address.com -C 'me@my_email_address.com'
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in me@my_email_address.com.
Your public key has been saved in me@my_email_address.com.pub.
The key fingerprint is:
60:e4:f3:f3:76:99:ce:66:d7:8a:4a:db:ec:c7:de:11 me@my_email_address.com
The key's randomart image is:
+--[ RSA 2048]----+
|      .          |
|     o           |
|      =          |
|     . +         |
|        S      E |
|         o   o  .|
|          + +. o |
|         o Bo.+.o|
|          o=B+o..|
+-----------------+

上面的ssh-keygen命令会创建一个秘钥,-t选项指定秘钥的类型为RSA,-f选项指定生成的文件名称,-C选项指定注释。这样就会生成2个文件:

me@localhost $ ls -l me*
-rw-------  1 me  staff  1766 May  3 15:54 me@my_email_address.com
-rw-r--r--  1 me  staff   405 May  3 15:54 me@my_email_address.com.pub

其中,me@my_email_address.com这个文件是私钥,而me@my_email_address.com.pub这个文件为公钥。如果生成的过程中你输入了密码(passphrase),则私钥有密码保护。

如果你已经有了自己的秘钥,但是私钥没有密码的保护,要加上或者改变密码,可以用如下命令:

me@localhost $ ssh-keygen -f me\@my_email_address.com -p
Enter old passphrase:
Key has comment 'me@my_email_address.com'
Enter new passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved with the new passphrase.

把生成的秘钥加入秘钥列表中:

me@localhost $ ssh-add me\@my_email_address.com
Identity added: me@my_email_address.com (me@my_email_address.com)

下面要把生成的公钥上传到要部署的服务器上相应的用户(即上面创建的deployer)的 ~/.ssh/authorized_keys 文件中。在Linux上通常会有ssh-copy-id这个命令,就是用来做这件事的:

me@localhost $ ssh-copy-id -i me@my_email_address.com deployer@my-server.com
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'deployer@my-server.com'"
and check to make sure that only the key(s) you wanted were added.

如果你的系统上没有ssh-copy-id这个命令,那么可以这么做:

me@localhost $ ssh-add -L  # 列出公钥
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0nGH9BA7EoAIRsCb+xwZkp20muUJdl/EtLffp5E0yOeEDRvlP9d9tpLZKKPSGG6SZo4CQNziv8kc7Bpogozafz2BG8YEk2mwdYm5jcGgKhH3YtVX7AGGga8mwFRgIed/jx4bxUEBP1uxANsL7ZOWrBOUj0YjcFelFU5aJYn822s3e+OXAPk4y02iZneHflf6lMoMP5mMIOReGmemxYzjNSy39JD0l8HULgh/4AlQzz0vDHKjidaOy21zf1YcV/FkOERMxozEXaYIjN0ff5gpSG8GN0gGKcNCy7hYil02bJBePc/AdBWxUSHJl6mpxGtoEn/nI7z6h/3BEr8E9KAGN me@my_email_address.com
me@localhost $ ssh root@my-server.com
root@my-server.com # su - deployer
deployer@my-server.com $ cd ~
deployer@my-server.com $ mkdir .ssh
deployer@my-server.com $ echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0nGH9BA7EoAIRsCb+xwZkp20muUJdl/EtLffp5E0yOeEDRvlP9d9tpLZKKPSGG6SZo4CQNziv8kc7Bpogozafz2BG8YEk2mwdYm5jcGgKhH3YtVX7AGGga8mwFRgIed/jx4bxUEBP1uxANsL7ZOWrBOUj0YjcFelFU5aJYn822s3e+OXAPk4y02iZneHflf6lMoMP5mMIOReGmemxYzjNSy39JD0l8HULgh/4AlQzz0vDHKjidaOy21zf1YcV/FkOERMxozEXaYIjN0ff5gpSG8GN0gGKcNCy7hYil02bJBePc/AdBWxUSHJl6mpxGtoEn/nI7z6h/3BEr8E9KAGN me@my_email_address.com" >> .ssh/authorized_keys
deployer@my-server.com $ chmod 700 .ssh
deployer@my-server.com $ chmod 600 .ssh/authorized_keys

用下面的命令验证上面所做的设置是正确的:

me@localhost $ ssh deployer@my-server.com 'hostname; uptime'
my-server.com
19:23:32 up 62 days, 44 min, 1 user, load average: 0.00, 0.01, 0.05

这应该不需要你输入密码,就能完成。这需要在每台服务器上(通过改变@my-server.com为其它服务器的主机名或IP地址)证实。

记得把私钥放在安全的地方。如果你负责管理整个团队的部署,那么可能需要收集每个可以做部署的开发人员的公钥,然后进行上面的步骤。

4.4.2 从部署的服务器到源代码控制服务器的用户验证

这里有三种方法,分别为SSH Agent Forwarding,HTTP Authentication和Deploy Keys,详情可以参考Capistrano的Authentication & Authorisation文档中1.2一节。

我采用的是Deploy Keys,这就是要生成一个不同的秘钥,只用于部署,这在Github等源码控制托管商都有相应的管理方法。

先用上面介绍的命令ssh-keygen生成用于部署的秘钥deployer@my_email.address.com。

然后在我使用的源码控制托管商GitLab上该项目的设置页面中,进入Deploy Keys页面(https://gitlab.com/my_username/my_project/deploy_keys),添加新的Deploy Key,拷贝公钥deployer@my_email.address.com.pub 的内容到这里,如下图所示:

Deploy Key

最后只需在本地(开发者的机器或者GitLab CI Runner运行的机器上)添加该秘钥即可:

me@localhost $ ssh-add deployer\@my_email_address.com
Identity added: deployer@my_email_address.com (deployer@my_email_address.com)

4.4.3 服务器上的用户授权

我们在服务器上用来部署的用户需要有足够的权限,在部署的目录中进行创建/删除/读/写目录和文件的操作。这仍然可以参考Capistrano的Authentication & Authorisation文档中Authroisation一节。

me@localhost $ ssh deployer@my-server.com
# 下面的 deploy_to 目录就是 Capistrano 要部署的目标目录,
# /var/www/ 后面的部分是由 deploy.rb 中的 :application 中设置的
# 你也可以设置 :deploy_to 变量来改变部署的目标目录,正如我们在本文4.3一节看到的。
deployer@my-server.com $ deploy_to=/var/www/my-project
deployer@my-server.com $ sudo mkdir -p ${deploy_to}
deployer@my-server.com $ sudo chown deployer:deployer ${deploy_to}
deployer@my-server.com $ umask 0002
deployer@my-server.com $ sudo chmod g+s ${deploy_to}
deployer@my-server.com $ sudo mkdir ${deploy_to}/{releases,shared}
deployer@my-server.com $ sudo chown deployer ${deploy_to}/{releases,shared}

其中,chmod g+s命令会使任何在${deploy_to}目录中创建的子目录继承${deploy_to}目录的组,而umask 0002会保证创建的文件具有拥有者可以读写,组可以读写,其它无权限的设置。

用下面的命令来验证上面的设置是正确的:

root@my-server.com # stat -c "%A (%a) %n" ${deploy_to}/
drwxr-sr-x (2755) /var/www/my-project/

root@my-server.com # stat -c "%A (%a) %n" ${deploy_to}/*
drwxr-sr-x (2755) /var/www/my-project/releases
drwxr-sr-x (2755) /var/www/my-project/shared

4.4.4 验证操作权限

我们来验证在这一节中上面所做的用户验证和授权的设置都是正确的,请参考Capistrano的Cold Start文档。

先检查我们在服务器上是否有足够的权限,这也是我们手工写的第一个Capistrano任务。相对于项目根目录,创建文件./lib/capistrano/tasks/access_check.cap:

desc "Check that we can access everything"
task :check_write_permissions do
  on roles(:all) do |host|
    if test("[ -w #{fetch(:deploy_to)} ]")
      info "#{fetch(:deploy_to)} is writable on #{host}"
    else
      error "#{fetch(:deploy_to)} is not writable on #{host}"
    end
  end
end

这样添加的新任务应该可以用下面的命令看到:

me@localhost $ cap -T
cap cakephp:cake[command_name]     # Executes a cake command
cap check_write_permissions # Check that we can access everything # ... 其它 Capistrano 任务 ...

运行该任务,检查deployer能够在服务器上进行所需的操作:

me@localhost $ cap production check_write_permissions
DEBUG [96f5c014] Running /usr/bin/env [ -w /var/www/my-project ] as deployer@my-server.com
DEBUG [96f5c014] Command: [ -w /var/www/my-project ]
DEBUG [96f5c014] Finished in 1.798 seconds with exit status 0 (successful).
INFO /var/www/my-project is writable on my-server.com

再来检查是否可以从服务器访问源码控制的代码库。因为检查Git稍微复杂一些,而且使用代码操作Git并不容易,所以Capistrano提供了如下的任务:

me@localhost $ cap production git:check
INFO [ef4028de] Running /usr/bin/env mkdir -p /tmp/my-project/ as deployer@my-server.com
DEBUG [ef4028de] Command: /usr/bin/env mkdir -p /tmp/my-project/
INFO [ef4028de] Finished in 0.514 seconds with exit status 0 (successful).
DEBUG Uploading /tmp/my-project/git-ssh.sh 0.0%
INFO Uploading /tmp/my-project/git-ssh.sh 100.0%
INFO [0f73bb2d] Running /usr/bin/env chmod +x /tmp/my-project/git-ssh.sh as deployer@my-server.com
DEBUG [0f73bb2d] Command: /usr/bin/env chmod +x /tmp/my-project/git-ssh.sh
INFO [0f73bb2d] Finished in 0.016 seconds with exit status 0 (successful).
DEBUG [42deaf82] Running /usr/bin/env git ls-remote git@gitlab.com:my_account/my_project.git as deployer@my-server.com
DEBUG [42deaf82] Command: ( GIT_ASKPASS=/bin/echo GIT_SSH=/tmp/my-project/git-ssh.sh /usr/bin/env git ls-remote git@gitlab.com:my_account/my_project.git )
DEBUG [42deaf82]     5a54268e8b92c5b6e1e4646dc719a10c5a1226ff    HEAD
DEBUG [42deaf82]     5a54268e8b92c5b6e1e4646dc719a10c5a1226ff    refs/heads/master
DEBUG [42deaf82] Finished in 7.391 seconds with exit status 0 (successful).

至此,一切正常,我们可以进行下一步了。

4.5 其它工具和设置

在服务器上进行部署时,还要用到一些额外的工具和设置。

首先是PHP的包管理软件Composer。按照它的Getting Started中的安装步骤:

deployer@my-server.com $ sudo curl -sS https://getcomposer.org/installer | php
#!/usr/bin/env php
All settings correct for using Composer
Downloading...

Composer successfully installed to: /home/deployer/composer.phar
Use it: php composer.phar
deployer@my-server.com $ sudo mv composer.phar /usr/local/bin/composer

另外,CakePHP需要PHP的扩展mcrypt,请参考mcrypt的安装/配置文档中:

deployer@my-server.com $ sudo apt-get install php5-mcrypt
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
  libmcrypt4
Suggested packages:
  libmcrypt-dev mcrypt
The following NEW packages will be installed:
  libmcrypt4 php5-mcrypt
0 upgraded, 2 newly installed, 0 to remove and 152 not upgraded.
Need to get 77.3 kB of archives.
After this operation, 324 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://ap-southeast-1.ec2.archive.ubuntu.com/ubuntu/ trusty/universe libmcrypt4 amd64 2.5.8-3.1ubuntu1 [61.9 kB]
Get:2 http://ap-southeast-1.ec2.archive.ubuntu.com/ubuntu/ trusty/universe php5-mcrypt amd64 5.4.6-0ubuntu5 [15.4 kB]
Fetched 77.3 kB in 0s (3838 kB/s)
Selecting previously unselected package libmcrypt4.
(Reading database ... 64192 files and directories currently installed.)
Preparing to unpack .../libmcrypt4_2.5.8-3.1ubuntu1_amd64.deb ...
Unpacking libmcrypt4 (2.5.8-3.1ubuntu1) ...
Selecting previously unselected package php5-mcrypt.
Preparing to unpack .../php5-mcrypt_5.4.6-0ubuntu5_amd64.deb ...
Unpacking php5-mcrypt (5.4.6-0ubuntu5) ...
Setting up libmcrypt4 (2.5.8-3.1ubuntu1) ...
Setting up php5-mcrypt (5.4.6-0ubuntu5) ...
Processing triggers for libc-bin (2.19-0ubuntu6.3) ...

deployer@my-server.com $ sudo service apache2 restart
 * Restarting web server apache2                                                             [ OK ]

再为命令行启用mcrypt:

deployer@my-server.com $ sudo ln -s /etc/php5/mods-available/mcrypt.ini /etc/php5/cli/conf.d/20-mcrypt.ini

5. 部署

现在准备工作做的差不多了,可以开始真正的部署了。我们先进行手工部署,只需要在项目根目录下执行一个命令cap production deploy就可以部署到生产环境了:

me@localhost $ cap production deploy
INFO [118bf2b0] Running /usr/bin/env mkdir -p /tmp/my-project/ as deployer@my-server.com
DEBUG [118bf2b0] Command: /usr/bin/env mkdir -p /tmp/my-project/
INFO [118bf2b0] Finished in 0.367 seconds with exit status 0 (successful).
DEBUG Uploading /tmp/my-project/git-ssh.sh 0.0%
INFO Uploading /tmp/my-project/git-ssh.sh 100.0%
INFO [e72de67d] Running /usr/bin/env chmod +x /tmp/my-project/git-ssh.sh as deployer@my-server.com
DEBUG [e72de67d] Command: /usr/bin/env chmod +x /tmp/my-project/git-ssh.sh
INFO [e72de67d] Finished in 0.016 seconds with exit status 0 (successful).
INFO [3ec77d26] Running /usr/bin/env git ls-remote --heads git@gitlab.com:my_account/my_project.git as deployer@my-server.com
DEBUG [3ec77d26] Command: ( GIT_ASKPASS=/bin/echo GIT_SSH=/tmp/my-project/git-ssh.sh /usr/bin/env git ls-remote --heads git@gitlab.com:my_account/my_project.git )
DEBUG [3ec77d26] 	fbc99fa4c6e11ab56be654a291b8e86b5327526f	refs/heads/master
INFO [3ec77d26] Finished in 8.877 seconds with exit status 0 (successful).
INFO [7b880538] Running /usr/bin/env mkdir -p /var/www/my-project/shared /var/www/my-project/releases as deployer@my-server.com
DEBUG [7b880538] Command: /usr/bin/env mkdir -p /var/www/my-project/shared /var/www/my-project/releases
INFO [7b880538] Finished in 0.016 seconds with exit status 0 (successful).
INFO [12fa8621] Running /usr/bin/env mkdir -p /var/www/my-project/shared/logs /var/www/my-project/shared/tmp/cache/models /var/www/my-project/shared/tmp/cache/persistent /var/www/my-project/shared/tmp/cache/views /var/www/my-project/shared/tmp/sessions /var/www/my-project/shared/tmp/tests as deployer@my-server.com
DEBUG [12fa8621] Command: /usr/bin/env mkdir -p /var/www/my-project/shared/logs /var/www/my-project/shared/tmp/cache/models /var/www/my-project/shared/tmp/cache/persistent /var/www/my-project/shared/tmp/cache/views /var/www/my-project/shared/tmp/sessions /var/www/my-project/shared/tmp/tests
INFO [12fa8621] Finished in 0.017 seconds with exit status 0 (successful).
DEBUG [e11395db] Running /usr/bin/env [ -f /var/www/my-project/current/REVISION ] as deployer@my-server.com
DEBUG [e11395db] Command: [ -f /var/www/my-project/current/REVISION ]
DEBUG [e11395db] Finished in 0.017 seconds with exit status 1 (failed).
DEBUG [66d77b61] Running /usr/bin/env [ -f /var/www/my-project/repo/HEAD ] as deployer@my-server.com
DEBUG [66d77b61] Command: [ -f /var/www/my-project/repo/HEAD ]
DEBUG [66d77b61] Finished in 0.015 seconds with exit status 0 (successful).
INFO The repository mirror is at /var/www/my-project/repo
DEBUG [b45cdad1] Running /usr/bin/env if test ! -d /var/www/my-project/repo; then echo "Directory does not exist '/var/www/my-project/repo'" 1>&2; false; fi as deployer@my-server.com
DEBUG [b45cdad1] Command: if test ! -d /var/www/my-project/repo; then echo "Directory does not exist '/var/www/my-project/repo'" 1>&2; false; fi
DEBUG [b45cdad1] Finished in 0.015 seconds with exit status 0 (successful).
INFO [c63f6bd9] Running /usr/bin/env git remote update as deployer@my-server.com
DEBUG [c63f6bd9] Command: cd /var/www/my-project/repo && ( GIT_ASKPASS=/bin/echo GIT_SSH=/tmp/my-project/git-ssh.sh /usr/bin/env git remote update )
DEBUG [c63f6bd9] 	Fetching origin
INFO [c63f6bd9] Finished in 7.166 seconds with exit status 0 (successful).
DEBUG [5e0897b2] Running /usr/bin/env if test ! -d /var/www/my-project/repo; then echo "Directory does not exist '/var/www/my-project/repo'" 1>&2; false; fi as deployer@my-server.com
DEBUG [5e0897b2] Command: if test ! -d /var/www/my-project/repo; then echo "Directory does not exist '/var/www/my-project/repo'" 1>&2; false; fi
DEBUG [5e0897b2] Finished in 0.025 seconds with exit status 0 (successful).
INFO [1c04aa23] Running /usr/bin/env mkdir -p /var/www/my-project/releases/20150506134335 as deployer@my-server.com
DEBUG [1c04aa23] Command: cd /var/www/my-project/repo && ( GIT_ASKPASS=/bin/echo GIT_SSH=/tmp/my-project/git-ssh.sh /usr/bin/env mkdir -p /var/www/my-project/releases/20150506134335 )
INFO [1c04aa23] Finished in 0.019 seconds with exit status 0 (successful).
INFO [2c26d74f] Running /usr/bin/env git archive master app | tar -x --strip-components 1 -f - -C /var/www/my-project/releases/20150506134335 as deployer@my-server.com
DEBUG [2c26d74f] Command: cd /var/www/my-project/repo && ( GIT_ASKPASS=/bin/echo GIT_SSH=/tmp/my-project/git-ssh.sh /usr/bin/env git archive master app | tar -x --strip-components 1 -f - -C /var/www/my-project/releases/20150506134335 )
INFO [2c26d74f] Finished in 1.176 seconds with exit status 0 (successful).
DEBUG [598e7eb8] Running /usr/bin/env if test ! -d /var/www/my-project/repo; then echo "Directory does not exist '/var/www/my-project/repo'" 1>&2; false; fi as deployer@my-server.com
DEBUG [598e7eb8] Command: if test ! -d /var/www/my-project/repo; then echo "Directory does not exist '/var/www/my-project/repo'" 1>&2; false; fi
DEBUG [598e7eb8] Finished in 0.015 seconds with exit status 0 (successful).
DEBUG [4a1e3dc5] Running /usr/bin/env git rev-list --max-count=1 --abbrev-commit master as deployer@my-server.com
DEBUG [4a1e3dc5] Command: cd /var/www/my-project/repo && ( GIT_ASKPASS=/bin/echo GIT_SSH=/tmp/my-project/git-ssh.sh /usr/bin/env git rev-list --max-count=1 --abbrev-commit master )
DEBUG [4a1e3dc5] 	fbc99fa
DEBUG [4a1e3dc5] Finished in 0.021 seconds with exit status 0 (successful).
DEBUG [927a68db] Running /usr/bin/env if test ! -d /var/www/my-project/releases/20150506134335; then echo "Directory does not exist '/var/www/my-project/releases/20150506134335'" 1>&2; false; fi as deployer@my-server.com
DEBUG [927a68db] Command: if test ! -d /var/www/my-project/releases/20150506134335; then echo "Directory does not exist '/var/www/my-project/releases/20150506134335'" 1>&2; false; fi
DEBUG [927a68db] Finished in 0.980 seconds with exit status 0 (successful).
INFO [b5bfbfbc] Running /usr/bin/env echo "fbc99fa" >> REVISION as deployer@my-server.com
DEBUG [b5bfbfbc] Command: cd /var/www/my-project/releases/20150506134335 && /usr/bin/env echo "fbc99fa" >> REVISION
INFO [b5bfbfbc] Finished in 0.016 seconds with exit status 0 (successful).
INFO [79f901da] Running /usr/bin/env mkdir -p /var/www/my-project/releases/20150506134335 /var/www/my-project/releases/20150506134335/tmp/cache /var/www/my-project/releases/20150506134335/tmp/cache /var/www/my-project/releases/20150506134335/tmp/cache /var/www/my-project/releases/20150506134335/tmp /var/www/my-project/releases/20150506134335/tmp as deployer@my-server.com
DEBUG [79f901da] Command: /usr/bin/env mkdir -p /var/www/my-project/releases/20150506134335 /var/www/my-project/releases/20150506134335/tmp/cache /var/www/my-project/releases/20150506134335/tmp/cache /var/www/my-project/releases/20150506134335/tmp/cache /var/www/my-project/releases/20150506134335/tmp /var/www/my-project/releases/20150506134335/tmp
INFO [79f901da] Finished in 0.015 seconds with exit status 0 (successful).
DEBUG [05583b4d] Running /usr/bin/env [ -L /var/www/my-project/releases/20150506134335/logs ] as deployer@my-server.com
DEBUG [05583b4d] Command: [ -L /var/www/my-project/releases/20150506134335/logs ]
DEBUG [05583b4d] Finished in 0.021 seconds with exit status 1 (failed).
DEBUG [ad22f1dd] Running /usr/bin/env [ -d /var/www/my-project/releases/20150506134335/logs ] as deployer@my-server.com
DEBUG [ad22f1dd] Command: [ -d /var/www/my-project/releases/20150506134335/logs ]
DEBUG [ad22f1dd] Finished in 0.016 seconds with exit status 1 (failed).
INFO [1b1a9946] Running /usr/bin/env ln -s /var/www/my-project/shared/logs /var/www/my-project/releases/20150506134335/logs as deployer@my-server.com
DEBUG [1b1a9946] Command: /usr/bin/env ln -s /var/www/my-project/shared/logs /var/www/my-project/releases/20150506134335/logs
INFO [1b1a9946] Finished in 0.844 seconds with exit status 0 (successful).
DEBUG [0721af0a] Running /usr/bin/env [ -L /var/www/my-project/releases/20150506134335/tmp/cache/models ] as deployer@my-server.com
DEBUG [0721af0a] Command: [ -L /var/www/my-project/releases/20150506134335/tmp/cache/models ]
DEBUG [0721af0a] Finished in 0.019 seconds with exit status 1 (failed).
DEBUG [67fd2a2a] Running /usr/bin/env [ -d /var/www/my-project/releases/20150506134335/tmp/cache/models ] as deployer@my-server.com
DEBUG [67fd2a2a] Command: [ -d /var/www/my-project/releases/20150506134335/tmp/cache/models ]
DEBUG [67fd2a2a] Finished in 0.018 seconds with exit status 1 (failed).
INFO [592441e0] Running /usr/bin/env ln -s /var/www/my-project/shared/tmp/cache/models /var/www/my-project/releases/20150506134335/tmp/cache/models as deployer@my-server.com
DEBUG [592441e0] Command: /usr/bin/env ln -s /var/www/my-project/shared/tmp/cache/models /var/www/my-project/releases/20150506134335/tmp/cache/models
INFO [592441e0] Finished in 0.018 seconds with exit status 0 (successful).
DEBUG [101259fc] Running /usr/bin/env [ -L /var/www/my-project/releases/20150506134335/tmp/cache/persistent ] as deployer@my-server.com
DEBUG [101259fc] Command: [ -L /var/www/my-project/releases/20150506134335/tmp/cache/persistent ]
DEBUG [101259fc] Finished in 0.018 seconds with exit status 1 (failed).
DEBUG [e83e75e3] Running /usr/bin/env [ -d /var/www/my-project/releases/20150506134335/tmp/cache/persistent ] as deployer@my-server.com
DEBUG [e83e75e3] Command: [ -d /var/www/my-project/releases/20150506134335/tmp/cache/persistent ]
DEBUG [e83e75e3] Finished in 0.020 seconds with exit status 1 (failed).
INFO [72653949] Running /usr/bin/env ln -s /var/www/my-project/shared/tmp/cache/persistent /var/www/my-project/releases/20150506134335/tmp/cache/persistent as deployer@my-server.com
DEBUG [72653949] Command: /usr/bin/env ln -s /var/www/my-project/shared/tmp/cache/persistent /var/www/my-project/releases/20150506134335/tmp/cache/persistent
INFO [72653949] Finished in 0.018 seconds with exit status 0 (successful).
DEBUG [b0043afb] Running /usr/bin/env [ -L /var/www/my-project/releases/20150506134335/tmp/cache/views ] as deployer@my-server.com
DEBUG [b0043afb] Command: [ -L /var/www/my-project/releases/20150506134335/tmp/cache/views ]
DEBUG [b0043afb] Finished in 0.018 seconds with exit status 1 (failed).
DEBUG [d5535049] Running /usr/bin/env [ -d /var/www/my-project/releases/20150506134335/tmp/cache/views ] as deployer@my-server.com
DEBUG [d5535049] Command: [ -d /var/www/my-project/releases/20150506134335/tmp/cache/views ]
DEBUG [d5535049] Finished in 0.015 seconds with exit status 1 (failed).
INFO [9df85492] Running /usr/bin/env ln -s /var/www/my-project/shared/tmp/cache/views /var/www/my-project/releases/20150506134335/tmp/cache/views as deployer@my-server.com
DEBUG [9df85492] Command: /usr/bin/env ln -s /var/www/my-project/shared/tmp/cache/views /var/www/my-project/releases/20150506134335/tmp/cache/views
INFO [9df85492] Finished in 0.017 seconds with exit status 0 (successful).
DEBUG [fd776064] Running /usr/bin/env [ -L /var/www/my-project/releases/20150506134335/tmp/sessions ] as deployer@my-server.com
DEBUG [fd776064] Command: [ -L /var/www/my-project/releases/20150506134335/tmp/sessions ]
DEBUG [fd776064] Finished in 0.016 seconds with exit status 1 (failed).
DEBUG [f45e7773] Running /usr/bin/env [ -d /var/www/my-project/releases/20150506134335/tmp/sessions ] as deployer@my-server.com
DEBUG [f45e7773] Command: [ -d /var/www/my-project/releases/20150506134335/tmp/sessions ]
DEBUG [f45e7773] Finished in 0.016 seconds with exit status 1 (failed).
INFO [2cccf11c] Running /usr/bin/env ln -s /var/www/my-project/shared/tmp/sessions /var/www/my-project/releases/20150506134335/tmp/sessions as deployer@my-server.com
DEBUG [2cccf11c] Command: /usr/bin/env ln -s /var/www/my-project/shared/tmp/sessions /var/www/my-project/releases/20150506134335/tmp/sessions
INFO [2cccf11c] Finished in 0.017 seconds with exit status 0 (successful).
DEBUG [4949e322] Running /usr/bin/env [ -L /var/www/my-project/releases/20150506134335/tmp/tests ] as deployer@my-server.com
DEBUG [4949e322] Command: [ -L /var/www/my-project/releases/20150506134335/tmp/tests ]
DEBUG [4949e322] Finished in 0.015 seconds with exit status 1 (failed).
DEBUG [102183f1] Running /usr/bin/env [ -d /var/www/my-project/releases/20150506134335/tmp/tests ] as deployer@my-server.com
DEBUG [102183f1] Command: [ -d /var/www/my-project/releases/20150506134335/tmp/tests ]
DEBUG [102183f1] Finished in 0.014 seconds with exit status 1 (failed).
INFO [06a03326] Running /usr/bin/env ln -s /var/www/my-project/shared/tmp/tests /var/www/my-project/releases/20150506134335/tmp/tests as deployer@my-server.com
DEBUG [06a03326] Command: /usr/bin/env ln -s /var/www/my-project/shared/tmp/tests /var/www/my-project/releases/20150506134335/tmp/tests
INFO [06a03326] Finished in 0.017 seconds with exit status 0 (successful).
INFO [f028e9f1] Running /usr/bin/env cd /var/www/my-project/releases/20150506134335/ && composer update as deployer@my-server.com
DEBUG [f028e9f1] Command: cd /var/www/my-project/releases/20150506134335/ && composer update
DEBUG [f028e9f1] 	Loading composer repositories with package information
DEBUG [f028e9f1] 	Updating dependencies (including require-dev)
DEBUG [f028e9f1] 	  - Removing cakephp/cakephp (2.6.3)
DEBUG [f028e9f1] 	  - Installing cakephp/cakephp (2.6.4)
DEBUG [f028e9f1] 	    Downloading: Connecting...
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 0%
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 5%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 10%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 15%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 20%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 25%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 30%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 35%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 40%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 45%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 50%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 55%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 60%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 65%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 70%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 75%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 80%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 85%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 90%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 95%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 100%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 100%
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	  - Removing phpunit/php-file-iterator (1.3.4)
DEBUG [f028e9f1] 	  - Installing phpunit/php-file-iterator (1.4.0)
DEBUG [f028e9f1] 	    Downloading: Connecting...
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 0%
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 100%
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	  - Removing symfony/yaml (v2.6.5)
DEBUG [f028e9f1] 	  - Installing symfony/yaml (v2.6.6)
DEBUG [f028e9f1] 	    Downloading: Connecting...
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 0%
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 5%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 10%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 15%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 65%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 70%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 75%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 80%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 100%
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	  - Removing guzzlehttp/ringphp (1.0.6)
DEBUG [f028e9f1] 	  - Installing guzzlehttp/ringphp (1.0.7)
DEBUG [f028e9f1] 	    Downloading: Connecting...
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 0%
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 15%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 25%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 40%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 50%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 55%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 65%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 80%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 90%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 95%
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	    Downloading: 100%
DEBUG [f028e9f1]
DEBUG [f028e9f1]
DEBUG [f028e9f1] 	Writing lock file
DEBUG [f028e9f1] 	Generating autoload files
INFO [f028e9f1] Finished in 21.330 seconds with exit status 0 (successful).
DEBUG [15975d75] Running /usr/bin/env if test ! -d /var/www/my-project/releases/20150506134335; then echo "Directory does not exist '/var/www/my-project/releases/20150506134335'" 1>&2; false; fi as deployer@my-server.com
DEBUG [15975d75] Command: if test ! -d /var/www/my-project/releases/20150506134335; then echo "Directory does not exist '/var/www/my-project/releases/20150506134335'" 1>&2; false; fi
DEBUG [15975d75] Finished in 0.015 seconds with exit status 0 (successful).
INFO [6b59d736] Running /usr/bin/env composer install --no-dev --prefer-dist --no-interaction --quiet --optimize-autoloader as deployer@my-server.com
DEBUG [6b59d736] Command: cd /var/www/my-project/releases/20150506134335 && /usr/bin/env composer install --no-dev --prefer-dist --no-interaction --quiet --optimize-autoloader
INFO [6b59d736] Finished in 0.212 seconds with exit status 0 (successful).
INFO [e565a2f9] Running /usr/bin/env ln -s /var/www/my-project/releases/20150506134335 /var/www/my-project/releases/current as deployer@my-server.com
DEBUG [e565a2f9] Command: /usr/bin/env ln -s /var/www/my-project/releases/20150506134335 /var/www/my-project/releases/current
INFO [e565a2f9] Finished in 0.016 seconds with exit status 0 (successful).
INFO [80a0ddf0] Running /usr/bin/env mv /var/www/my-project/releases/current /var/www/my-project as deployer@my-server.com
DEBUG [80a0ddf0] Command: /usr/bin/env mv /var/www/my-project/releases/current /var/www/my-project
INFO [80a0ddf0] Finished in 0.018 seconds with exit status 0 (successful).
DEBUG [1d600961] Running /usr/bin/env ls -xtr /var/www/my-project/releases as deployer@my-server.com
DEBUG [1d600961] Command: /usr/bin/env ls -xtr /var/www/my-project/releases
DEBUG [1d600961] 	20150506043519	20150506092943	20150506093923	20150506102952	20150506103719
DEBUG [1d600961] 	20150506122119	20150506130326	20150506130947	20150506134335
DEBUG [1d600961] Finished in 0.018 seconds with exit status 0 (successful).
INFO Keeping 5 of 9 deployed releases on my-server.com
INFO [64fdd5ed] Running /usr/bin/env rm -rf /var/www/my-project/releases/20150506043519 /var/www/my-project/releases/20150506092943 /var/www/my-project/releases/20150506093923 /var/www/my-project/releases/20150506102952 as deployer@my-server.com
DEBUG [64fdd5ed] Command: /usr/bin/env rm -rf /var/www/my-project/releases/20150506043519 /var/www/my-project/releases/20150506092943 /var/www/my-project/releases/20150506093923 /var/www/my-project/releases/20150506102952
INFO [64fdd5ed] Finished in 0.308 seconds with exit status 0 (successful).
DEBUG [300aa3cb] Running /usr/bin/env if test ! -d /var/www/my-project/releases; then echo "Directory does not exist '/var/www/my-project/releases'" 1>&2; false; fi as deployer@my-server.com
DEBUG [300aa3cb] Command: if test ! -d /var/www/my-project/releases; then echo "Directory does not exist '/var/www/my-project/releases'" 1>&2; false; fi
DEBUG [300aa3cb] Finished in 0.015 seconds with exit status 0 (successful).
INFO [66a165f2] Running /usr/bin/env echo "Branch master (at fbc99fa) deployed as release 20150506134335 by vagrant" >> /var/www/my-project/revisions.log as deployer@my-server.com
DEBUG [66a165f2] Command: echo "Branch master (at fbc99fa) deployed as release 20150506134335 by vagrant" >> /var/www/my-project/revisions.log
INFO [66a165f2] Finished in 0.017 seconds with exit status 0 (successful).
十分冗长的部署输出

从浏览器访问时,由于前面的准备工作不够完善,还有若干问题,下面一一解决。

第一个错误是这样的:

Warning: _cake_core_ cache was unable to write 'cake_dev_en-us' to File cache in /var/www/my-project/releases/20150506134335/Vendor/cakephp/cakephp/lib/Cake/Cache/Cache.php on line 328

Warning: /var/www/my-project/releases/20150506134335/tmp/cache/persistent/ is not writable in /var/www/my-project/releases/20150506134335/Vendor/cakephp/cakephp/lib/Cake/Cache/Engine/FileEngine.php on line 385

Fatal error: Uncaught exception 'CacheException' with message 'Cache engine "_cake_core_" is not properly configured. Ensure required extensions are installed, and credentials/permissions are correct' in /var/www/my-project/releases/20150506134335/Vendor/cakephp/cakephp/lib/Cake/Cache/Cache.php:186 Stack trace: #0 /var/www/my-project/releases/20150506134335/Vendor/cakephp/cakephp/lib/Cake/Cache/Cache.php(151): Cache::_buildEngine('_cake_core_') #1 /var/www/my-project/releases/20150506134335/Config/core.php(388): Cache::config('_cake_core_', Array) #2 /var/www/my-project/releases/20150506134335/Vendor/cakephp/cakephp/lib/Cake/Core/Configure.php(72): include('/var/www/privat...') #3 /var/www/my-project/releases/20150506134335/Vendor/cakephp/cakephp/lib/Cake/bootstrap.php(175): Configure::bootstrap(true) #4 /var/www/my-project/releases/20150506134335/webroot/index.php(104): include('/var/www/privat...') #5 {main} thrown in /var/www/my-project/releases/20150506134335/Vendor/cakephp/cakephp/lib/Cake/Cache/Cache.php on line 186

这是因为apache运行的用户www-data对缓存的目录没有写入权限。根据Capistrano的Structure文档,服务器上部署的目录结构是这样的:

├── current -> /var/www/my-project/releases/20150506134335/
├── releases
│   ├── 20150506103719
│   ├── 20150506122119
│   ├── 20150506130326
│   ├── 20150506130947
│   └── 20150506134335
├── repo
│   └── 
├── revisions.log
└── shared
    └── <linked_files and linked_dirs>

linked_dirs目录就是shared目录下的缓存和日志所在的目录tmp、logs等等。要把这些目录给予用户www-data完全的权限,我采用的做法是把这些目录的组设置为www-data,再给予该目录的组写入权限,则www-data就有了写入的权限了:

deployer@my-server.com $ cd /var/www/my-project
deployer@my-server.com $ sudo chown :www-data releases
deployer@my-server.com $ sudo chmod g+w releases
deployer@my-server.com $ cd shared deployer@my-server.com $ sudo
chown :www-data *
deployer@my-server.com $ sudo chmod g+w *

 写入权限的问题解决之后,遇到的问题是:

Missing Plugin

Error: The application is trying to load a file from the DebugKit plugin

Error: Make sure your plugin DebugKit is in the 20150507044736/Plugin directory and was loaded

<?php
CakePlugin::load('DebugKit');

Loading all plugins: If you wish to load all plugins at once, use the following line in your 20150507044736/Config/bootstrap.php file

CakePlugin::loadAll();

Notice: If you want to customize this error message, create 20150507044736/View/Errors/missing_plugin.ctp

这是因为生产环境的部署中,Composer没有安装require-dev的包,所以就没有安装CakePHP的DebugKit插件。修改代码,在生产环境中不加载DebugKit:

switch (env('HTTP_HOST')) {
    case '127.0.0.1':             // local
        CakePlugin::load('DebugKit');
        break;

    case 'www.my-project.com':    // production
    default:
        break;
}

这样再次部署,就一切正常了。

当推送了改动到GitLab的代码库之后,可以看到,构建和部署自动启动,并正确执行,如下图所示:

Commits correctly built

详细构建日志如下图所示:

Detailed build log

Detailed build log (2)

6. 小结

本文虽然是使用了把CakePHP应用程序部署到Ubuntu系统上的Apache web服务器为例,但是自动化部署的方法其实是适用多种语言和平台的,对此Capistrano有各种插件,可以扩展其功能,或者针对某种语言和框架进行定制。

另外,文中涉及的情况还是比较简单的,我没有谈到如何部署数据库的改动,以及其它服务器(应用服务器、缓存,等等)的部署,有兴趣的读者可以进一步深入研究。

总的来说,我只是了解了一些工具(GitLab CI和Capistrano)的简单使用,做了个介绍,还有更多的场景和深入的功能有待探索,希望能起到抛砖引玉的作用,有什么反馈和建议,欢迎大家在评论中留言讨论,互相切磋,共同提高。

A. 参考资料

  1. Installing GitLab Runner
    https://gitlab.com/gitlab-org/omnibus-gitlab-runner/blob/master/doc/install/README.md
  2. Unofficial GitLab CI Runner
    https://about.gitlab.com/2015/04/17/unofficial-gitlab-ci-runner/
  3. Capistrano Documentation
    http://capistranorb.com/
  4. Capistrano source code
    https://github.com/capistrano/capistrano
  5. Expert PHP Deployments
    https://leftnode.org/posts/expert-php-deployments.html
  6. Deploying a CakePHP site with Capistrano
    http://mark-story.com/posts/view/deploying-a-cakephp-site-with-capistrano
  7. How To Use Capistrano to Automate Deployments: Getting Started
    https://www.digitalocean.com/community/tutorials/how-to-use-capistrano-to-automate-deployments-getting-started
  8. Capistrano 3 Tutorial
    http://www.talkingquickly.co.uk/2014/01/deploying-rails-apps-to-a-vps-with-capistrano-v3/
  9. Use Capistrano 3 to Deploy Rails Applications - a Step-by-Step Tutorial
    http://www.gotealeaf.com/blog/deploy-rails-apps-with-capistrano
  10. PHP and Capistrano 3: Notes to Self
    http://jeremykendall.net/2013/11/24/php-and-capistrano-3-notes-to-self/
  11. Capistrano 3 Tutorial Series Part 1 - Secure SSH key based website deployment from Subversion using Capistrano 3
    http://www.zodiacmedia.co.uk/blog/capistrano-3-tutorial-series-part-1
  12. jadb/capcake - Deploy CakePHP applications with Capistrano v3.*
    https://github.com/jadb/capcake
  13. Sudoers - Community Help Wiki
    https://help.ubuntu.com/community/Sudoers
  14. What's the difference between /sbin/nologin and /bin/false
    http://unix.stackexchange.com/questions/10852/whats-the-difference-between-sbin-nologin-and-bin-false
  15. useradd(8) - Linux man page
    http://linux.die.net/man/8/useradd
  16. Start ssh-agent on login
    http://stackoverflow.com/questions/18880024/start-ssh-agent-on-login
  17. Using ssh-agent with ssh
    http://mah.everybody.org/docs/ssh
  18. SSH Agent Forwarding considered harmful
    http://heipei.github.io/2015/02/26/SSH-Agent-Forwarding-considered-harmful/
  19. OpenSSH Change a Passphrase With ssh-keygen command
    http://www.cyberciti.biz/faq/howto-ssh-changing-passphrase/
  20. Capistrano deploy composer error
    http://stackoverflow.com/questions/26093260/capistrano-deploy-composer-error
  21. PHP 手册 > 函数参考 > 加密扩展 > Mcrypt > 安装/配置
    http://php.net/manual/zh/mcrypt.installation.php
  22. LC / Locales issues on Ubuntu 14.04 server
    http://ubuntuforums.org/showthread.php?t=2268614
  23. Mcrypt extension is missing in 14.04 server for mysql
    http://askubuntu.com/questions/460837/mcrypt-extension-is-missing-in-14-04-server-for-mysql
  24. Unofficial runner becomes official one
    https://about.gitlab.com/2015/05/03/unofficial-runner-becomes-official/
  25. Issue #151 - wrong runner used - GitLab.org / GitLab CI |  GitLab
    https://gitlab.com/gitlab-org/gitlab-ci/issues/151
 
posted @ 2015-05-10 12:46  Black Puppy  阅读(2165)  评论(0编辑  收藏  举报