使用 Capistrano 进行自动化部署(2)

之前的一篇文章是为了解决问题而写的,很多东西都没有介绍清楚,这一篇文章就是完整介绍一下 Capistrano,主要的参考来源是 Modern PHP 这本书。

Capistrano 是用于自动部署应用的软件,能让部署变得简单、可预知结果和可逆。Capistrano 运行在本地设备中,通过 SSH 与远程服务器通信。Capistrano 本来是为了部署 Ruby 应用而开发的,不过对任何编程语言开发的应用都有用,包括 PHP。

Capistrano 的工作方式

Capistrano 安装在本地设备中。部署 PHP 应用时,Capistrano 会在本地设备中执行 SSH 命令,与远程服务器通信。Capistrano 会在远程服务器中保存之前部署的应用,而且每次部署的版本放在各自的目录中。Capistrano 会维护五个或更多之前部署的应用,以防需要回滚到早期版本。Capistrano 还会创建一个 current/ 目录,通过符号链接指向当前部署的应用所在的目录。在生产服务器中,Capistrano 管理的目录结构可能像下图这样:

home/
    deploy/
        apps/
            my_app/
                current/
                releases/
                    release1/
                    release2/
                    release3/
                    release4/

把新版应用部署到生产环境时,Capistrano 首先从应用的 Git 仓库获取最新版代码,然后把应用的代码放到 releases/ 目录中的一个新子目录中,最后把 current/ 目录的符号链接指向这个新目录。让 Capistrano 回滚到之前的版本时,Capistrno 会把 current/ 目录的符号链接指向 releases/ 目录中存档之前版本的目录。Capistrano 是一种优雅且简单的部署方案,能让 PHP 应用的部署过程变得简单、可预知和可逆。

安装

Capistrano 应该安装在本地设备中,别在远程服务器中安装。安装时还需要 ruby 和 gem。OS X 系统已经有了。Ubuntu 用户可以直接用下面的命令安装:

$ sudo apt-get install ruby
$ sudo apt-get install gem

安装好之后,执行下面命令安装 Capistrano:

$ gem install capistrano

配置

安装 Capistrano 之后,为了使用 Capistrano,必须初始化项目。打开终端,进入项目的根目录,执行下面的命令:

$ cap install

这个命令会创建 Capfile 文件,config/ 目录和 lib/ 目录。现在,项目目录结构应该如下所示:

Capfile
config/
    deploy/
        production.rb
        staging.rb
    deploy.rb
lib/
    capistrano/
        tasks/

Capfile 是 Capistrano 的中央配置文件,会聚合 config/ 目录中的配置文件。 config/ 目录中存放的是各个远程服务器环境(例如,测试环境、过渡环境或生产环境)的配置文件。

默认情况下,Capistrano 假设你为应用搭建了多个环境。例如,可能有单独的过渡环境和生产环境。Capistrano 在 config/deploy/ 目录中为每个环境都提供了单独的配置文件。Capistrano 还提供了 config/deploy.rb 配置文件,这个文件用于保存所有环境通用的设置。

在每个环境中,Capistrano 会区分服务器的角色。例如,生产环境可能有前置 Web 服务器(web角色),应用服务器(app角色)和数据库服务器(db角色)。只有最大规模的应用才有必要使用这种架构,小型 PHP 应用一般在同一台设备中运行 Web 服务器(nginx)、应用服务器(PHP-FPM)和数据库服务器(MariaDB)。

这篇文章的例子中,我使用的是 web 角色,和生产环境的配置。

config/deploy.rb 文件

这个配置文件包含所有环境通用的配置。打开这个文件,然后更新下列设置:

  • :application 这是 PHP 应用的名称。只能包含字母、数字和下划线。
  • :repo_url 这是Git仓库的URL。这个URL必须指向一个Git仓库,而且远程服务器必须能访问这个仓库。
  • :reploy_to 这是远程服务器中一个目录的绝对路径,我们不熟的PHP应用就存放在这个目录中,此时,该路径为:/home/deploy/apps/my_app
  • :keep_releases 保留多少个旧版,以便于应用的版本回滚。

