想象一座工厂:每件产品用同一模具、同一标签出厂,并在送达客户前经过质检。这就是一套可靠的 Docker + CI/CD + Coolify 流水线——不是“把我笔记本上能跑的东西手动上传”,而是把代码变成可重复、可信赖的发布过程。
本文用清晰语言和具体步骤,说明如何部署 Laravel API、Node 应用以及容器化的 WordPress。适合希望减少故障的产品负责人,也适合需要真正运维手册(而不是零散 Dockerfile)的技术团队。
为什么对业务重要
每一次临时部署都是风险:支付停收、周五表单挂掉,或因没人记得线上版本而无法回滚。良好的流水线缩短上线时间,让预发环境可信,并把部署变成可度量的操作——而不是午夜仪式。
- 减少“在我机器上能跑”:同一产物经过测试再晋升。
- 可预期回滚:几分钟内回到上一标签,而不是靠猜。
- 可审计:清楚生产环境是哪个 commit、谁晋升的。
- 团队可扩展:初级工程师也能按流程部署,不破坏资深流程。
关键概念(通俗 + 技术)
Docker:密封的箱子
Docker 把应用及其依赖打包成镜像。像货运集装箱:码头(服务器)可以换,内容运输方式不变。技术上:分层、多阶段 Dockerfile,以及不含构建工具链和密钥的运行时。
CI/CD:装配线
CI(持续集成)验证每次变更:lint、测试、构建。CD(持续交付/部署)把产物送到预发,并通过质量门后到生产。Coolify 擅长部署(SSL、变量、重启);CI 仍在 GitHub Actions、GitLab CI 或其他 runner 中。
不可变标签 vs latest
只用 latest 就像给箱子贴“当前版本”却没有批次号。应使用 registry/app:gitsha:确切知道运行内容,并可重新部署该 digest。
| 部件 | 类比 | 实际作用 |
|---|---|---|
| Docker 镜像 | 打包好的产品 | 预发与生产使用同一产物 |
| CI 流水线 | 质检 | Lint、测试、扫描、构建 |
| Coolify | 仓库 + 发货 | 部署、SSL、环境变量、健康检查 |
| SHA 标签 | 批次号 | 精确回滚与可追溯 |
实践指南:最小流水线
- PR:lint + 类型检查 + 单元测试(有结账流程时加关键 e2e)。
- 多阶段构建:依赖 → 构建 → 精简运行时。
- 不可变标签:
registry/app:gitsha(不要只用latest)。 - 基础镜像扫描(明显 CVE、root 用户、层中密钥)。
- 部署到预发:在 Coolify 使用相同变量名(不同值)。
- 冒烟 / 健康检查:廉价路由验证应用 + 数据库。
- 晋升到生产:同一 digest/标签——不要另做一次不同构建。
Laravel / Node 多阶段构建
- deps:按层顺序缓存 Composer/npm。
- build:
npm ci+npm run build、php artisan optimize、静态资源。 - runtime:非 root 用户、无工具链、不内嵌
.env。 - Laravel 的
storage与bootstrap/cache权限正确。
Docker 中的 WordPress
- 为
wp-content/uploads使用持久卷。 - 密钥通过环境变量 / 运行时生成的
wp-config——绝不打进镜像。 - 流量需要时,把对象缓存(Redis)作为独立服务。
- 多站点:域名、Cookie 与路径需文档化。
- 重大更新前备份数据库与上传文件。
Coolify 配置
- 变量与密钥放在 Dockerfile 之外。
- 真实健康检查(稳定路由返回 HTTP 200,不只是“进程存在”)。
- 规范 apex 域名;
www做 301 重定向。 - 两个主机都配置 Let's Encrypt SSL。
- 预发与生产分离;配置重启策略并保证日志可访问。
常见错误
- 生产环境另做一次构建:既不知道跑什么,也无法复现问题。
- 健康检查打到带 301 的
/→ unhealthy 循环。 - WordPress 卷属主为
root→ 上传失败。 - 并行执行两次
migrate --force。 - 忘记队列 worker:网站能访问,webhook 不处理。
- 为图方便把密钥放进 Git 或 Docker 层。
上线前检查清单
- 标签 = git SHA(不要只用
latest)。 - 仓库与 Docker 层中均无密钥。
- 预发使用同一镜像且健康检查为绿。
- 迁移已演练 + 有近期备份。
- 已验证 apex /
www与 SSL。 - 部署后 worker 与 cron 存活。
- 写好回滚计划(重新部署上一 SHA)。
- 预发与生产变量名一致、值不同。