攻略 - Capistrano 部署 Laravel 项目

Capistrano

file
Capistrano 部署的原理和 Deployer 是一样的,@overtrue 大神写了一篇关于 delopyer 攻略,里面讲的操作原理,服务器端用户配置,允许访问 git 仓库和免密码登录的基本知识可以先了解下。

这篇文章主要详细介绍下 capistrano 的具体用法:

结构

Capistrano 部署成功后的代码文件结构是像这样的:

├── current -> /var/www/app_name/releases/20180120114500/
├── releases
│   |----- 20180080072500
│   |----- 20180090083000
│   |----- 20180100093500
│   |----- 20180110104000
│   |----- 20180120114500
├── repo
│   |----- <VCS related data>
├── revisions.log
└── shared
    |----- <linked_files and linked_dirs>

current, releases,shared 的含义和 deployer 的是一样的,版本是按时间排序的,repo 里包含了 VCS 的信息,比如 git 或者 svn,revisions.log 日志记载了每一次部署和 rollback 的详细信息。

流程

deploy:starting    - 开始部署 确认一切就绪
deploy:started     - started hook (自定义任务)
deploy:updating    - 更新服务器
deploy:updated     - updated hook
deploy:publishing  - 发布新的部署
deploy:published   - published hook
deploy:finishing   - 结束部署
deploy:finished    - finished hook

安装

推荐使用 RVM 去安装 ruby,最大的好处在于你可以安装不同的版本,而且能够在版本中随意切换。

\curl -sSL https://get.rvm.io | bash -s stable(安装 rvm)

安装完后,可以运行 source ~/.rvm/scripts/rvm 或者重开 shell window 激活 rvm。

rvm list known(查看版本)

rvm install 2.5(安装 ruby 2.5)

gem install capistrano(安装 capistrano,gem 类似于 composer)

配置

我一般会在项目的根目录下新建一个 deployment 文件夹,然后运行 cap install,这个命令会创建以下的配置文件:

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

首先,看一下 Capfile,默认的配置即可,不需做太大修改。因为本文例子中 tasks 会定义在 deploy.rb 中,所以 lib 文件夹用不到,可以忽略。

# 加载 DSL 和设置 stages
require "capistrano/setup"

# 加载默认的部署任务
require "capistrano/deploy"

# 加载 SCM git 插件:
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git

# 加载自定义任务 `lib/capistrano/tasks`
# Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }

其次,deploy.rb 中的基本配置如下,每个配置我做了简单的注释:

# 设置 capistrano 版本
lock "~> 3.11.0"

# 设置项目名称
set :application, 'app_name'
# 设置服务器上的部署路径
set :deploy_to, '/var/www/app_name'
# 设置 git 仓库的 url
set :repo_url, 'git@github.com:username/app_name.git'
# 设置部署版本保持的个数
set :keep_releases, 5
# 设置日志 level
set :log_level, :debug
# 设置样式,美化 Capistrano 在命令行的输出
set :format, :airbrussh
# 设置 ssh 使用的 key,免密码登录
set :ssh_options, {
    keys: %w(~/.ssh/id_rsa)
}

如果你需要在服务器上编译资源,可以设置环境变量,比如加载 nodejs 的路径:

set :default_env, {
    path: "/home/deployer/.nvm/versions/node/v10.9.0/bin:$PATH"
}

顺便提一下,无论在 MAC 还是服务器上,可以使用 NVM 安装 nodejs,这个和 ruby 的 RVM 是一样的,让你安装不同的 nodejs 和 npm 的版本,而且很容易切换。

下面就是比较重要的 shared 的文件和文件夹,用来存储版本之间共享的文件:

set :linked_files, %w{.env}

set :linked_dirs, %w{
    vendor
    storage
    storage/app/public
    storage/framework/cache
    storage/framework/sessions
    storage/framework/testing
    storage/framework/views
    storage/logs
}

然后,定义一些常用的任务,比如:

namespace :app do
    task :up do
        on roles(:app), in: :sequence, wait: 5 do
            within release_path do
                execute :php, :artisan, "up"
            end
        end
    end

    task :down do
        on roles(:app), in: :sequence, wait: 5 do
            within release_path do
                execute :php, :artisan, "down"
            end
        end
    end

    ......
end

定义这些任务后,就可以本地运行 php artisan 命令,例如 cap staging app:down 就可以把服务器上的网站设置为维护模式。再以缓存为例子,在 namespace cache 下可以定义以下任务:

namespace :cache do
    task :clear do
        on roles(:app), in: :sequence, wait: 5 do
            within release_path do
                execute :php, :artisan, "cache:clear"
                execute :php, :artisan, "view:clear"
                execute :php, :artisan, "route:clear"
                execute :php, :artisan, "config:clear"
            end
        end
    end

    task :route do
        on roles(:app), in: :sequence, wait: 5 do
            within release_path do
                execute :php, :artisan, "route:cache"
            end
        end
    end

    task :config do
        on roles(:app), in: :sequence, wait: 5 do
            within release_path do
                execute :php, :artisan, "config:cache"
            end
        end
    end

    task :refresh do
        invoke('cache:clear')
        invoke('cache:route')
        invoke('cache:config')
    end
end

所有的 php artisan 命令你都可以归类写成 task,放在 lib/capistrano/tasks 下,我们就简单放在 deploy.rb 里了。

接着 deploy 的配置:

namespace :deploy do
    desc "Run Composer Install"
    task :composer_install do
        on roles(:app), in: :sequence, wait: 5 do
            within release_path do
                execute :composer, "install --prefer-dist --no-dev --optimize-autoloader"
            end
        end
    end

    desc "Run Migration"
    task :migrate do
        on roles(:app), in: :sequence, wait: 5 do
            within release_path do
                execute :php, "artisan migrate --no-interaction --force"
            end
        end
    end

    desc "Run NPM Scripts"
    task :npm_scripts do
        on roles(:app), in: :sequence, wait: 5 do
            within release_path do
                execute :npm, "install"
                execute :npm, "run production"
            end
        end
    end

    desc "Restart PHP FPM"
    task :restart_php_fpm do
        on roles(:app), in: :sequence, wait: 5 do
            within release_path do
                execute :sudo, :service, "php7.2-fpm restart"
            end
        end
    end

    after :updated, "deploy:composer_install"
    after :updated, "deploy:migrate"
    after :updated, "deploy:npm_scripts"
    after :published, "deploy:restart_php_fpm"
end

这里需要注意的是,部署不需要重启 apache 或者 nginx,不过需要重启 php-fpm,这就需要给服务器用户 deployer 重启 php-fpm 的权限,安全起见,请仅给予重启 php-fpm 的权限
sudo visudo
deployer ALL=(ALL:ALL) NOPASSWD:/usr/sbin/service php7.2-fpm restart

最后,deploy/staging.rb 中的配置如下:

set :stage, :staging

set :branch, 'develop'

server '{server_ip_address}', user: 'deployer', roles: %w{app}

set :app_env, 'staging'

这样每次部署到测试服务器时,只需要本地运行 cap staging deploy 就可以,production 的配置类似。部署是需要一段时间的,不过只有最终成功的时候,服务器上才会更新 symlink,指向最新的版本,所以基本上是没有 downtime 的。

本作品采用《CC 协议》,转载必须注明作者和本文链接
jltxwesley
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!