Files
workpod/docs/03-运维/开发环境搭建手册.md
T

1031 lines
36 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WorkPod 开发环境容器搭建手册
> 版本:1.1 | 更新日期:2026-04-07
> 用途:运维 AI 按此文档执行,为任意项目快速搭建完整的 Docker 开发环境
---
## 0. 设计原则
| 原则 | 说明 |
|------|------|
| **挂载优先** | 代理工具/知识库/配置全部从宿主机挂载,不写入镜像 |
| **信息隔离** | 每个容器只挂载该项目相关的配置和文档,禁止无关账号/服务器信息 |
| **可复用** | 一套模板适用于 flux/suke/lab/case 等任何项目 |
| **声明式** | 配置即环境,改 YAML 即换环境 |
| **持久化** | home 目录独立挂载,重建容器不丢配置 |
### 架构总览
```
┌─ 宿主机 (Windows) ─────────────────────────────────────────────┐
│ │
│ E:/wk-oth/rust-work/dist-Linux/ │
│ ├── mysql-proxy ───┐ │
│ ├── ssh-proxy ───┤ │
│ ├── redis-proxy ───┼──→ [挂载 ro] → 容器 /usr/local/bin/ │
│ └── mongo-proxy ───┘ │
│ │
│ C:/Users/{user}/.ssh/id_ed25519 ──→ [挂载 ro] → /root/.ssh/ │
│ │
│ E:/wk-flux/ ─────────→ [挂载] → 容器 /workspace │
│ │
│ workpod/dev-envs/{project}/ │
│ ├── servers.yaml ──→ [挂载 ro] → /root/.dev-env/servers.yaml │
│ ├── databases.yaml ──→ [挂载 ro] → /root/.dev-env/databases.yaml │
│ ├── norms.md ──→ [挂载 ro] → /root/.dev-env/norms.md │
│ ├── ssh-proxy.toml ──→ [挂载 ro] → /root/.dev-env/ssh-proxy.toml │
│ ├── mysql-proxy.toml ──→ [挂载 ro] → /root/.dev-env/mysql-proxy.toml│
│ ├── redis-proxy.toml ──→ [挂载 ro] → /root/.dev-env/redis-proxy.toml│
│ ├── docs/ ──→ [挂载 ro] → /root/.dev-env/docs/ │
│ └── claude/ ──→ [挂载 ro] → /root/.dev-env/claude/ │
│ ├── CLAUDE.md │
│ └── settings.local.json │
│ │
│ workpod/data/home/{project}-dev/ ──→ [挂载 rw] → /root │
│ ├── .gitconfig │
│ ├── .bashrc ← claude wrapper + 代理自动启动 │
│ ├── .claude/ ← Claude Code 运行时数据 │
│ └── ... │
│ │
│ instances/{project}/.env ──→ ANTHROPIC_AUTH_TOKEN=xxx │
│ │
└────────────────────────────────────────────────────────────────┘
```
---
## 1. 快速搭建(以 Flux 项目为例)
### 1.1 创建项目环境目录
```bash
# 在 workpod 下创建项目级配置目录
mkdir -p E:/wk-lab/workpod/dev-envs/flux/claude
mkdir -p E:/wk-lab/workpod/data/home/flux-dev
# 复制代理工具(或符号链接)
cp E:/wk-oth/rust-work/dist-Linux/* E:/wk-lab/workpod/dev-envs/flux/bin/
# 或(推荐,自动同步最新版):
# ln -s E:/wk-oth/rust-work/dist-Linux E:/wk-lab/workpod/dev-envs/flux/bin
```
### 1.2 编写项目配置文件
以下 4 个文件是每个项目的**必需配置**,按实际修改即可:
#### `dev-envs/flux/servers.yaml` — 服务器信息
```yaml
# Flux 项目服务器清单 (仅含 Flux 相关,信息隔离)
project: flux
description: 贷款撮合平台
last_updated: "2026-04-07"
servers:
# === 生产环境 ===
- name: prod_baiyarong
display: 百雅融生产服
host: 101.201.107.111
port: 22
user: root
deploy_dir: /opt/
jdk_path: /opt/app/
services:
- name: flux-api
dir: /opt/flux-api
restart: "cd /opt/flux-api && bash bin/restart.sh"
health_check: "curl -sf http://localhost:6080/partnerapi/ping"
- name: flux-admin
dir: /opt/flux-admin
- name: flux-mock
dir: /opt/flux-mock
- name: file-server
dir: /opt/file-server
port: 8071
domains:
- api.baiyarong.cn
- r.baiyarong.cn
# === 测试环境 (flux_dev) ===
- name: dev_test
display: 测试机 (flux_dev)
host: 39.99.243.191
port: 22
user: root
deploy_dir: /opt/
docker: true
jdk_path: /opt/jdk-25
services:
- name: mysql
port: 3306
image: mysql:8.0
- name: redis
port: 6379
image: redis:7.4
password: <TEST_REDIS_PASSWORD>
- name: workpod-1
web_port: 7681
domain: wk.1216.top
- name: workpod-alpine
web_port: 7683
domain: wk2.1216.top
domains:
- fluxapi.1216.top
- flux.1216.top
- wk.1216.top
```
> **注意**: ssh-proxy.toml 中的 server name 用短名(如 `byr_pro`),与 servers.yaml 的显示名不同。
> 这是正常的:ssh-proxy.toml 的 `name` 是内部连接标识符,servers.yaml 的 `name` 是人工可读名称。
#### `dev-envs/flux/databases.yaml` — 数据库连接
```yaml
# Flux 项目数据库连接 (仅含 Flux 相关)
project: flux
last_updated: "2026-04-07"
mysql:
# --- 测试环境 ---
- name: flux_dev
env: test
host: 39.99.243.191
port: 3306
database: flux_dev
users:
- username: root
password: <TEST_DB_ROOT_PASSWORD>
role: admin
- username: u_flux
password: <TEST_DB_APP_PASSWORD>
role: app
proxy_name: flux_dev # mysql-proxy 连接名
# --- 生产环境 ---
- name: flux_prox
env: prod
host: 101.201.107.111
port: 3306
database: flux_prox
users:
- username: root
password: <PROD_DB_ROOT_PASSWORD>
role: admin
proxy_name: flux_prox
- name: flux_mp
env: prod
host: 101.201.107.111
port: 3306
database: flux_mp
users:
- username: u_mp
password: <PROD_MP_APP_PASSWORD>
role: app
note: 小程序数据库
redis:
- name: flux_dev
env: test
host: 39.99.243.191
port: 6379
password: <TEST_REDIS_PASSWORD>
proxy_name: flux_dev # redis-proxy 连接名
feishu_bot:
workspace: flux
app_id: <FEISHU_APP_ID>
app_secret: <FEISHU_APP_SECRET>
open_platform: https://open.feishu.cn/app/
# === 代理工具速查 ===
# mysql-proxy cli -c flux_dev -e "SQL" # 查询
# mysql-proxy cli -c flux_dev -e "SQL" -F json # JSON输出
# mysql-proxy cli -c flux_dev -e "DML" -x # 执行写入
# ssh-proxy exec -n flux_dev -c "command" # 远程执行
# ssh-proxy exec -n flux_dev -c "command" -F json # JSON输出
# redis-proxy get -c flux_dev -k "key" # 取值
# redis-proxy run -c flux_dev -C "KEYS" -a "user:*" # 通用命令
```
#### `dev-envs/flux/norms.md` — 开发规范摘要
```markdown
# Flux 项目开发规范
## Git 提交规范
格式:`<类型>: <简述>`
类型:新增 | 修复 | 优化 | 重构
禁止:
- 英文提交信息
- Co-Authored-By 尾巴
- 提及工具名称
## 技术栈
| 模块 | 技术 | 启动命令 |
|------|------|---------|
| flux-api | Java 17 + Redkale + Maven | cmd /c bin\restart.bat |
| flux-admin | Vue 3 + Arco Design + Vite + bun | bun run dev |
| flux-uniapp | UniApp + Vite | bun run dev:h5 |
| flux-mock | Go | go run *.go |
| flux-test | Go | go run test_quick.go {channel} |
| file-server | Go | go run *.go |
## 代码审查要点
- Redkale FilterNode 使用规范(见 .kms/Redkale使用易错点.md
- JSON 字段映射 @ConvertColumn 注意事项
- SQL 慢查询优化(见 .kms/MySQL慢查询分析.md
## 命名规范
前缀: flux-{type}-{name}
类型后缀: -api(后端) | -admin(管理后台) | -web(用户端) | -app(移动端)
## 高危操作提醒
- 改 Docker/系统配置: 先备份,改完验证语法,再重启
- 删数据库/容器: 先确认备份和影响范围
- 生产操作: 必须先在测试环境验证
```
#### `dev-envs/flux/claude/CLAUDE.md` — Claude Code 项目指令
```markdown
# Flux 开发环境
> 当前在 ws-flux-dev 容器内,工作目录 /workspace = E:/wk-flux
## 项目概述
贷款撮合平台,核心模块:
- **flux-api**: 后端 API (Java 17 + Redkale)
- **flux-admin**: 管理后台 (Vue 3 + Arco Design)
- **flux-uniapp**: H5 前端 (UniApp)
- **flux-mock**: 三方模拟服务 (Go)
- **flux-test**: 业务链测试 (Go)
- **file-server**: 文件服务 (Go)
## 可用工具
### 代理工具(已挂载到 /usr/local/bin/
```bash
mysql-proxy cli -c flux_dev -e "SQL" # MySQL 查询
ssh-proxy exec -n flux_dev -c "command" # SSH 远程执行
redis-proxy get -c flux_dev -k "key" # Redis 操作
mongo-proxy find -c suke_dev -C collection # MongoDB 查询
fet GET https://api.example.com # HTTP 请求
```
### 连接信息速查
详见 `/root/.dev-env/servers.yaml``/root/.dev-env/databases.yaml`
## 开发命令
```bash
# flux-api (Redkale/Java)
cd /workspace/flux-api && mvn clean package
cmd /c bin\restart.bat
# flux-admin (Vue3/bun)
cd /workspace/flux-admin && bun install && bun run dev
# flux-uniapp (UniApp)
cd /workspace/flux-uniapp && npm install && npm run dev:h5
# Go 服务
cd /workspace/flux-mock && go run *.go
cd /workspace/flux-test && go run test_quick.go qulaijie
```
## 规范
- Git 提交: `<类型>: <简述>` 类型=新增|修复|优化|重构
- 禁止英文提交、禁止 Co-Authored-By 尾巴
- 详见 `/root/.dev-env/norms.md`
## 开发规范
> **唯一事实来源**: `/root/.dev-env/norms.md`
> 本文件不重复规范内容,避免维护不一致。
执行任务前先读取 norms.md,关键规则:
- Git 提交、代码审查、命名规范、高危操作检查清单
## 项目知识库
Flux 专属文档位于 `/root/.dev-env/docs/`
| 文件 | 用途 |
|------|------|
| Redkale使用易错点.md | **flux-api 必读** — 框架踩坑记录 |
| MySQL慢查询分析.md | SQL 慢查询优化参考 |
```
#### `dev-envs/flux/claude/settings.local.json` — Claude Code 权限
```json
{
"permissions": {
"allow": [
"Bash(mysql-proxy *)",
"Bash(ssh-proxy *)",
"Bash(redis-proxy *)",
"Bash(mongo-proxy *)",
"Bash(mvn *)",
"Bash(java *)",
"Bash(javac *)",
"Bash(go *)",
"Bash(bun *)",
"Bash(npm *)",
"Bash(node *)",
"Bash(cmd *)",
"Bash(git *)",
"Bash(docker *)",
"Bash(curl *)",
"Bash(wget *)",
"Bash(cat *)",
"Bash(ls *)",
"Bash(grep *)",
"Bash(find *)",
"Read",
"Write",
"Edit"
],
"deny": []
}
}
```
> **注意**: `fet` 暂未挂载(Linux 版未编译),故不在权限列表中。编译后需添加 `Bash(fet *)`。
### 1.3 配置持久化 Home 目录
`data/home/flux-dev/.gitconfig`:
```ini
[user]
name = 绝尘
email = dev@1216.top
[core]
autocrlf = input
quotepath = false
[push]
default = simple
```
### 1.4 生成 Compose 文件
从模板生成 `instances/flux/docker-compose.yml`
```yaml
services:
ws-flux-dev:
build:
context: ../../
dockerfile: instances/flux/Dockerfile
image: ws-flux-dev:latest
container_name: ws-flux-dev
hostname: ws-flux-dev
restart: unless-stopped
ports:
- "2201:22" # SSH
- "7701:7681" # Web 终端 ttyd
volumes:
# ===== 项目源码 =====
- E:/wk-flux:/workspace
# ===== 开发工具 (JDK/Maven) =====
- D:/Java/jdk-musl-17:/opt/jdk-musl-17:ro
- D:/Java/maven-mvnd-3.9.14:/opt/maven-mvnd-3.9.14:ro
# ===== 代理工具 (Linux static binaries) =====
- E:/wk-oth/rust-work/dist-Linux/mysql-proxy:/usr/local/bin/mysql-proxy:ro
- E:/wk-oth/rust-work/dist-Linux/ssh-proxy:/usr/local/bin/ssh-proxy:ro
- E:/wk-oth/rust-work/dist-Linux/redis-proxy:/usr/local/bin/redis-proxy:ro
- E:/wk-oth/rust-work/dist-Linux/mongo-proxy:/usr/local/bin/mongo-proxy:ro
# ===== SSH 密钥 + 代理配置 (仅该项目相关) =====
- C:/Users/{user}/.ssh/id_ed25519:/root/.ssh/id_ed25519:ro
- ../../dev-envs/flux/ssh-proxy.toml:/root/.dev-env/ssh-proxy.toml:ro
- ../../dev-envs/flux/mysql-proxy.toml:/root/.dev-env/mysql-proxy.toml:ro
- ../../dev-envs/flux/redis-proxy.toml:/root/.dev-env/redis-proxy.toml:ro
# ===== 项目级配置 (只读挂载) =====
- ../../dev-envs/flux/servers.yaml:/root/.dev-env/servers.yaml:ro
- ../../dev-envs/flux/databases.yaml:/root/.dev-env/databases.yaml:ro
- ../../dev-envs/flux/norms.md:/root/.dev-env/norms.md:ro
- ../../dev-envs/flux/docs:/root/.dev-env/docs:ro
- ../../dev-envs/flux/claude/CLAUDE.md:/root/.dev-env/claude/CLAUDE.md:ro
- ../../dev-envs/flux/claude/settings.local.json:/root/.dev-env/claude/settings.local.json:ro
# ===== 持久化 Home (读写挂载) =====
- ../../data/home/flux-dev:/root
environment:
- TZ=Asia/Shanghai
- TERM=xterm-256color
- ROOT_PASSWORD=${ROOT_PASSWORD:-workpod123}
- TTYD_CREDENTIALS=${TTYD_CREDENTIALS:-jc:1234567}
- WORKPOD_PROJECT=flux
- JAVA_HOME=/opt/jdk-musl-17
- MAVEN_HOME=/opt/maven-mvnd-3.9.14
# === Claude Code (智谱 AI, 从 .env 读取密钥) ===
- ANTHROPIC_BASE_URL=https://open.bigmodel.cn/api/anthropic
- ANTHROPIC_API_KEY=${ANTHROPIC_AUTH_TOKEN}
- ANTHROPIC_DEFAULT_SONNET_MODEL=glm-5v-turbo
- ANTHROPIC_DEFAULT_OPUS_MODEL=glm-5.1
- ANTHROPIC_DEFAULT_HAIKU_MODEL=glm-4.5-air
deploy:
resources:
limits:
memory: 4G
reservations:
memory: 1G
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD-SHELL", "netstat -tlnp 2>/dev/null | grep -qE ':(22|7681)\\b' || exit 1"]
interval: 30s
timeout: 5s
start_period: 15s
retries: 3
working_dir: /workspace
tty: true
stdin_open: true
networks:
default:
external: true
name: workpod-{project}-network
```
> **`.env` 文件**: 在 `instances/{project}/` 下创建 `.env`,存放敏感信息(不进 git):
> ```bash
> # Claude Code API Key (智谱 AI)
> ANTHROPIC_AUTH_TOKEN=your_token_here
> ```
### 1.5 启动与验证
```bash
# 构建并启动
cd E:/wk-lab/workpod
docker build -t ws-flux-dev:latest -f instances/flux/Dockerfile .
docker compose -f instances/flux/docker-compose.yml up -d
# 验证 1: 代理工具
MSYS_NO_PATHCONV=1 docker exec ws-flux-dev bash -lc '
echo "=== 代理工具 ==="
mysql-proxy --version && echo " ✓ mysql-proxy"
ssh-proxy --version && echo " ✓ ssh-proxy"
redis-proxy --version && echo " ✓ redis-proxy"
mongo-proxy --version && echo " ✓ mongo-proxy"
echo ""
echo "=== 项目知识库 (仅该项目相关) ==="
ls /root/.dev-env/docs/
echo ""
echo "=== 项目配置 ==="
cat /root/.dev-env/servers.yaml | head -5
cat /root/.dev-env/databases.yaml | head -5
echo ""
echo "=== Git 配置 ==="
git config --global --list
'
# 验证 2: Web 终端访问
# 打开 http://localhost:7701 用户 jc / 1234567
# 验证 3: SSH 访问
ssh root@localhost -p 2201 # 密码 workpod123
```
---
## 2. 为新项目快速搭建(模板流程)
当需要为新项目(如 suke、lab、case)搭建开发环境时,只需 **3 步**
### Step 1: 复制模板目录
```bash
# 以 suke 项目为例
PROJECT=suke
SSH_PORT=2202
WEB_PORT=7702
PROJECT_PATH=E:/wk-suke
mkdir -p E:/wk-lab/workpod/dev-envs/$PROJECT/claude
mkdir -p E:/wk-lab/workpod/data/home/$PROJECT-dev
```
### Step 2: 编写 4 个配置文件
复制 flux 的配置文件作为模板,修改以下内容:
| 文件 | 需修改项 |
|------|---------|
| `servers.yaml` | 该项目的服务器列表、部署路径、域名 |
| `databases.yaml` | 该项目的数据库连接、Redis、第三方密钥 |
| `norms.md` | 该项目的技术栈、启动命令、特殊规范 |
| `claude/CLAUDE.md` | 项目描述、模块说明、可用命令 |
### Step 3: 生成并启动 compose
从上面的 compose 模板复制,修改:
- `container_name` / `hostname`
- `ports` (SSH/Web)
- `volumes` 中的项目路径和 dev-envs 路径
- `environment` 中的项目特定变量
- `networks.name`
```bash
# 一键启动
docker compose -f instances/$PROJECT/docker-compose.yml up -d
```
---
## 3. 挂载资源清单
### 3.1 代理工具(只读挂载)
| 工具 | 宿主机源 | 大小 | 容器路径 | 用途 |
|------|---------|------|---------|------|
| mysql-proxy | `dist-Linux/mysql-proxy` | 8.9MB | `/usr/local/bin/mysql-proxy` | MySQL 查询代理 (:3307) |
| ssh-proxy | `dist-Linux/ssh-proxy` | 4.6MB | `/usr/local/bin/ssh-proxy` | SSH 命令代理 (:3308) |
| redis-proxy | `dist-Linux/redis-proxy` | 3.4MB | `/usr/local/bin/redis-proxy` | Redis 命令代理 (:3310) |
| mongo-proxy | `dist-Linux/mongo-proxy` | 6.4MB | `/usr/local/bin/mongo-proxy` | MongoDB 代理 (:3309) |
> 全部为 **static-pie** 链接,无动态依赖,兼容 Alpine musl。
### 3.1b SSH 密钥 + 代理配置(只读挂载)
| 资源 | 宿主机源 | 容器路径 | 用途 |
|------|---------|---------|------|
| SSH 私钥 | `C:/Users/{user}/.ssh/id_ed25519` | `/root/.ssh/id_ed25519` | ssh-proxy 认证远程服务器 |
| ssh-proxy.toml | `dev-envs/{project}/ssh-proxy.toml` | `/root/.dev-env/ssh-proxy.toml` | SSH 代理服务配置 (仅该项目服务器) |
| mysql-proxy.toml | `dev-envs/{project}/mysql-proxy.toml` | `/root/.dev-env/mysql-proxy.toml` | MySQL 代理配置 (仅该项目连接) |
| redis-proxy.toml | `dev-envs/{project}/redis-proxy.toml` | `/root/.dev-env/redis-proxy.toml` | Redis 代理配置 (仅该项目连接) |
> **信息隔离**: 每个 `.toml` 只包含当前项目的连接/服务器,禁止混入其他项目。
> **fet 待补充**: 目前仅有 Windows 版 (`PE32+`),需要交叉编译 Linux 版。编译命令:
> ```bash
> cd E:/wk-oth/rust-work/fet
> rustup target add x86_64-unknown-linux-musl
> cargo build --release --target x86_64-unknown-linux-musl
> ```
### 3.2 项目专属知识库(只读挂载)
> **重要原则**: 只挂载与当前项目相关的文档,避免无关信息干扰和误操作。
宿主机: `workpod/dev-envs/{project}/docs/` → 容器: `/root/.dev-env/docs/`
从全局 KMS 中**按需筛选**该项目需要的文档复制到此目录:
| 文件 | 来源 | 适用项目 |
|------|------|---------|
| Redkale使用易错点.md | ~/.claude/kms/ | flux (flux-api 用 Redkale) |
| MySQL慢查询分析.md | ~/.claude/kms/ | 有 MySQL 的项目 |
| 其他框架/业务文档 | ~/.claude/kms/ 或项目自身 | 按需 |
**禁止挂载到容器的内容**:
- `账号信息.md` — 包含所有项目密码,有泄露和误操作风险
- 其他项目的服务器/数据库信息 — 避免连接错误环境
### 3.3 项目级配置(只读挂载)
宿主机: `workpod/dev-envs/{project}/` → 容器: `/root/.dev-env/`
| 文件 | 用途 |
|------|------|
| servers.yaml | 该项目涉及的服务器 IP/端口/用途/域名 |
| databases.yaml | MySQL/Redis 连接信息 + 第三方密钥 |
| norms.md | 开发规范摘要 (Git/代码审查/命名/高危操作) |
| claude/CLAUDE.md | Claude Code 项目指令 |
| claude/settings.local.json | Claude Code 权限配置 |
### 3.4 持久化 Home(读写挂载)
宿主机: `workpod/data/home/{project}-dev/` → 容器: `/root`
> **只存放运行时产生的文件**,不存放项目配置(配置在 `dev-envs/` 中)
| 文件 | 来源 | 说明 |
|------|------|------|
| `.gitconfig` | 手动配置 | Git 用户名/邮箱/Gitea 凭据 |
| `.git-credentials-gitea` | 手动配置 | Gitea 密码 (权限 600) |
| **`.bashrc`** | **手动编写** | **★ claude wrapper + 代理自动启动 (见第 5 节)** |
| `.claude/` | 自动产生 | Claude Code 运行时数据 (sessions/settings/history) |
| `.bun/` | 容器内安装 | bun 运行时安装的包 |
| `.npm/` | 容器内产生 | npm 缓存 |
| `.chelper/` | 容器内产生 | coding-helper 数据 |
| `.ash_history` | 自动产生 | 命令历史 |
### 3.4b 自定义技能(读写挂载)
> **不同项目容器需要不同的技能内容**,按项目需求选择性同步。
宿主机: `~/.claude/skills/{name}/skill.md` → 容器: `/root/.claude/skills/{name}/skill.md`
技能文件放在 `data/home/{project}-dev/.claude/skills/` 下,随 `/root` 持久化挂载自动同步。
#### 技能清单
| 技能名 | 触发词 | 用途 | 适用项目 |
|--------|--------|------|---------|
| **commit** | commit / 提交 | Git 提交规范(中文、类型前缀) | 所有项目 |
| **review** | review / 审查 | 代码审查(Redkale/Java/Go/SQL 风格偏好) | Java/Go 项目 |
| **taskhub** | taskhub / 任务 | 任务管理(ID 规范、todo.md 同步看板) | 所有项目 |
#### 技能来源与同步方式
```bash
# 从本机复制到指定项目的容器 home
cp ~/.claude/skills/commit/skill.md data/home/flux-dev/.claude/skills/commit/
cp ~/.claude/skills/review/skill.md data/home/flux-dev/.claude/skills/review/
cp ~/.claude/skills/taskhub/skill.md data/home/flux-dev/.claude/skills/taskhub/
# 验证
docker exec {container} ls /root/.claude/skills/*/skill.md
```
#### 项目差异示例
| 项目 | 推荐技能 | 说明 |
|------|----------|------|
| flux (Java+Redkale) | commit + review + taskhub | review 含 Redkale 易错点 |
| suke (Go) | commit + review + taskhub | review 侧重 Go 规范 |
| lab (Node) | commit + taskhub | 可不需要 review(或简化版) |
> **原则**: 技能内容应匹配项目技术栈。Java 项目的 review 不应包含 Go 规则,反之亦然。
#### 各项目技能差异示例
**review 技能按项目定制**
| 项目 | tech stack | review 应包含 | review 不应包含 |
|------|------------|---------------|-----------------|
| flux | Java 17 + Redkale | FilterNode 用法、`@ConvertColumn`、Entity 承担逻辑 | Go 惯例、Node 规范 |
| suke | Go + Gin | `if err != nil``gofmt`、接口设计 | Redkale 注解、Java 命名 |
| lab | Node.js + Vue | ESLint 规则、异步模式、TypeScript 类型 | Java/Go 编译规范 |
**操作方式**:为每个项目维护独立的 `skill.md`,从通用模板复制后按技术栈裁剪。
```bash
# 示例: 为 suke 项目定制 review 技能 (去除 Java/Redkale 部分)
cp ~/.claude/skills/review/skill.md data/home/suke-dev/.claude/skills/review/
# 然后编辑 data/home/suke-dev/.claude/skills/review/skill.md
# 删除 Redkale/Java 章节,保留 Go + 通用审查流程
```
---
## 4. 容器内工具安装(重建后需重新执行)
> 基础镜像只包含最小工具集(curl/git/tmux/ttyd/node)。以下工具需要在容器启动后安装。
> 安装命令写入 `.bashrc` 可实现自动安装,但首次仍需手动执行。
### 4.1 一键安装脚本
在宿主机执行(或进入容器后执行):
```bash
MSYS_NO_PATHCONV=1 docker exec {container_name} bash -c '
# ===== 1. 系统工具 (apk) =====
apk add --no-cache vim jq htop
# ===== 2. Bun (JS 包管理器) =====
curl -fsSL https://bun.sh/install | bash
# ===== 3. 持久化 bun PATH (所有 shell 生效) =====
echo "export BUN_INSTALL=\"\$HOME/.bun\"" >> /root/.bashrc
echo "export PATH=\"\$BUN_INSTALL/bin:\$PATH\"" >> /root/.bashrc
cat > /etc/profile.d/bun.sh << "EOF"
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"
EOF
# ===== 4. Go (如项目需要) =====
# 方案 A: apk 安装 (Alpine 仓库版)
# apk add go
# 方案 B: 从官方下载指定版本 (推荐)
# wget -q https://go.dev/dl/go1.24.1.linux-amd64.tar.gz \
# && tar -C /usr/local -xzf go1.24.1.linux-amd64.tar.gz \
# && rm go1.24.1.linux-amd64.tar.gz
'
```
### 4.2 工具清单与用途
| 工具 | 版本 | 大小 | 安装命令 | 用途 | 适用项目 |
|------|------|------|---------|------|---------|
| **vim** | 9.2 | **3.2M** (包: 9M) | `apk add vim` | 文件编辑器 | 所有项目 |
| **jq** | 1.8.1 | **28K** (包: 9M) | `apk add jq` | JSON 处理/查询 | 所有项目 |
| **htop** | 3.4 | **272K** (包: 9M) | `apk add htop` | 系统资源监控 | 所有项目 |
| **bun** | 1.3.x | **89.8M** | 官方安装脚本 | JS/TS 包管理器 | flux-admin, flux-uniapp |
| **Go** | 1.24+ | ~250M (官方tar) | `apk add go` 或官方下载 | Go 编译运行 | flux-test, flux-mock, file-server |
> 注: vim/jq/htop 三者共享 apk 基础依赖 (~9M),一起安装不会额外增加太多空间。
#### 全部工具大小汇总
| 类别 | 工具 | 大小 | 来源 |
|------|------|------|------|
| **基础镜像内置** | Node.js v24 + npm | **~200MB** | Dockerfile 多阶段构建 |
| | ttyd 1.7.7 | ~2MB | Dockerfile |
| | git 2.52 | **2.9M** | Dockerfile |
| | tmux 3.6 | **808K** | Dockerfile |
| | curl / wget / nc / tree / less | <1MB | Dockerfile |
| **代理工具 (挂载 ro)** | mysql-proxy | **8.9M** | dist-Linux/ |
| | ssh-proxy | **4.6M** | dist-Linux/ |
| | redis-proxy | **3.4M** | dist-Linux/ |
| | mongo-proxy | **6.3M** | dist-Linux/ |
| | 小计 | **23.2M** | |
| **开发工具 (挂载 ro)** | JDK 17 musl | **363.2M** | D:/Java/jdk-musl-17 |
| | Maven mvnd-3.9.14 | **10.5M** | D:/Java/maven-mvnd-3.9.14 |
| | 小计 | **373.7M** | |
| **容器内安装 (重建丢失)** | vim 9.2 | **3.2M** | `apk add vim` |
| | jq 1.8.1 | **28K** | `apk add jq` |
| | htop 3.4 | **272K** | `apk add htop` |
| | bun 1.3.x | **89.8M** | 官方安装脚本 |
| | Go (如需) | ~250M | `apk add go` 或 tar |
| | 小计 (不含 Go) | **~96.5M** | |
**容器镜像写层**: 基础 ~45KB + 运行时数据 (~100MB 含 bun/npm 缓存等)
### 4.3 安装验证
```bash
MSYS_NO_PATHCONV=1 docker exec {container_name} bash -lc '
for cmd in vim jq htop bun go; do
v=$($cmd --version 2>/dev/null | head -1)
[ -n "$v" ] && echo "✓ $cmd: $v" || echo "✗ $cmd: 未安装"
done
'
```
### 4.4 固化到镜像(可选)
如果不想每次重建都重装,可将常用工具加入基础镜像 Dockerfile
```dockerfile
# 在现有 RUN 指令后追加
RUN apk add --no-cache vim jq htop
```
---
## 5. 容器内 Shell 配置 (.bashrc)
> **关键**: 以下两个函数是容器内 Claude Code 和代理工具正常工作的核心。
### 5.1 claude wrapper(绕过 OAuth
容器内 Claude Code 默认走 OAuth 登录流程,在无浏览器环境下会卡住。解决方案:用 `--bare` 模式强制走 API Key 认证,并通过 wrapper 函数补回被跳过的功能。
```bash
# data/home/{project}-dev/.bashrc
# claude wrapper: use --bare for API key auth, restore CLAUDE.md + settings
claude() {
local _args=()
_args+=(--bare)
# CLAUDE.md auto-discovery (bare skips it)
[ -f /root/.dev-env/claude/CLAUDE.md ] && _args+=(--add-dir /root/.dev-env/claude)
# project settings
[ -f /root/.dev-env/claude/settings.local.json ] && _args+=(--settings /root/.dev-env/claude/settings.local.json)
# pass through all user args
command claude "${_args[@]}" "$@"
}
```
**原理**:
- `--bare` 模式:只认 `ANTHROPIC_API_KEY`,不走 OAuth/keychain
- `--bare` 会跳过 CLAUDE.md 自动发现 → 用 `--add-dir` 手动指定
- `--bare` 不读 settings → 用 `--settings` 手动加载权限配置
### 5.2 代理服务自动启动
代理工具需要在容器内以 server 模式运行(不是 client 模式),且需要各自的 `.toml` 配置文件。
```bash
# 代理服务 (idempotent: 只在未运行时启动)
_start_proxy() {
local name=$1 bin=$2 cfgdir=$3
if pgrep -x "$bin" > /dev/null 2>&1; then return; fi
if [ -f "$cfgdir/$bin.toml" ]; then
(cd "$cfgdir" && "$bin" &>/tmp/$bin.log &)
sleep 1
fi
}
_start_proxy mysql-proxy mysql-proxy /root/.dev-env
_start_proxy redis-proxy redis-proxy /root/.dev-env
_start_proxy ssh-proxy ssh-proxy /root/.dev-env
```
**原理**:
- `pgrep -x` 确保幂等(多次 source 不重复启动)
-`/root/.dev-env/` 目录读取对应 `.toml` 启动
- 日志输出到 `/tmp/{proxy}.log` 方便排查
### 5.3 完整 .bashrc 示例
```bash
# bun (idempotent)
if [ -z "$BUN_INSTALL" ]; then
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"
fi
# 代理服务自动启动 (见 5.2)
_start_proxy() { ... } # 同上
_start_proxy mysql-proxy mysql-proxy /root/.dev-env
_start_proxy redis-proxy redis-proxy /root/.dev-env
_start_proxy ssh-proxy ssh-proxy /root/.dev-env
# claude wrapper (见 5.1)
claude() { ... } # 同上
```
---
## 6. 踩坑记录
| # | 问题 | 原因 | 解决方案 |
|---|------|------|---------|
| 1 | **Claude Code 弹出 OAuth 登录** | 容器内无浏览器,默认交互模式走 OAuth | 用 `--bare` + `ANTHROPIC_API_KEY`(见 5.1 |
| 2 | **Auth conflict 警告** | 同时设置 `ANTHROPIC_AUTH_TOKEN``ANTHROPIC_API_KEY` | compose 中只用 `ANTHROPIC_API_KEY=${ANTHROPIC_AUTH_TOKEN}` |
| 3 | **ssh-proxy/mysql-proxy 报 "No such file"** | 代理工具需要 `.toml` 配置文件才能以 server 模式启动 | 挂载项目专属 `.toml``/root/.dev-env/`(按信息隔离原则) |
| 4 | **SSH 连接失败 "Permission denied"** | ssh-proxy 需要私钥文件认证远程服务器 | 挂载宿主机 `~/.ssh/id_ed25519``/root/.ssh/` |
| 5 | **--bare 模式不读 CLAUDE.md** | bare 模式跳过自动发现机制 | wrapper 函数中加 `--add-dir` 手动指定 |
| 6 | **容器重建后代理不可用** | 代理进程在容器写层,重建丢失 | 在 `.bashrc` 中用 `_start_proxy()` 自动启动 |
| 7 | **BUN_INSTALL/PATH 重复追加** | 安装脚本被多次执行,每次都 append | 加 `[ -z "$BUN_INSTALL" ]` 幂等守卫 |
| 8 | **data/home 下出现 .dev-env/ 重复目录** | 旧版 compose 将 dev-envs 挂载到了 home 下 | 删除 `data/home/{project}-dev/.dev-env/`,确认 compose 只挂载 ro 版本 |
---
## 7. 目录结构总览
```
workpod/
├── instances/{project}/ # 容器编排
│ ├── docker-compose.yml # Compose 定义
│ ├── Dockerfile # (可选) 扩展镜像
│ └── .env # 敏感变量: ANTHROPIC_AUTH_TOKEN (不进 git)
├── dev-envs/{project}/ # ★ 项目配置 (只读挂载 → /root/.dev-env)
│ ├── servers.yaml # 服务器 IP/端口/用途
│ ├── databases.yaml # 数据库/Redis/第三方密钥
│ ├── norms.md # 开发规范 (唯一事实来源)
│ ├── ssh-proxy.toml # SSH 代理配置 (仅该项目服务器)
│ ├── mysql-proxy.toml # MySQL 代理配置 (仅该项目连接)
│ ├── redis-proxy.toml # Redis 代理配置 (仅该项目连接)
│ ├── docs/ # 仅该项目相关文档 (从 KMS 筛选)
│ └── claude/
│ ├── CLAUDE.md # Claude Code 项目指令 (引用 norms.md)
│ └── settings.local.json # Claude Code 权限
├── data/home/{project}-dev/ # 运行时数据 (读写挂载 → /root)
│ ├── .gitconfig # Git 用户 + 凭据配置
│ ├── .git-credentials-gitea # Gitea 密码 (权限 600)
│ ├── .bashrc # ★ Shell 配置 (claude wrapper + 代理启动)
│ ├── .claude/ # Claude Code 运行时数据
│ │ └── skills/ # ★ 自定义技能 (按项目需求同步,见 §3.4b)
│ │ ├── commit/skill.md # Git 提交规范 (通用)
│ │ ├── review/skill.md # 代码审查 (按技术栈定制内容)
│ │ └── taskhub/skill.md # 任务管理 (通用)
│ ├── .bun/ # bun 安装包
│ └── .ash_history # 命令历史
├── docs/03-运维/
│ ├── 部署维护手册.md
│ └── 开发环境搭建手册.md # ← 本文档
├── Dockerfile # 基础镜像构建
├── entrypoint.sh # 容器入口脚本
└── SPECS.md # 技术规格文档
```
### 职责划分
| 目录 | 挂载方式 | 内容 | 谁来维护 |
|------|---------|------|---------|
| `dev-envs/{project}/` | **只读** | 项目配置、规范、知识库 | AI / 开发者编写 |
| `data/home/{project}-dev/` | **读写** | 运行时产生的文件 | 容器自动产生 |
| `instances/{project}/` | — | Compose 编排定义 | AI 生成 |
> **禁止**: 在 `data/home/` 下放置配置文件(会导致与 dev-envs 重复或被覆盖)
---
## 附录 A: 运维 AI 执行 Checklist
新建项目开发环境时,按此清单逐项执行:
```
□ 1. 创建目录
□ mkdir -p dev-envs/{project}/claude
□ mkdir -p data/home/{project}-dev
□ 2. 编写配置文件 (8 个文件 + 知识库文档)
□ dev-envs/{project}/servers.yaml # 服务器信息 (仅该项目)
□ dev-envs/{project}/databases.yaml # 数据库连接 (仅该项目)
□ dev-envs/{project}/norms.md # 开发规范
□ dev-envs/{project}/ssh-proxy.toml # SSH 代理配置 (仅该项目服务器)
□ dev-envs/{project}/mysql-proxy.toml # MySQL 代理配置 (仅该项目连接)
□ dev-envs/{project}/redis-proxy.toml # Redis 代理配置 (仅该项目连接)
□ dev-envs/{project}/docs/ # 从 KMS 筛选该项目相关文档
□ dev-envs/{project}/claude/CLAUDE.md
□ dev-envs/{project}/claude/settings.local.json
□ 3. 配置 home
□ data/home/{project}-dev/.gitconfig
□ data/home/{project}-dev/.bashrc # ★ claude wrapper + _start_proxy (见第 5 节)
□ 4. 生成 compose + .env
□ 从模板复制 instances/{project}/docker-compose.yml
□ 修改: name/ports/volumes(项目路径+dev-envs+SSH密钥+.toml)/env/Claude变量/network
□ 创建 instances/{project}/.env # ANTHROPIC_AUTH_TOKEN (不进 git)
□ 5. 构建镜像 (如需新 Dockerfile)
□ docker build -t ws-{project}-dev:latest -f instances/{project}/Dockerfile .
□ 6. 启动容器
□ docker compose -f instances/{project}/docker-compose.yml up -d
□ 7. 安装额外工具(重建后需重新执行,见第 4 节完整命令)
□ vim + jq + htop: `apk add vim jq htop`
□ bun: `curl -fsSL https://bun.sh/install | bash` + 持久化 PATH
□ Go (如需): `apk add go` 或官方下载
□ 8. 同步自定义技能(按项目需求选择性复制,见 §3.4b)
□ mkdir -p data/home/{project}-dev/.claude/skills/{commit,review,taskhub}
□ cp ~/.claude/skills/commit/skill.md data/home/{project}-dev/.claude/skills/commit/
□ cp ~/.claude/skills/review/skill.md data/home/{project}-dev/.claude/skills/review/
□ cp ~/.claude/skills/taskhub/skill.md data/home/{project}-dev/.claude/skills/taskhub/
□ 9. 验证代理工具
□ docker exec {container} bash -c 'source ~/.bashrc && mysql-proxy cli -c flux_dev -e "SELECT 1"'
□ docker exec {container} bash -c 'source ~/.bashrc && redis-proxy get -c flux_dev -k "test_key"'
□ docker exec {container} bash -c 'source ~/.bashrc && ssh-proxy exec -n flux_dev -c "hostname"'
□ 10. 验证 Claude Code
□ docker exec {container} bash -c 'source ~/.bashrc && claude -p "say hi"'
□ 11. 验证技能
□ docker exec {container} ls /root/.claude/skills/*/skill.md
□ 12. 验证其他
□ docker exec {container} ls /root/.dev-env/docs/
□ docker exec {container} cat /root/.dev-env/servers.yaml | head -5
□ docker exec {container} git config --global --list
□ docker exec {container} vim --version | head -1
□ 浏览器打开 http://localhost:{WEB_PORT}
```
---
## 附录 B: fet 交叉编译
```bash
# 1. 添加 musl target
rustup target add x86_64-unknown-linux-musl
# 2. 交叉编译
cd E:/wk-oth/rust-work/fet
cargo build --release --target x86_64-unknown-linux-musl
# 3. 复制到 dist-Linux
cp target/x86_64-unknown-linux-musl/release/fet ../dist-Linux/
# 4. 验证
file ../dist-Linux/fet
# 期望输出: ELF 64-bit LSB pie executable, x86-64, static-pie linked
# 5. 在 compose 中添加挂载
# - E:/wk-oth/rust-work/dist-Linux/fet:/usr/local/bin/fet:ro
```