引言:为什么你至今仍害怕点击“部署”?
\n\n你写好了代码。在本地机器上测试通过。所有测试都通过了。一切完美。你点击了那个梦寐以求的 部署 按钮……5分钟后,你看到 500 错误不断出现,用户们惊慌失措地向客服投诉。熟悉吗?
\n\n传统的部署策略(蓝绿部署、滚动更新)固然不错,但它们有一个缺点:它们要么一次性包含所有新代码,要么根本不包含。但是,如果你能将一个新功能只发送给 1% 的用户,观察指标,然后在确认稳定性后,再将其推广到 100% 的用户,那会怎样?
\n\n这正是 金丝雀部署 的工作原理。这个名字源于古老的矿工实践——带一只金丝雀下井,以便及时发现瓦斯泄漏。如果小鸟停止鸣叫,矿工们就知道:该往上跑了。在 IT 世界里,“金丝雀”是一小部分用户,新代码会在他们身上进行测试。如果一切顺利,发布就会继续推进。如果没有,你可以在说出“热修复”之前就完成回滚。
\n\n在本文中,我们将使用 TypeScript 构建一个完整的金丝雀部署系统。你将学习如何配置流量负载均衡,如何通过 CI/CD 实现流程自动化,以及如何监控你的“金丝雀”的健康状况。我们开始吧!
\n\n什么是金丝雀部署,为什么需要它?
\n\n金丝雀部署 是一种新代码的发布策略,其中应用程序的更新版本首先发送给一小部分用户(通常为 1-10%)。其余用户继续使用旧的稳定版本。如果新版本没有出现问题(错误、性能下降、延迟增加),你逐渐增加流向它的流量百分比,直到它完全取代旧版本。
\n\n关键优势:
\n- \n
- 风险最小化 — 错误仅影响一小部分受众。 \n
- 快速回滚 — 只需将流量重新定向回稳定版本。 \n
- 真实环境下的 A/B 测试 — 可以比较新旧版本的指标。 \n
- 平滑发布 — 你不会因突然的负载激增而压垮服务器。 \n
现在让我们从理论转向实践。我们将构建一个由三部分组成的系统:
\n- \n
- 基于 TypeScript (Express.js) 的后端。 \n
- 基于 Nginx 的流量负载均衡器。 \n
- 通过 GitHub Actions 实现自动化。 \n
步骤 1. 编写支持版本管理的 TypeScript 应用程序
\n\n首先,我们创建一个简单的 Express 应用程序,它能够在两种模式下运行:stable 和 canary。区别仅在于对根端点的响应,但在实际项目中,这可以是任何新功能。
\n\n// src/app.ts\nimport express, { Request, Response } from 'express';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\nconst app = express();\nconst PORT = process.env.PORT || 3000;\nconst VERSION = process.env.VERSION || 'stable'; // 'stable' 或 'canary'\n\napp.get('/', (req: Request, res: Response) => {\n res.json({\n message: 'Hello from API!',\n version: VERSION,\n timestamp: new Date().toISOString(),\n });\n});\n\n// 健康检查端点\napp.get('/health', (req: Request, res: Response) => {\n res.status(200).send('OK');\n});\n\napp.listen(PORT, () => {\n console.log(`Server running on port ${PORT} in ${VERSION} mode`);\n});\n\n\n现在,我们创建一个 Dockerfile,将应用程序打包到容器中。这将简化部署和负载均衡。
\n\n# Dockerfile\nFROM node:18-alpine AS builder\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci\nCOPY . .\nRUN npm run build\n\nFROM node:18-alpine AS runner\nWORK