- DevOps
- CI/CD
- CLI
- 开发工具
- 运维
【免费下载链接】deployer
The PHP deployment tool with support for popular frameworks out of the box
本篇技术指南基于 Deployer 开源仓库中的 Symfony 部署配方文档 及其源码 recipe/symfony.php,系统讲解如何通过require 'recipe/symfony.php'将 Symfony 应用部署到服务器。你将掌握该配方的全部配置参数(shared_dirs、writable_dirs、bin/console、migrations_config等)、核心任务(deploy、database:migrate、deploy:cache:clear、deploy:dump-env)以及它们在源码层面的真实调用链,从而能独立编写、定制并排查自己的deploy.php。
一、Symfony 配方是什么
Deployer 是一个用 PHP 编写的免费开源部署工具,帮助你把 Symfony 应用发布到远程服务器。它的设计目标是“开箱即用”:只要在部署脚本里引入 Symfony 配方,就能立刻获得一套针对 Symfony 项目结构优化过的部署流程。
配方(recipe)本质上是一个可复用的 PHP 文件,通过require引入后,它会自动注册任务(task)和配置项(configuration):
// deploy.php require 'recipe/symfony.php';从源码看,recipe/symfony.php的第一行就加载了common.php(见 recipe/symfony.php),同时通过add('recipes', ['symfony'])把自己注册进配方列表。因此Symfony 配方是基于 common 配方的扩展,common 提供的基础能力(详见 docs/recipe/common.md)在 Symfony 配方中全部可用。
三大核心特性
- Provisioning(服务器预配置):在部署之前先把服务器环境准备好(如安装 PHP、创建用户、配置网站),相关配方见 docs/recipe/provision.md。
- Zero downtime deployment(零停机部署):代码先发布到新 release 目录,全部就绪后再一次性切换符号链接,整个过程旧版本持续对外服务。
- Rollbacks(回滚):某个版本出问题时,可以一键回滚到上一个可用版本。
此外,Deployer 语法简单直观、易于上手;通过并行连接加速部署;全程基于 SSH 连接服务器保证安全;并支持所有主流 PHP 框架(Laravel、Symfony、CakePHP、Magento 等,对应配方见 docs/recipe 目录)。更多基础概念可参考 docs/getting-started.md。
二、deploy 任务的整体流水线
Symfony 配方的核心是deploy任务(源码见 recipe/symfony.php),它是一个组任务(group task),按顺序执行四个子任务:
task('deploy', [ 'deploy:prepare', 'deploy:vendors', 'deploy:cache:clear', 'deploy:publish', ]);与 common 配方的通用deploy(只包含deploy:prepare和deploy:publish,见 recipe/common.php)相比,Symfony 配方在中间插入了deploy:vendors(安装依赖)和deploy:cache:clear(清缓存),完全贴合 Symfony 应用的发布节奏。
展开后,完整的调用树如下:
deploy ├─ deploy:prepare # 准备新 release │ ├─ deploy:info # 显示部署信息 │ ├─ deploy:setup # 准备主机目录结构 │ ├─ deploy:lock # 加部署锁(防止并发部署) │ ├─ deploy:release # 创建新 release 目录 │ ├─ deploy:update_code # 拉取/更新代码 │ ├─ deploy:env # 配置 .env 文件 │ ├─ deploy:shared # 为共享文件/目录创建软链 │ └─ deploy:writable # 设置可写目录权限 ├─ deploy:vendors # 安装 Composer 依赖 ├─ deploy:cache:clear # 清空并预热缓存 └─ deploy:publish # 发布 release ├─ deploy:symlink # 切换 current 软链到新 release ├─ deploy:unlock # 解除部署锁 ├─ deploy:cleanup # 清理旧 release └─ deploy:success # 输出成功信息其中deploy:prepare与deploy:publish的定义在 recipe/common.php,子任务的逐个说明分散在 docs/recipe/deploy 目录的对应文档中。理解这条链路是排查部署问题的关键:例如deploy:release(源码见 recipe/deploy/release.php)负责创建releases/N目录并建立release软链,而release_or_current_path(recipe/deploy/release.php)在部署期间指向release、平时回落到current,这正是后面所有 Symfony 命令都能“在正确目录里执行”的机制基础。
三、配置项详解(Configuration)
Symfony 配方通过set()定义了若干配置项,覆盖了部署 Symfony 应用时需要定制的一切:目录结构、可写权限、控制台命令路径等。下面逐项说明其默认值与作用。
3.1 symfony_version — 自动探测 Symfony 版本
set('symfony_version', function () { $result = run('{{bin/console}} --version'); preg_match_all('/(\d+\.?)+/', $result, $matches); return $matches[0][0] ?? 5.0; });该配置在访问时才自动计算(autogenerated):它执行{{bin/console}} --version,从输出中用正则(\d+\.?)+提取第一个版本号;若提取失败则回退到5.0。它是后续按版本差异化处理(如不同 Symfony 版本采用不同的缓存预热参数)的基础,一般无需手动覆盖,但如果远程环境特殊(比如bin/console输出格式异常),也可以手动set('symfony_version', '6.4')。
3.2 shared_dirs — 跨 release 共享的目录
set('shared_dirs', [ 'var/log', ]);它覆盖(override)了 recipe/deploy/shared.php 中同名配置(默认空数组)。含义是:var/log目录在每次发布时不做复制,而是软链到deploy_path/shared下统一维护,这样日志在版本切换、回滚后依然连续不丢失。如果你还需要共享其他目录(如上传文件目录),在deploy.php中追加即可:
set('shared_dirs', [ 'var/log', 'var/uploads', ]);共享机制的细节见 docs/recipe/deploy/shared.md:每个 release 里的共享目录/文件都会是指向deploy_path/shared下实体的软链。
3.3 shared_files — 跨 release 共享的文件
set('shared_files', [ '.env.local', ]);同样覆盖 recipe/deploy/shared.php 的同名配置。.env.local保存着每个环境的敏感配置(数据库密码、密钥等),绝不应随代码发布而变动,因此必须放在共享区——首次部署时 Deployer 会基于.env.example(dotenv_example配置,见 docs/recipe/deploy/env.md)初始化,后续发布则始终复用同一份。需要共享其他文件(比如自签名证书、业务配置文件)时按同样方式追加即可。
3.4 writable_dirs — 需要 Web 服务器可写的目录
set('writable_dirs', [ 'var', 'var/cache', 'var/log', 'var/sessions', ]);它覆盖 recipe/deploy/writable.php 的同名配置(默认空数组)。Symfony 的var/下缓存、日志、会话目录必须让运行 PHP-FPM 的 http 用户可写,否则应用会直接报权限错误。具体以哪种方式设置权限,由writable_mode决定,可选值包括chown、chgrp、chmod、acl、sticky、skip,默认'acl';相关配套配置还有http_user(自动探测)、writable_use_sudo(默认false)、writable_recursive(默认false)、writable_chmod_mode(默认'0755')等,详见 docs/recipe/deploy/writable.md。在 CentOS/RedHat 系服务器上若 ACL 不可用,可改成:
set('writable_mode', 'chmod');3.5 log_files — 应用日志文件匹配模式
set('log_files', 'var/log/*.log');该配置被 common 配方的logs:app任务使用(见 recipe/common.php):执行dep logs:app时会在current_path下对var/log/*.log执行tail -f,实时跟踪应用日志。Symfony 的标准日志路径恰好是var/log/*.log,因此该默认值开箱即用。
3.6 migrations_config — 迁移配置文件路径
set('migrations_config', '');默认为空字符串。它是database:migrate任务的开关:只有显式设置了迁移配置文件(如config/packages/doctrine_migrations.yaml对应的 XML/JSON 配置)时,迁移命令才会附带--configuration参数(源码见 recipe/symfony.php):
if (get('migrations_config') !== '') { $options = "$options --configuration={{release_or_current_path}}/{{migrations_config}}"; }3.7 doctrine_schema_validate_config — Schema 校验配置
set('doctrine_schema_validate_config', '');默认为空字符串。它直接作为doctrine:schema:validate命令的附加参数使用(recipe/symfony.php)。当你的 Doctrine 映射需要额外配置(如指定--em=default或多个实体管理器)时在此传入。
3.8 bin/console — Symfony 控制台命令路径
set('bin/console', '{{bin/php}} {{release_or_current_path}}/bin/console');定义了远程执行 Symfony 命令时使用的完整命令前缀。其中:
{{bin/php}}来自 common 配方(recipe/common.php),默认用which('php')探测,若主机设置了php_version则使用/usr/bin/php{{php_version}};{{release_or_current_path}}在部署期间指向新 release、平时指向 current(recipe/deploy/release.php),保证命令始终在正确目录执行。
如需指定 PHP 版本,可在deploy.php中覆盖:
host('prod') ->set('php_version', '8.2'); // 使 bin/php 解析为 /usr/bin/php8.23.9 console_options — console 命令通用选项
set('console_options', function () { return '--no-interaction'; });同样在访问时自动生成,默认给所有bin/console调用附加--no-interaction,避免部署过程中远程命令因等待交互输入而挂起。CI/CD 环境下尤其重要。
四、任务详解(Tasks)
Symfony 配方定义了五个任务:三个是 Symfony 专属业务任务,两个是扩展/重定义的部署任务。
4.1 database:migrate — 执行数据库迁移
desc('Migrates database'); task('database:migrate', function () { $options = '--allow-no-migration'; if (get('migrations_config') !== '') { $options = "$options --configuration={{release_or_current_path}}/{{migrations_config}}"; } run("cd {{release_or_current_path}} && {{bin/console}} doctrine:migrations:migrate $options {{console_options}}"); });- 默认携带
--allow-no-migration,即使没有待执行迁移也不会报错退出; - 配置了
migrations_config时会追加--configuration指定配置文件; - 该任务不在默认
deploy组任务内,需要手动挂载。推荐放在deploy:cache:clear之后、deploy:publish之前:
task('deploy', [ 'deploy:prepare', 'deploy:vendors', 'deploy:cache:clear', 'database:migrate', // 手动插入 'deploy:publish', ]);也可以单独执行:dep database:migrate。
4.2 doctrine:schema:validate — 校验 Doctrine 映射
desc('Validate the Doctrine mapping files'); task('doctrine:schema:validate', function () { run("cd {{release_or_current_path}} && {{bin/console}} doctrine:schema:validate {{doctrine_schema_validate_config}} {{console_options}}"); });等价于在服务器上执行bin/console doctrine:schema:validate,用于检查实体映射与数据库 schema 是否一致,常在发布前作为质量门禁使用:dep doctrine:schema:validate。
4.3 deploy:cache:clear — 清空缓存
desc('Clears cache'); task('deploy:cache:clear', function () { if (false !== strpos(get('composer_options', ''), '--no-scripts')) { run('{{bin/console}} cache:clear {{console_options}}'); } });这个任务体现了 Deployer 对性能的精细考虑:Composer 的install脚本通常已经清空并预热了 Symfony 缓存,所以默认什么都不做;只有当composer_options中包含--no-scripts(即跳过了 Composer 脚本)时,才会手动执行cache:clear。composer_options的默认值来自 recipe/deploy/vendors.php:
set('composer_options', '--verbose --prefer-dist --no-progress --no-interaction --no-dev --optimize-autoloader');4.4 deploy:dump-env — 优化环境变量
desc('Optimize environment variables'); task('deploy:dump-env', function () { within('{{release_or_current_path}}', function () { run('{{bin/composer}} dump-env "${APP_ENV:-prod}"'); }); });在release_or_current_path目录内执行composer dump-env,把.env中的环境变量按APP_ENV(默认prod)编译进.env.local.php,避免每次请求动态解析.env带来的开销。{{bin/composer}}来自 recipe/deploy/vendors.php,它会自动探测远程 Composer:若.dep/composer.phar存在则优先使用,否则用系统composer,都没有时自动下载安装到.dep/composer.phar。
4.5 deploy — 一键部署
如前所述,deploy组任务按deploy:prepare → deploy:vendors → deploy:cache:clear → deploy:publish的顺序执行,其中:
deploy:vendors(recipe/deploy/vendors.php)在 release 目录内执行composer install,若远程缺少unzip命令会给出提速提示;deploy:publish依次完成软链切换(deploy:symlink)、解锁(deploy:unlock)、旧版本清理(deploy:cleanup)与成功提示(deploy:success)。
命令行直接运行:
dep deploy五、编写自己的 deploy.php:完整示例
把以上配置与任务组合起来,一个可用的 Symfony 部署脚本大致如下:
<?php namespace Deployer; require 'recipe/symfony.php'; // 项目信息 set('repository', 'git@github.com:yourname/yourproject.git'); // 部署仓库 set('application', 'your-symfony-app'); // 应用名(用于目录与提示) // 主机配置 host('prod') ->set('hostname', '1.2.3.4') ->set('remote_user', 'deployer') ->set('deploy_path', '/var/www/your-symfony-app'); // 必填:部署根目录 // 覆盖 Symfony 配方默认值(按需) set('shared_dirs', ['var/log', 'var/uploads']); // 追加共享目录 set('shared_files', ['.env.local']); // 共享环境配置文件 set('writable_mode', 'chmod'); // 服务器不支持 ACL 时改用 chmod set('keep_releases', 5); // 只保留 5 个历史 release(默认 10) // 在发布前插入数据库迁移 task('deploy', [ 'deploy:prepare', 'deploy:vendors', 'deploy:cache:clear', 'database:migrate', 'deploy:publish', ]);需要注意的要点:
deploy_path是必填项,缺失时 common 配方会抛出ConfigurationException(见 recipe/common.php);- 首次部署前可先用
dep deploy:setup初始化目录结构,或用dep provision直接预配置整台服务器; - 部署出错后回滚:
dep rollback;查看发布历史:dep releases(表格形式展示时间、release 号、作者、目标与提交,实现见 recipe/deploy/release.php); - 跟踪日志:
dep logs:app。
六、源码级原理补充:release 目录结构
理解 Symfony 配方的部署行为,关键在于 Deployer 的 release 机制。一次部署会在deploy_path下形成如下结构(由deploy:setup、deploy:release等任务协同创建,参见 recipe/deploy/release.php):
/var/www/your-symfony-app ├── current -> releases/4 (对外服务的版本) ├── release -> releases/5 (正在部署的版本) ├── releases/ │ ├── 1/ 2/ 3/ 4/ 5/ ├── shared/ │ ├── var/log/ (共享目录实体) │ └── .env.local (共享文件实体) └── .dep/ ├── latest_release └── releases_logdeploy:symlink只做一次原子性的ln -nfs切换,把current指向新 release,这就是“零停机”的本质;deploy:cleanup则依据keep_releases(默认 10,见 recipe/common.php)清理过期版本。shared_dirs、shared_files中的条目会在每个 release 内被软链到shared/下的实体,从而保证日志、环境配置在版本间持续可用——这正是 Symfony 配方默认把var/log与.env.local放进共享区的原因。
结语
recipe/symfony.php用不到 80 行代码,把 Deployer 的通用部署能力与 Symfony 的项目约定(var/目录体系、bin/console、Doctrine 迁移、Composer 依赖)无缝对接。掌握本文介绍的配置项与任务,你既可以开箱即用地执行dep deploy,也能按业务需要自由组合任务链(如插入迁移、调整共享目录、切换权限模式)。当出现部署问题时,从 recipe/symfony.php 出发,沿deploy:prepare → deploy:vendors → deploy:cache:clear → deploy:publish这条主线逐段核对(对应文档见 docs/recipe/deploy 目录),即可快速定位问题所在。
- DevOps
- CI/CD
- CLI
- 开发工具
- 运维
【免费下载链接】deployer
The PHP deployment tool with support for popular frameworks out of the box
相关推荐
使用 Deployer 的 Laravel 配方实现零停机部署:recipe/laravel.php 全解析
使用 Deployer 的 Laravel 配方实现零停机部署:recipe/laravel.php 全解析 本指南以 Deployer 开源项目中的 Lara
DevOpsCI/CDCLI开发工具运维使用 Deployer 零停机部署 Shopware 6:recipe/shopware.php 完整实战指南
使用 Deployer 零停机部署 Shopware 6:recipe/shopware.php 完整实战指南 Deployer 是一个用 PHP 编写的开源部
DevOpsCI/CDCLI开发工具运维使用 Deployer 零停机部署 CodeIgniter 4:recipe/codeigniter4 完整实战指南
使用 Deployer 零停机部署 CodeIgniter 4:recipe/codeigniter4 完整实战指南 本指南讲解如何在 Deployer 中引入
DevOpsCI/CDCLI开发工具运维
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考