第十九章:NPM 包与 Docker CI/CD 自动化 交付详解,利用 Github Action 实现全自动化发布
第十九章:NPM 包与 Docker CI/CD 自动化 交付详解,利用 Github Action 实现全自动化发布
Prorise第十九章:NPM 包与 Docker CI/CD 自动化 交付详解,利用 Github Action 实现全自动化发布
本章目标:将 Release Please 生成的版本号与 NPM 发布、Docker 构建流程打通,实现端到端的自动化交付
开始之前:认识什么是制品
在软件工程中,制品 指的是可以直接分发给用户的、可执行的交付物,常见类型包括:
| 制品类型 | 示例 | 分发渠道 | 本章是否覆盖 |
|---|---|---|---|
| NPM 包 | react、vue、lodash | npmjs.com | ✅ 是 |
| Docker 镜像 | nginx:latest、node:18-alpine | Docker Hub、GHCR | ✅ 是 |
| 二进制可执行文件 | kubectl、terraform | GitHub Releases | ⚠️ 原理相同 |
| 移动应用 | .apk、.ipa | Google Play、App Store | ❌ 否 |
注意,本章节默认了你已经熟悉了 docker 的基础操作,在此之上我们引申出 Docker 的 CI/CD 流程,如果你对于 Docker 还不熟悉,请跳转至
19.1. NPM 包的无人值守发布
19.1.1. 手动发布的痛点与安全风险
传统手动发布流程:
1 | # 1. 手动修改版本号 |
问题分析:
| 步骤 | 问题 | 风险 |
|---|---|---|
| 1 | 版本号可能冲突/遗漏 | 覆盖已发布版本 |
| 2 | CHANGELOG 容易漏记 | 用户不知道更新了什么 |
| 3 | 忘记打 Tag | 无法回溯代码 |
| 4 | 需要人工输入 OTP | CI 无法自动化 |
19.1.2. NPM 的 2FA 认证机制
为什么 NPM 强制 2FA?
2018 年,著名的 event-stream 事件中,攻击者通过盗取维护者账号,向包中植入了窃取比特币钱包的恶意代码,影响了数百万下载量。
从那以后,NPM 强制要求:
- 所有发布操作必须启用 2FA
- 敏感操作(发布、删除包)需要输入 OTP
问题:CI 服务器没有手机,无法输入 OTP。
解决方案:Automation Token(自动化令牌)
19.1.3. 生成 NPM Automation Token 的正确姿势
步骤 1:登录 NPM 官网
访问 https://www.npmjs.com/ 并登录。
步骤 2:进入 Access Tokens 页面
点击头像 → Access Tokens
或直接访问:https://www.npmjs.com/settings/YOUR_USERNAME/tokens
步骤 3:创建新 Token
点击 Generate New Token → 选择 Automation
三种 Token 类型对比:
| 类型 | 权限 | 有效期 | 是否需要 OTP(一次性密码) | 适用场景 |
|---|---|---|---|---|
| Publish | 可发布包 | 永久(可撤销) | ✅ 需要 | 本地开发 |
| Automation | 可发布包 | 永久(可撤销) | ❌ 不需要 | CI/CD ⭐ |
| Read-Only | 只读私有包 | 永久(可撤销) | ❌ 不需要 | 安装私有依赖 |
选择 Automation 后,会显示 Token(格式类似:npm_xxxxxxxxxxxxxxxxxxxxxxxxxxxx)
重要提醒:
- Token 只显示一次,必须立即复制
- 建议复制到密码管理器(如 1Password)
- 永远不要 提交到 Git 仓库
19.1.4. 配置 GitHub Secrets
进入 GitHub 仓库 → Settings → Secrets and variables → Actions → New repository secret
添加 Secret:
- Name:
NPM_TOKEN - Value: 粘贴刚才复制的 Token
19.1.5. 编写自动发布 Workflow
为什么作为 Release Please 的第二个 Job?
很多新手会写成独立的 workflow:
1 | # ❌ 错误示范 |
问题:
- Release Please 使用
GITHUB_TOKEN创建的 Release,可能不会触发release事件(GitHub 的防循环机制) - 时间差问题:Release 创建和 workflow 触发之间有延迟
正确做法:将发布作为 Release Please workflow 的第二个 Job,通过 needs 和 if 条件控制。
完整 Workflow 代码
文件路径:.github/workflows/release-please.yml
1 | name: Release Please |
19.1.6. 常见问题排查手册
问题 1:“This package has been marked as private”
错误信息:
1 | npm ERR! This package has been marked as private |
原因:package.json 中有 "private": true 字段。
解决方法:打开 package.json,删除或修改:
1 | { |
⚠️ 注意:如果这个包确实不应该发布到公开 NPM,请检查是否配置错误。
问题 2:“You must be logged in to publish packages”
错误信息:
1 | npm ERR! code ENEEDAUTH |
原因:
NODE_AUTH_TOKEN环境变量没有正确设置- Token 已过期或被撤销
actions/setup-node的registry-url配置错误
解决方法:
- 确认
secrets.NPM_TOKEN在 GitHub Secrets 中存在 - 确认 workflow 中有
registry-url: 'https://registry.npmjs.org' - 检查 Token 是否过期(在 NPM 官网查看)
19.2. Docker 镜像的分级发布与标签管理
19.2.1. 生产环境 vs 测试环境:矛盾的需求
在容器化交付中,不同环境对镜像的要求是截然相反的。如果不做分级管理,就会导致“测试环境无法验证最新代码”或“生产环境随意更新导致事故”。
| 维度 | 测试/开发环境 (Dev/Test) | 生产环境 (Prod) |
|---|---|---|
| 核心诉求 | 时效性:代码合并后,必须立即能测 | 稳定性:版本必须锁定,严禁变动 |
| 镜像标签 | latest (滚动更新) | v1.2.3 (不可变) |
| 更新频率 | 高频 (每次 Merge Request 合并) | 低频 (仅在正式发版时) |
| 拉取策略 | imagePullPolicy: Always | imagePullPolicy: IfNotPresent |
设计目标:
- 日常开发:只要代码合并到
main分支,流水线应自动构建latest标签,供测试环境拉取。 - 正式发布:当发布新版本时,流水线除更新
latest外,必须 额外 打上v1.2.3等精确版本标签,供生产环境使用。
19.2.2. 企业级镜像标签 (Tag) 策略
为了满足从开发调试、自动升级到严格回滚的全场景需求,一个成熟的 Docker 镜像仓库应包含以下五个层级的标签。
| 标签类型 | 示例 | 触发时机 | 适用场景 | 关键特性 |
|---|---|---|---|---|
| Git SHA | sha-abc1234 | 每次 Push | 调试/定位:精准对应某次代码提交,用于排查 Bug。 | 唯一性 |
| Latest | latest | 每次 Push | 测试环境:永远指向 main 分支的最新代码。 | 易变性 |
| Patch | v1.2.3 | 发版时 | 生产部署:锁定特定版本,生产环境 YAML 必须使用此标签。 | 不可变 |
| Minor | v1.2 | 发版时 | 安全更新:指向 v1.2.x 系列的最新版,用于自动获取 Bug 修复。 | 滑动指针 |
| Major | v1 | 发版时 | 长期维护:指向 v1.x.x 系列的最新版。 | 滑动指针 |
最佳实践图解:
1 | Commit A (Fix Bug) ---> Build ---> my-app:latest, my-app:sha-AAA |
19.2.3. 动态标签编排 (Dynamic Tagging)
为了在一条流水线中同时满足上述需求,我们利用 docker/metadata-action 的条件逻辑,而不是编写两个重复的 Job。
逻辑流向:
- 监听:流水线监听
main分支的所有推送。 - 判断:
release-please判断当前提交是“普通合并”还是“正式发版”。 - 分支处理:
- 如果是 普通合并:仅构建
latest和sha-xxxx。 - 如果是 正式发版:构建
latest、sha-xxxx以及v1.2.3。
- 如果是 普通合并:仅构建
19.2.4. 完整工作流实现
此配置文件实现了上述的“动静分离”策略。它确保了测试环境随时可用,且生产环境版本严格受控。
文件路径:.github/workflows/release-publish.yml
1 | name: Release & Publish |
19.2.5. 结果验证
运行上述流水线后,Docker Hub 的仓库中会出现以下情况,完美匹配企业需求:
日常开发提交时:
- 更新
latest标签(测试环境自动获取新功能)。 - 新增
sha-7b3f1a...标签(保留历史构建记录)。 - 不会 生成
v1.2.3(保护生产版本号不被滥用)。
- 更新
Release Please 自动发版时:
- 更新
latest标签。 - 新增
sha-8c4d2e...标签。 - 新增
v1.2.3标签(生产环境 YAML 修改为此版本进行上线)。 - 新增
v1.2标签(可选,供依赖次版本的下游服务使用)。
- 更新
19.3. 完整 CD 流程集成:Release → NPM → Docker
19.3.1. 最终架构图
1 | ┌──────────────────────────────────────────────────────┐ |















