Deployer 实战:使用 Symfony 配方(Recipe)零停机部署 PHP 应用
2026/9/24 1:12:37 网站建设 项目流程
  • DevOps
  • CI/CD
  • CLI
  • 开发工具
  • 运维

【免费下载链接】deployer

The PHP deployment tool with support for popular frameworks out of the box

项目地址:https://gitcode.com/gh_mirrors/de/deployer
点击查看免费下载

本篇技术指南基于 Deployer 开源仓库中的 Symfony 部署配方文档 及其源码 recipe/symfony.php,系统讲解如何通过require 'recipe/symfony.php'将 Symfony 应用部署到服务器。你将掌握该配方的全部配置参数(shared_dirswritable_dirsbin/consolemigrations_config等)、核心任务(deploydatabase:migratedeploy:cache:cleardeploy: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:preparedeploy: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:preparedeploy: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.exampledotenv_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决定,可选值包括chownchgrpchmodaclstickyskip,默认'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.2

3.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:clearcomposer_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:setupdeploy: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_log

deploy:symlink只做一次原子性的ln -nfs切换,把current指向新 release,这就是“零停机”的本质;deploy:cleanup则依据keep_releases(默认 10,见 recipe/common.php)清理过期版本。shared_dirsshared_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

项目地址:https://gitcode.com/gh_mirrors/de/deployer
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询