适用读者:要对"十个人都能跑起来"负责的人(Tech Lead / 平台工程 / 团队负责人)。
前置:S01-J02(流程与 CR)、S01-J05(IDE 性能)、S01-B09(环境可重建)。
版本基线:JDK 17/21、Maven 3.9.x、Git 2.4x、Node 20 LTS(仅文档站)。
覆盖旧文:A-555(团队 Git 流程的治理视角,duplicate_ref 至 S01-J02)。
新增扩展:E-S01-028(devcontainer / Codespaces)。
上一篇:S01-J08 · 制品发布:GPG 签名与中央仓库发布
下一篇:S01-A02 · 制品仓库与供应链安全。
本篇的读者层级是"架构师":不教你怎么装,而是教你怎么让一群人不靠口口相传地装好,并对结果负责。
1. 业务目标与约束
1.1 目标(可度量)
| 目标 | 指标 | 现状假设 | 目标值 |
|---|---|---|---|
| 新人可独立提交 | D0(入职当天)首个 PR 合入率 | 30% | ≥ 80% |
| 环境问题不占开发时间 | 环境类工单 / 总工单 | 25% | ≤ 5% |
| 构建可复现 | CI 构建成功率(同一 commit 重跑一致率) | 85% | ≥ 99% |
| 换机器成本 | 从零到可提交的耗时 | 1–3 天 | ≤ 2 小时 |
为什么用这四个:它们分别对应"人进来""人干活""结果可信""机器坏了"四种成本。任何标准化投入,都必须能在这四个数字上说清收益。
1.2 约束(先摆清楚,否则方案一定跑偏)
| 约束 | 影响 |
|---|---|
| 多操作系统(Win/macOS/Linux) | 任何"只在我机器上有效"的方案都要打折 |
| 公司网络(代理/白名单) | 镜像源、插件市场、GPG keyserver 都可能不通 |
| 安全合规(代码不离内网) | 云端 IDE 可能直接被否 |
| 预算(Licenses) | IDE Ultimate 席位、云开发环境按量计费 |
| 历史包袱(多 JDK、多 Maven) | 不能一步切齐,需并行期 |
2. 方案比较:五条路径
| 方案 | 一致性 | 上手成本 | 成本 | 安全 | 适合 |
|---|---|---|---|---|---|
| ① 文档(Wiki/README) | 低(会过期、会漏) | 低 | 低 | 高 | 极小团队(≤3 人) |
| ② dotfiles + 安装脚本 | 中(脚本会烂) | 中 | 低 | 高 | 5–20 人,混合 OS |
| ③ devcontainer(容器化开发环境) | 高 | 中 | 低 | 高(本地) | 20 人内首选 |
| ④ 云开发环境(CDE,自建) | 高 | 高 | 中(服务器) | 高 | 安全要求严、远端算力 |
| ⑤ 全托管(Codespaces/Gitpod) | 高 | 低 | 按人月计费 | 中(代码出网) | 短期项目、外包 |
判据:"新人的第一份错误,会不会来自环境而不是代码?" 会 → 至少上 ③;不会 → ② 也够。
3. 版本矩阵:唯一的"事实来源"
标准化不是"大家都装最新版",而是版本可查询、可对齐:
| 组件 | 允许版本 | 强制方式 | 谁负责升级 |
|---|---|---|---|
| JDK | 17 / 21(LTS) | maven.compiler.release + .sdkmanrc / devcontainer |
平台组(季度) |
| Maven | 3.9.x | mvnw(wrapper 锁版本) |
平台组 |
| Git | ≥ 2.34(签名特性) | 文档 + CI 检查 | 个人 |
| IDE | 2025.1+(Ultimate 统一) | 许可管理 | 平台组 |
| Node(文档站) | 20 LTS | .nvmrc |
文档 owner |
| Docker | ≥ 24 | devcontainer 镜像 | 平台组 |
关键设计:能锁的都用文件锁,不能锁的用 CI 检查。
<!-- pom.xml:锁编译器插件与 release -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration><release>17</release></configuration>
</plugin>
# .mvn/wrapper/maven-wrapper.properties(mvnw 生成,锁 Maven 版本)
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
为什么强调
mvnw:S01-B03 实测过"默认插件版本随 Maven 变",S01-J07 实测过"没锁插件直接构建失败"。版本漂移是环境类工单的头号来源。
4. devcontainer:把环境写成代码(E-S01-028)
4.1 草案(可直接进仓库)
/.devcontainer/devcontainer.json:
{
"name": "team-java-dev",
"image": "mcr.microsoft.com/devcontainers/java:21-bookworm",
"features": {
"ghcr.io/devcontainers/features/java:1": { "version": "21", "installMaven": true },
"ghcr.io/devcontainers/features/git:1": {}
},
"postCreateCommand": "./mvnw -B -q dependency:go-offline",
"customizations": {
"vscode": { "extensions": ["vscjava.vscode-java-pack", "redhat.java"] }
},
"mounts": [
"source=${localEnv:HOME}/.m2,target=/home/vscode/.m2,type=bind"
],
"remoteUser": "vscode"
}
| 设计点 | 理由 |
|---|---|
| 基础镜像带 JDK 21 | 版本由镜像决定,不靠人装 |
postCreateCommand 预拉依赖 |
首次 mvn 不再等下载;go-offline 把依赖固化到挂载的 ~/.m2 |
挂载宿主机 ~/.m2 |
复用缓存,避免每次重建下载几十 MB |
| 不挂载源码目录 | 保持"环境与代码分离",代码始终在 Git 里 |
4.2 IDEA 侧
IDEA 支持"连接 devcontainer 后在容器内开发"(Ultimate)。取舍:
| 优点 | 代价 |
|---|---|
| 环境完全一致,新人几乎零配置 | 需要 Ultimate 席位 |
| 容器出问题就重建,不污染本机 | 索引/编译在容器里,需给容器足够内存 |
4.3 容器化不能解决的事(诚实边界)
| 问题 | 为什么解决不了 |
|---|---|
| IDE 图形性能 | 渲染仍在本地,远端索引受网络影响 |
| 调试端口 | 需要端口映射与 JDWP 安全边界(S01-J04 §10.4) |
| 依赖镜像源不通 | 容器内也要配镜像(S01-B03 §7) |
| 硬件相关(JNI、GPU) | 容器难以透传 |
5. Onboarding 检查单(可交付物)
D0(入职当天)
- 账号:Git 平台、私服、CI、制品库(权限按最小可用给)
- 代码:
git clone主仓库,./mvnw -v通过 - 环境:devcontainer 或 dotfiles 脚本执行完成
- 首个 PR:改一行文档/修一个 typo,走完整 CR 流程(目的不是产出,是验证流程可用)
- 认领一块"第一次就能做完"的小任务
D1–D3
- 本地跑起一个服务的集成测试
- 完成一次 hotfix 演练(在测试分支)
- 读懂
CONTRIBUTING.md(提交规范、分支策略、CR 要求)
W1
- 独立完成一个需求从分支到合并
- 能自行定位一次环境故障(用 S01 系列的排障表)
- 填写 Onboarding 反馈(哪一步卡住)
D0 的"首个 PR"是整份清单的关键:它把"环境是否可用"变成了一次可观测的、有产出的验证,而不是"我觉得装好了"。
6. 可观测性与故障域
6.1 三条必须监控的指标
| 指标 | 采集方式 | 告警阈值 |
|---|---|---|
| CI 构建成功率 | CI 平台统计 | < 95% 连续 3 天 |
| 环境类工单占比 | 工单系统标签 | > 10% |
| 私服/镜像可用性 | 定时 mvn dependency:get 探活 |
1 次失败即告警 |
第三条最容易被忽略:私服挂了,所有人构建都失败,但没人会主动报"私服挂了"——他们报"我的代码有问题"。
6.2 故障域分析
| 故障 | 影响面 | 缓解 |
|---|---|---|
| 私服不可用 | 全员构建失败 | 本地仓库预热 + 公网镜像兜底(settings.xml 备选仓库) |
| 镜像源(阿里云)故障 | 新人装不上依赖 | 双镜像配置,文档写清切换方式 |
| 证书/密钥过期 | 发布链路突然全断 | 到期前 30 天提醒(GPG、SSH、CI token) |
| devcontainer 基础镜像下架 | 新人无法启动 | 镜像版本 pin + 内部 Harbor 备份 |
| IDE 许可证到期 | 无法开发 | 许可池管理 + 到期提醒 |
7. 迁移与回滚
| 阶段 | 动作 | 回滚条件 |
|---|---|---|
| 试点(2 周) | 3 人用 devcontainer,其余用旧方式 | 出现阻塞性问题即停 |
| 并行(1 月) | devcontainer 与 dotfiles 并存 | 任一方案失败可切回 |
| 切换(1 天) | 新人默认 devcontainer | 保留旧文档 3 个月 |
| 固化 | CI 检查版本矩阵(enforcer + mvnw) |
— |
回滚原则:任何标准化都必须保留"旧路径可用"至少一个季度。一刀切切换,出问题时团队会同时失去生产力和信任。
8. 验收条件(写进团队 OKR 的那种)
| # | 验收项 | 判据 |
|---|---|---|
| 1 | 新人 D0 首个 PR | 3 个新人中 ≥ 2 人达成 |
| 2 | 环境类工单占比 | ≤ 5%(连续两月) |
| 3 | 构建一致率 | 同一 commit 重跑一致 ≥ 99% |
| 4 | 换机恢复 | 从零到可提交 ≤ 2 小时(实测 2 人) |
| 5 | 回滚可用 | 旧路径在新人入职文档中仍可查 |
9. 与 S01 其他文章的关系
| 主题 | 基础/进阶篇 | 本篇的治理视角 |
|---|---|---|
| 版本对齐 | B02、B03 | 版本矩阵 + mvnw + enforcer |
| IDE 配置 | B04、B09 | devcontainer + 共享 Code Style |
| Git 流程 | B10、J02 | 分支保护、CR 准入、CODEOWNERS |
| 性能 | J05 | 容器资源配额、索引策略 |
| 依赖治理 | J07 | 私服可用性监控 |
10. 自测(架构师版)
- 为什么"D0 首个 PR"比"文档写清楚"更能验证环境可用?
- devcontainer 挂载
~/.m2的好处与风险各是什么? - 私服挂掉时,你的兜底链路是什么?多久能恢复全员构建?
- 为什么标准化方案必须保留旧路径一个季度?
- 三个指标里,哪个最能提前预警"下一次发布要出事"?
11. 下一篇
S01-A02 · 制品仓库与供应链安全
环境标准化解决"人怎么干活",下一层是"依赖从哪来、能不能信"。下一篇讲制品流向、SBOM、漏洞追溯、许可证合规与制品晋升,并给出"某个 CVE 影响我们哪些服务"的可执行答案。
本篇属于系列《S01 · 开发环境与工具链》,架构师层第 1 篇。旧文关联:A-555(duplicate_ref);扩展点 E-S01-028。