v1.1.0: Alpine 轻量级 Docker 开发环境 + 敏感凭证清理

This commit is contained in:
lxy
2026-07-27 13:59:18 +08:00
parent feb76081a0
commit ccca0fa62b
51 changed files with 6125 additions and 993 deletions
+316
View File
@@ -0,0 +1,316 @@
# 架构设计审核报告 -- WorkPod
> 审核日期:2026-04-07
> 审核范围:`E:/wk-lab/workpod`
> 镜像大小:~436MBalpine:3.23 基础,多阶段构建)
---
## 架构概览
```
+-----------------------------+ +------------------------+
| Docker Host (测试服) | | Container |
| | | alpine:3.23 |
| workpod-alpine (2222/7681) |------>| +--------------------+|
| docker-compose.yml | | | /usr/sbin/sshd ||
| 基础实例 | | | ttyd (-W 无认证) ||
| workpod-network | | | Node.js (musl) ||
| | | | Claude Code @latest||
| | | | coding-helper ||
| ws-flux-dev (2201/7701) |------>| | tmux ||
| docker-compose.flux.yml | | +--------------------+|
| Flux 项目实例 | | |
| Dockerfile.flux 扩展 | | /opt/ttyd-session.sh |
| | | (tmux session 选择) |
| | | entrypoint.sh |
| | | (开发工具自动检测) |
| | +------------------------+
| _archive/auth-proxy.js |
| (备用认证代理) |
| nginx 反向代理 (wk.1216.top)|
+-----------------------------+
**核心组件关系**
- **Dockerfile**:多阶段构建(builder 安装 Node.js/npm 包 -> runtime 仅复制产物到 alpine:3.23),entrypoint.sh 和 ttyd-session.sh 通过 `COPY --chmod=755` 内置到镜像
- **entrypoint.sh**:统一入口(已内置镜像),直接 `/usr/sbin/sshd` 启动 SSH,自动检测 /root 下开发工具设置 PATHttyd 使用 ttyd-session.sh 做 tmux session 管理
- **Dockerfile.flux**Flux 项目实例扩展构建,基于基础镜像追加项目特定配置
- **ttyd-session.sh**:独立的会话管理脚本(已通过 `COPY --chmod=755` 内置到镜像),支持 URL 参数 `?session=name` 或交互式菜单选择/创建 tmux session
- **docker-compose.yml**:基础实例编排(context: .),workpod-network 网络,2222/7681 端口
- **docker-compose.flux.yml**Flux 项目实例编排,2201/7701 端口,挂载 Flux 工作空间
- **docker-compose-alpine.yml**Alpine 变体备用编排文件,多端口映射(7683/7684),挂载 /root
- **_archive/auth-proxy.js**Node.js 认证代理(已归档),提供登录页 + token 认证 + 多工作区路由 + WebSocket 代理,作为可选组件保留
- **wk.1216.conf**Nginx 配置,SSL 终止 + 反向代理到 ttyd
**关键特征**
- 轻量级镜像(~436MB vs Ubuntu 版 ~2.6GB
- 单一 entrypoint + Dockerfile 扩展模式:基础实例与项目实例共享核心逻辑,通过 Dockerfile.flux 按需扩展
- 开发工具"外挂"模式:安装到 /root 挂载卷,entrypoint 自动检测
- 认证代理方案(auth-proxy.js)已归档至 _archive/,作为可选组件按需启用
---
## 优势分析
### 1. 多阶段构建 -- 镜像体积控制优秀
builder 阶段完成所有重量级操作(npm install、编译依赖),runtime 阶段仅复制 `/opt/node` 到 `/usr/local`。最终镜像 ~436MB,是 Ubuntu 版的 1/6。这是本项目最突出的架构优势。
### 2. 开发工具"外挂"设计 -- 灵活性高
通过 entrypoint.sh 自动检测 `/root` 下的 `.cargo`、`.pyenv`、`go`、`.local/bin` 等目录并动态设置 PATH,实现了:
- 工具安装与镜像构建解耦
- 不同实例可安装不同工具集
- 容器重建不丢失手动安装的工具(只要 /root 已挂载)
- 新增工具类型只需在 entrypoint 添加一行检测逻辑
这一设计在 ISSUES.md 中有清晰记录,体现了"踩坑 -> 抽象 -> 文档化"的良好工程实践。
### 3. ttyd-session.sh -- 会话管理解耦
将 ttyd 的启动命令从 entrypoint 中抽离为独立脚本 `ttyd-session.sh`
- 支持 URL 参数快速进入指定 session`?session=xxx`
- 交互式菜单列出已有 session 并支持新建
- session 名安全过滤(仅允许字母数字下划线连字符)
- 共享 attach 模式(不加 `-d`,多人可同时查看同一 session)
职责划分清晰:entrypoint 负责服务启停,ttyd-session 负责终端会话逻辑。
### 4. 问题记录完整 (ISSUES.md)
ISSUES.md 记录了 11 个已解决的问题及解决方案,涵盖:
- Alpine 特有命令差异(ss vs netstat
- BuildKit 兼容性(--chmod、缓存行为)
- 运行时问题(中文输入、断线恢复、数据持久化)
- 架构决策记录(/root 安装原则)
这是非常有价值的知识资产,降低了团队其他成员的踩坑成本。
### 5. auth-proxy.js -- 完整的认证层
虽然未默认集成到容器中,但 auth-proxy.js 提供了:
- Basic Auth 登录 + Token 机制
- 内存 Token 存储(1小时过期)
- 多工作区路由(默认 + hszd)
- HTTP 和 WebSocket 双协议代理
- 自定义登录页面
这为生产化部署提供了现成的安全方案。
---
## 问题与建议
### [严重] 多实例 entrypoint 膨胀与维护噩梦 -- **[已解决]**
- **位置:** 原为 `entrypoint.sh` vs `entrypoint-test.sh`
- **现状:**
- `entrypoint-test.sh` 已归档至 `_archive/`
- 当前仅保留单一 `entrypoint.sh` 作为统一入口
- Flux 项目实例通过 `Dockerfile.flux` 扩展构建,不再需要独立 entrypoint
- **原问题描述:**
1. **代码大量重复**:两个文件约 70% 代码完全相同(信号处理、PATH 检测、sshd 启动、健康检查、启动信息打印)。修改公共逻辑需要同步两处
2. **yxl 实例的 entrypoint 未纳入仓库**:该实例应该还有第三个 entrypoint 变体,但仓库中只有两个
3. **每新增一个用户就要复制一份 entrypoint**:当前 2 个文件,如果有 10 个用户就是 10 个几乎相同的脚本
4. **配置散落在脚本内部**:ttyd 凭据、端口号、用户名等硬编码在不同 entrypoint 中
- **解决方案:** 归档 entrypoint-test.sh,统一使用单一 entrypoint.sh + Dockerfile 扩展模式。项目特定配置通过 Dockerfile.flux 注入,无需维护多份 entrypoint。
- **遗留建议(供参考):** 如未来需支持更多定制化实例,可考虑将差异项外部化为环境变量:
```bash
# entrypoint.sh 统一入口
TTYD_CREDENTIALS="${TTYD_CREDENTIALS:-ada:123}"
TTYD_PORT="${TTYD_PORT:-7681}"
SSH_PORT="${SSH_PORT:-22}"
CREATE_DEVELOPER_USER="${CREATE_DEVELOPER_USER:-false}"
DEVELOPER_NAME="${DEVELOPER_NAME:-developer}"
[ "$CREATE_DEVELOPER_USER" = "true" ] && setup_developer_user
```
### [高] 安全凭据硬编码且各实例不一致 -- **[已修复]**
- **位置:** 原为 `entrypoint.sh:45`, `entrypoint-test.sh:93`, `Dockerfile:34`
- **现状:** 所有凭据已统一通过环境变量注入,不再在各文件中硬编码
- **原问题描述:**
| 凭据类型 | 原始状态 | 当前状态 |
|----------|---------|---------|
| root 密码 | 多处硬编码 workpod123 | 环境变量注入 |
| ttyd 凭据 | 各实例不一致(ada:123 / jc:1234567 | 环境变量统一注入 |
| auth-proxy 密码 | JS 源码明文 | 已随 auth-proxy 归档,按需启用时从配置读取 |
- **原问题:**
1. **密码明文写在 4 个不同文件中**,修改密码需要改多处
2. **ttyd 凭据各实例不同**ada:123 vs jc:1234567),但没有统一的管理方式
3. **auth-proxy.js 的密码是 JS 源码中的明文**,如果该文件被包含在镜像或 Web 目录中则直接暴露
4. **root 密码与 Dockerfile 中 chpasswd 一致**,但如果通过环境变量覆盖 entrypoint 的密码,Dockerfile 层的密码仍然存在
- **解决方案:** 统一通过 docker-compose 环境变量或 `.env` 文件注入所有凭据,清除源码中的硬编码值。
### [中] auth-proxy.js 与容器架构脱节
- **位置:** `_archive/auth-proxy.js`, `static/login.html`, `wk.1216.conf`
- **现状:** auth-proxy.js 已归档至 `_archive/` 目录,作为可选组件保留在主目录中。不再作为核心组件强制集成。
- **问题:**
1. **部署方式需明确**:如需启用 auth-proxy,应补充启动说明(手动 / systemd / compose sidecar
2. **生命周期无保障**:若独立进程运行,容器重启后 auth-proxy 不会自动恢复
3. **token 存储在内存中**auth-proxy 重启后所有用户需重新登录(可接受,但应文档化)
4. **工作区配置硬编码**`WORKSPACES` 数组写死记录,新增工作区需改代码重启
5. **与 ttyd -W 标志冲突**:容器内 ttyd 启动时用了 `-W`(禁用重连提示,非认证),如果 auth-proxy 作为唯一入口则需确保 ttyd 端口不对外暴露
- **建议:**
- 如需正式使用:将 auth-proxy 集成到 docker-compose 中作为 sidecar 容器或独立 service
- 或将认证能力内置到容器内(如 ttyd 加 `-c` 参数 + Nginx basic_auth
- 工作区配置改为从环境变量或 JSON 文件读取
- 在 README 中说明 auth-proxy 的启用方式和适用场景
### [中] 编排文件职责需明确
- **位置:** `docker-compose.yml`, `docker-compose.flux.yml`, `docker-compose-alpine.yml`
- **现状:** 当前有 3 个编排文件:
- **`docker-compose.yml`**:基础实例,2222/7681 端口,挂载 workspace4G 内存限制,workpod-network 网络。适用于通用开发环境。
- **`docker-compose.flux.yml`**Flux 项目专用实例,2201/7701 端口,挂载 Flux 工作空间目录,使用 Dockerfile.flux 扩展构建。适用于 Flux 项目开发。
- **`docker-compose-alpine.yml`**Alpine 变体备用编排,2222/7683+7684 端口,挂载 workspace + /root,无资源限制。适用于需要完整 /root 挂载的调试场景。
- **问题:**
1. 三个文件用途已有区分但未在文档中集中说明
2. `docker-compose-alpine.yml` 直接引用镜像而非构建,与另外两个文件的构建模式不一致
3. 缺少 `.env` 文件或参数化配置来统一管理端口/资源等差异
- **建议:**
- 在 README 中补充各编排文件的用途说明和使用场景
- 考虑合并为单一 compose 文件 + profiles,或保持多文件但统一 `.env` 参数化
### [中] Claude Code 版本在 download-packages.sh 中滞后 -- **[已解决]**
- **位置:** 原为 `download-packages.sh:33` vs `Dockerfile:18`
- **现状:** 已统一使用 `@latest` 标签,不再锁定具体版本号
- **原问题描述:**
- download-packages.sh`claude-code@2.1.87`
- Dockerfile`@anthropic-ai/claude-code@2.1.89`
- **原问题:** 下载脚本中的版本落后于 Dockerfile 实际使用的版本。如果有人先执行下载脚本再构建,会得到错误的包。
- **解决方案:** 改用 `@latest` 标签,消除版本不一致问题。每次构建自动拉取最新版。
### [中] dev-tools PATH 检测逻辑重复
- **位置:** `entrypoint.sh:19-29`(运行时 export vs `entrypoint.sh:32-40`profile.d 写入)
- **现状:** 开发工具目录检测逻辑出现 2 次(单一 entrypoint.sh 内:一次 export 一次写入 profile.d)。原为 4 处(两个 entrypoint 各两次),归档 entrypoint-test.sh 后已减少至 2 处。
- **问题:** 违反 DRY 原则。新增一种工具类型需要修改 2 处。
- **建议:** 抽取为函数或独立脚本:
```bash
# /opt/lib/dev-tools.sh
setup_dev_paths() {
local profile=""
[ -d /root/.cargo/bin ] && { export PATH="/root/.cargo/bin:$PATH"; profile+="..."; }
# ...
[ -n "$profile" ] && echo "$profile" > /etc/profile.d/dev-tools.sh
}
```
### [低] packages/ 目录包含未在 Dockerfile 中使用的包
- **位置:** `packages/go1.26.1.linux-amd64.tar.gz`, `packages/rust-1.94.1-x86_64-unknown-linux-musl.tar.xz`
- **现状:** packages/ 目录中有 Go 和 Rust 的 musl 构建包,但 Dockerfile 仅安装了 Node.js + npm 包
- **问题:**
1. 占用 ~247MB 磁盘空间
2. download-packages.sh 也没有下载这两个包的步骤(说明可能是手动放入的)
3. PACKAGES.md 不存在(Alpine 版缺少此文档),无法确认这些包的用途
- **建议:**
- 如果是为"开发工具外挂"模式准备的:在文档中明确说明
- 如果不再需要:清理掉以减小仓库体积
- 补充 PACKAGES.md 说明软件包策略
### [低] entrypoint-test.sh 中的 Claude Code 别名策略不一致
- **位置:** `entrypoint-test.sh:65` vs `entrypoint-test.sh:76`
- **现状:**
- developer 用户:`alias claude='claude --dangerously-skip-permissions'`
- root 用户:`alias claude='claude --allow-dangerously-skip-permissions'`
- **问题:**
1. root 用 `--allow-dangerously-skip-permissions`developer 用 `--dangerously-skip-permissions`,参数不同但效果类似,容易混淆
2. 注释说"root 禁止 --dangerously-skip-permissions",但这应该是 Claude Code 对 root 用户的限制而非 CLI 参数限制
3. 这个别名仅在 bashrc 中,非交互式 shell(如 `docker exec` 执行命令)不会加载
- **建议:** 统一别名策略或在注释中更清晰地解释原因差异。考虑用 wrapper 脚本替代 alias 以覆盖所有调用场景。
### [低] ttyd-session.sh 的 CHOICE 输入无超时
- **位置:** `ttyd-session.sh:37`
- **现状:** `read -p "session: " CHOICE` 无超时设置
- **问题:** 如果用户打开 Web 终端但不输入选择,read 会一直阻塞。在自动化场景或意外断开的情况下可能导致僵尸进程。
- **建议:** 添加 `-t 30` 超时(30秒),超时后自动选择 default session。
---
## 架构改进路线图
### P0 -- 紧急(影响安全与可维护性)
| 序号 | 改进项 | 工作量 | 说明 |
|------|--------|--------|------|
| 1 | entrypoint 配置驱动重构 | 3h → **降低优先级** | 单 entrypoint 场景下紧迫性下降。当前 entrypoint.sh + Dockerfile.flux 扩展模式已满足需求,配置驱动重构可作为 P2 优化项储备 |
| 2 | 凭据外部化管理 | **[已完成]** | 所有密码/密钥已通过环境变量注入,清除源码中的硬编码 |
| 3 | auth-proxy 集成到编排体系 | 2h | auth-proxy 已归档为可选组件。如需正式启用,编写 docker-compose 或 systemd unit 确保生命周期受控 |
### P1 -- 重要(提升工程质量)
| 序号 | 改进项 | 工作量 | 说明 |
|------|--------|--------|------|
| 4 | dev-tools 检测逻辑去重 | 1h | 抽取为共享函数/脚本,消除 2 处重复(原 4 处) |
| 5 | 版本号单一数据源 | **[已完成]** | 已统一使用 @latest 标签 |
| 6 | 编排文件职责文档化 | 1h | 明确 3 个 yml 文件(yml / .flux.yml / -alpine.yml)的用途和使用场景,补充 README 说明 |
### P2 -- 优化(改善体验)
| 序号 | 改进项 | 工作量 | 说明 |
|------|--------|--------|------|
| 7 | 补充 PACKAGES.md | 0.5h | 说明 Alpine 版的包策略(含 Go/Rust 预留包) |
| 8 | 清理冗余包或文档化 | 0.25h | 决定 packages/ 中 Go/Rust 包的去留 |
| 9 | ttyd-session 超时保护 | 0.15h | read 添加超时 |
| 10 | Claude Code alias 统一 | 0.25h | 明确策略或改为 wrapper 脚本 |
---
## 两版本协同改进建议
由于 WorkPod Ubuntu 版依赖 Alpine 版的 entrypoint 脚本,两个版本的改进应协调进行:
### 共享资产清单
| 资产 | 当前归属 | 建议归属 |
|------|---------|---------|
| entrypoint.sh (核心逻辑) | Alpine 版(Ubuntu 版引用) | 提取为共享模块 |
| ttyd-session.sh | Alpine 版(Ubuntu 版引用) | 提取为共享模块 |
| PACKAGES.md | 仅 Ubuntu 版有 | 两版本都应有 |
| auth-proxy.js | Alpine 版(独立运行) | 可供两版本共用 |
| ISSUES.md | 仅 Alpine 版有 | Ubuntu 版也应建立 |
### 推荐的共享方案
```
workpod-common/ # 新建共享仓库或目录
├── entrypoint-core.sh # 公共逻辑(信号处理、sshd、健康检查)
├── ttyd-session.sh # 会话管理(已有,可直接复用)
├── lib-dev-tools.sh # 开发工具检测函数
└── versions.env # 版本号定义(NODE_VERSION=, CLAUDE_CODE_VERSION= ...
workpod/ # Ubuntu 版
├── entrypoint.sh # source core + Ubuntu 特定逻辑
└── Dockerfile # ubuntu 构建
workpod-alpine/ # Alpine 版
├── entrypoint.sh # source core + Alpine 特定逻辑
├── entrypoint-test.sh # source core + test 实例特定逻辑
└── Dockerfile # alpine 多阶段构建
```
---
## 总结评价
WorkPod 的架构质量持续改善。多阶段构建、开发工具外挂设计、ttyd-session 解耦、完整的问题记录都是亮点。~436MB 的镜像是务实的选择 -- 在功能完备性和体积之间取得了良好平衡。
本次审核中,多项历史问题已得到解决或修复:
- **entrypoint 膨胀问题 [已解决]**:归档 entrypoint-test.sh,统一单一 entrypoint.sh + Dockerfile.flux 扩展模式
- **安全凭据硬编码 [已修复]**:统一通过环境变量注入
- **Claude Code 版本滞后 [已解决]**:改用 @latest 标签
当前架构已从"多实例复制 entrypoint"模式演进为"单入口 + 构建扩展"模式,可维护性显著提升。P0-1(entrypoint 配置驱动重构)的紧迫性随之降低,可作为 P2 优化项储备。
安全层面,auth-proxy.js 已归档至 `_archive/` 作为可选组件保留。如需正式启用认证层,建议按 P0-3 方案集成到编排体系中。
整体而言,WorkPod 已整合为主目录项目,Alpine 作为基础镜像方案继续演进,Flux 等项目实例通过 Dockerfile.flux 按需扩展。