config/deploy/production.rb 文件

这个文件只包含生产环境的设置。这个文件用于定义生产环境的角色,列出属于各个角色的服务器。我们只使用 web 角色,而且只有一个服务器属于这个角色。所以,这是,把该文件全部内容替换为下列代码即可:

role :web, %w(deploy@123.123.123.123)

认证

使用 Capistrano 部署应用之前,我们必须在本地电脑和远程服务器之间,以及远程服务器和 Git 仓库之间建立认证。在之前的文章中 设置 SSH Key 登录服务器和 Git 服务器 已经讨论了如何使用 SSH 密钥登录服务器和 Git 服务,使用之前讨论的方法在每台远程服务器中生成 SSH 公钥和私钥。Git 仓库应该能访问每台远程服务器的公钥。Github 允许在用户账户中添加多个 SSH 公钥。总之,我们必须不使用密码就能把 Git 仓库克隆到远程服务器。

准备远程服务器

就快能部署环境了,但在此之前,还需要准备远程服务器。我们要通过 SSH 登录远程服务器,创建一个目录,存放部署的 PHP 应用。deploy 用户必须有这个目录的读写权限。我喜欢在 deploy 用户的主目录中创建这个目录:

/home
    /deploy
        apps/
            my_app/

虚拟主机

Capistrano 会创建符号链接,把 current/ 目录指向存放当前应用版本的目录。因此,我们要更新 Web 服务器的虚拟主机文档根目录,指向 Capistrano 的 current/ 目录。根据上述文件系统的结构图,要把虚拟主机的文档根目录改为 /home/deploy.apps.my_app/current/public/。这么设置的前提是,假设 PHP 应用中有个 public/ 目录,把它当做文档根目录。然后重启 Web 服务器,加载修改后的虚拟主机配置。

依赖的软件

远程服务器不需要 Capistrano,但是需要 Git。而且还需要运行 PHP 应用所需要的全部软件。

Capistrano 的钩子

Capistrano 允许在部署应用过程中的特定时刻执行我们指定的命令。很多 PHP 开发者都使用 Composer 管理应用的依赖。每次使用 Capistrano 部署应用时,我们可以使用 Capistrano 的钩子安装 Composer 依赖,打开 config/deploy.rb 文件,添加下面的 ruby 代码:

namespace :deploy do
    desc "update composer package"
    after :updated, :build do
      on roles(:web) do
          within release_path do
              execute :composer, "install --no-dev --quiet"
              execute :cp, "-rfv  ../../shared/configs ./application/"
          end
      end
    end
  end

一些不便于放在 Git 中的配置文件此时可以通过在钩子中执行 ln -s source dest 命令,建立符号链接,引用外部的配置文件。

部署应用

一切准备就绪以后,切换到本地项目根目录,执行下列命令部署你的应用!

$ cap production deploy

回滚应用

要回滚到上个版本,只需执行下列命令:

$ cap production deploy:rollback

FAQs

fatal: Not a valid object name: ‘dev’

原因:set branch ‘dev’,中 dev 分支并不存在。

rm stderr: rm: cannot remove ‘xxx’ Permission denied

rm stderr: rm: cannot remove ‘/home/deploy/apps/<project-name>/releases/20180930034435/storage/framework/cache/data/7e/e2/7ee26eb04819797da018521ae355096eb5af5eb1’: Permission denied

原因:这是一个 Laravel 项目,storage 目录下面是 Laravel 的运行过程中产生的日志文件和缓存文件,权限属于 www-data,而当前操作 Capistrano 发布新版的用户是 deploy,发布新版时,就要删除多余的旧版项目,而在删除时遇到这种没有权限删除的文件和目录,就会报这个错误。

解决:将 storage 链接到项目外的一个固定目录,比如 shared/storage,然后,给予 deploy chmod 的权限,每次在发布前,设置一个自动执行的操作:chmod 777 storage/。即可。

参考: https://stackoverflow.com/questions/35724285/capistrano-remove-cache-permission-denied