登录
首页 >  文章 >  php教程

Envoyer零停机部署实战教程

时间:2026-05-19 16:09:52 298浏览 收藏

Envoyer 的“零停机部署”并非开箱即用的魔法功能,而是依赖符号链接原子切换、独立发布目录与严格配置的共享路径(如 .env 和 storage)三者精密协同的结果;真正实现无缝更新的关键在于:数据库迁移必须在 current 切换前完成且保持向前兼容,共享文件需手动上传并正确映射,而队列和定时任务必须通过 Supervisor 或 Cron 主动重启或指向 current 路径——任何一环疏漏(比如在 After 阶段执行 migrate、遗漏 shared 配置或忽略健康检查盲区),都可能引发静默故障、500 错误或后台任务停滞,让看似成功的部署暗藏线上危机。

Envoyer如何实现零停机_LaravelEnvoyer无缝部署策略【实战】

Envoyer 本身不提供“零停机”的魔法开关,它只是把一套已被验证的原子化发布流程封装成了图形界面。真正起作用的是符号链接切换 + 独立发布目录 + 共享路径隔离 —— 这三者缺一不可。如果你在 Envoyer 面板里勾了“Zero Downtime Deployment”但没配对共享目录或迁移仍在新代码加载后执行,那还是会有请求失败。

为什么 current 软链切换能实现零停机

PHP-FPM 处理每个请求时,会根据 Nginx 的 root /home/forge/example.com/current/public 去加载文件。只要 current 指向的是一个完整、已安装依赖、已运行迁移、已生成缓存的目录,切换动作(ln -nfs releases/20260429123456 current)就是纳秒级的。用户不会感知到任何中断,因为旧进程还在处理完手头请求,新请求立刻落到新代码上。

容易踩的坑:

  • 没把 .envstorage/ 设为共享路径 → 新 release 目录读不到配置或上传文件,直接报错
  • 在 Envoyer 的“After”阶段才跑 php artisan migrate → 此时 current 已切过去,旧代码可能还在执行,而新迁移已改表结构,导致 500
  • 启用了“Run migrations in queue”,但队列进程没配置为优雅重启 → 迁移卡在队列里,或者旧 worker 仍用老代码执行任务

php artisan migrate 必须在 current 切换前完成

Envoyer 默认把迁移放在“Deploy”阶段末尾,也就是新目录准备就绪但尚未激活时。这是安全窗口:代码已就位,数据库还没动,旧服务照常运行。你必须确认这个阶段确实执行了迁移,并且迁移本身是向前兼容的。

关键检查点:

  • 打开项目设置 → “Deployment Scripts” → 找到 “Before” 或 “Deploy” 区块,确认有 php artisan migrate --force 且不在 “After”
  • 如果迁移含破坏性操作(如删字段、改类型),务必拆成两步:先加字段并兼容旧逻辑,上线后再删;Envoyer 不会帮你做语义分析
  • 避免在迁移里写 DB::table(...)->get() 加载大量数据 —— 这会阻塞部署,超时后 Envoyer 可能标记失败并回滚

共享路径(shared)不是可选项,是强制项

Envoyer 在服务器上自动创建 /home/forge/example.com/shared,但不会自动把你的 .envstorage 放进去。你得手动上传并配置路径映射,否则每次部署都会覆盖掉这些运行时必需的数据。

正确做法:

  • 首次部署前,把生产 .env 上传到 /home/forge/example.com/shared/.env
  • 在 Envoyer 设置页 → “Shared Files” 里填入:.env, storage(注意不带斜杠)
  • 确保 storage 目录权限为 775,属主是 forge:www-data,否则新 release 下的 php artisan storage:link 会失败
  • 不要在 “Deployment Script” 里写 cp -r shared/storage ./storage —— Envoyer 会在每次部署时自动软链,重复操作反而可能破坏结构

队列与定时任务不随 current 自动更新

Nginx 请求走的是 PHP-FPM,它每次请求都重新加载 current 下的代码;但 php artisan queue:work 是长进程,启动后就锁死了当时的代码路径。你切了 current,它还跑在上个 release 里。

解决方案只有两个:

  • 在 Envoyer 的 “After” 脚本里加:sudo supervisorctl reread && sudo supervisorctl update && sudo supervisorctl restart myapp-queue(假设你用 Supervisor 管理)
  • 或者更稳妥地,在 “Before” 阶段就停掉旧队列:sudo supervisorctl stop myapp-queue,再在 “After” 启动新队列
  • 同理,php artisan schedule:run 如果是用 Cron 调用的,需确认 Cron 条目里路径写的是 /home/forge/example.com/current/artisan,而不是固定死的某个 release 目录

最常被忽略的一点:Envoyer 的“健康检查”默认只访问 / 返回 200 就算成功。但它不校验数据库连接、缓存是否生效、队列是否已重启。一次看似成功的部署,可能让后台任务静默失效数小时——直到你发现邮件没发、通知没推、统计漏了数据。

到这里,我们也就讲完了《Envoyer零停机部署实战教程》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于的知识点!

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>