Files
DeepSeekHarnessDocker/DEPLOY.md
T
SKYMirror 0bfe0b4a65 chore: strip monorepo; keep Docker runtime deploy for official dsh@latest
Image installs @deepseek-ai/dsh from npm on start. Fork 0.1.2-alpha.2 source
is obsolete for this deployment path.
2026-09-16 00:18:32 +08:00

286 lines
12 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.
# DeepSeek Harness (DSH) Docker 部署指南
## 概述
本仓库是 DeepSeek Harness 源码 + Docker 构建配置。镜像**只内置工具链**,不把 dsh 钉死在构建层:容器每次启动由 `docker/entrypoint.sh` 从 npm 安装官方 `@deepseek-ai/dsh@latest`(可用环境变量覆盖),安装失败则非零退出,不回退到旧版本。因此**启动时必须能访问 npm registry**。
### 端口拓扑(当前实现)
官方 `dsh web` **只监听 `127.0.0.1`**,并明确拒绝 `--host 0.0.0.0`(安全原因:Web 面可远程执行代码)。Docker 的 `-p` 打不到容器内 loopback,故 entrypoint 额外起一层 L4 转发:
```
宿主机 :3080 → 容器 0.0.0.0:3080 → 127.0.0.1:3081 (dsh web --no-open --port 3081)
```
```
┌──────────┐ http://localhost:3080/?token=… ┌─────────────────────────────┐
│ 浏览器 │ ────────────────────────────────▶ │ 0.0.0.0:3080 (转发) │
└──────────┘ │ ↓ │
│ 127.0.0.1:3081 (dsh web) │
└──────────────┬──────────────┘
┌──────────────────────────────┼──────────────┐
│ dsh-data 卷 │ ./workspace │
│ /home/dsh/.dsh │ /workspace │
│ (会话/设置/插件/配置) │ (工作目录) │
└──────────────────────────────┴──────────────┘
```
### 浏览器认证(官方包行为)
官方 `@latest` **强制浏览器认证**,没有免 token 的开关:
1. 从 `docker logs` 复制带 `?token=` 的 URL,用浏览器打开**一次**
2. 服务端 `303` 下发 **30 天签名 cookie**
3. 之后同一浏览器直接访问 `http://<host>:3080/` 即可
**说明**:历史 fork 镜像里的 `DSH_TRUST_ALL=1`、`DSH_TRUSTED_HOSTS` 环境变量、默认绑定 `0.0.0.0` 均**不在官方 npm 包中**。官方侧 Host/Origin 围栏可用 **`--trusted-host`**(compose `command` 传入)扩展非 loopback 权威;cookie 认证仍必须完成。
## 镜像信息
**当前 Dockerfile 为「运行时拉取」模型**:构建产出工具链底座(约 747MB,linux/arm64 本地实测),dsh 版本由每次容器启动时的 `@deepseek-ai/dsh@latest` 决定,不体现在镜像 tag 里。
| 项目 | 值 |
|------|-----|
| 基础镜像 | `registry.cn-hangzhou.aliyuncs.com/skymirror/node:24.19.0-bookworm-slim`(`ARG BASE_IMAGE` 可覆盖;内容同 `docker.io/library/node:24.19.0-bookworm-slim`) |
| dsh 安装 | 启动时 `npm install -g @deepseek-ai/dsh@latest`(默认 `registry.npmjs.org`) |
| 宿主机端口 | `3080`(compose `3080:3080`) |
| 容器内 dsh 端口 | `3081`(仅 `127.0.0.1`) |
| ENTRYPOINT | `/usr/local/bin/dsh-entrypoint` |
### 历史镜像存档(已过时,勿按其行为部署)
以下 digest 对应**旧 fork 构建时安装**镜像(`0.1.2-alpha.2-skymirror.1`,`dist/` pack + `file:` 闭包、`DSH_TRUST_ALL`、默认 `0.0.0.0`)。当前 Dockerfile 已取代该模型,哈希仅备查:
| 项目 | 值 |
|------|-----|
| manifest list | `sha256:4c8636d1f20804a39757829de5adb27dccf6435b99610e2a70e74fe8cc95b5bd` |
| 更早 monorepo 编译镜像 | `sha256:8a5d6406abd56f5cc3f175aa6b751e226bc91430dfb896add1fcf9a3f970f39e` |
## 快速开始
```bash
git clone <仓库地址>
cd DSH
docker compose build
docker compose up -d
docker logs -f dsh
# 等待出现类似:
# dsh-entry: installed 0.1.5-rc.1
# dsh-entry: forwarding 0.0.0.0:3080 -> 127.0.0.1:3081
# dsh web: http://127.0.0.1:3081/?token=<一次性令牌>
# 把日志 URL 中的 127.0.0.1:3081 换成 127.0.0.1:3080(或服务器 IP:3080)后打开
```
首次使用时在 Web UI 中配置模型 API Key(DeepSeek 或任意 OpenAI 兼容端点)。
国内网络建议在 compose 的 `environment` 里加:
```yaml
- DSH_NPM_REGISTRY=https://registry.npmmirror.com
```
## 启动环境变量与参数
### 环境变量(`docker/entrypoint.sh`)
| 变量 | 默认 | 说明 |
|------|------|------|
| `DSH_PACKAGE` | `@deepseek-ai/dsh` | 要安装的包名 |
| `DSH_DIST_TAG` | `latest` | npm dist-tag 或精确版本(如 `0.1.5-rc.1`) |
| `DSH_NPM_REGISTRY` | `https://registry.npmjs.org` | 拉包 registry;国内可设 `https://registry.npmmirror.com` |
| `DSH_NPM_CACHE` | `$DSH_HOME/npm-cache` | npm cache(`dsh-data` 卷内,重启可命中) |
| `DSH_INTERNAL_PORT` | `3081` | dsh 监听端口(仅 `127.0.0.1`) |
| `DSH_FORWARD_PORT` | `3080` | entrypoint 在 `0.0.0.0` 上的转发端口(Docker `-p` 应映射此端口) |
### 传给 `dsh web` 的参数
entrypoint 固定附加 `--no-open --port ${DSH_INTERNAL_PORT}`。compose 的 `command` 会**追加**在后面,例如:
```yaml
command: ["--trusted-host", "203.0.113.10"]
```
| 参数 | 作用 |
|------|------|
| `--trusted-host <authority>` | 向 Host/Origin 围栏追加非 loopback 权威(可重复);**不**替代 cookie 认证 |
| `--port` / `--host` | 不要通过 command 覆盖:端口由 `DSH_INTERNAL_PORT` 管理;`--host 0.0.0.0` 会被官方拒绝 |
## 前置条件
- Docker Engine 20.10+(BuildKit)
- Docker Compose v2
- 启动时能访问 npm registry(官方 npmjs 或 npmmirror)
## 一、不用 Docker 直接跑
```bash
# Node.js ^22.19 || >=24
npx --yes @deepseek-ai/dsh@latest web
# 或
npm install -g @deepseek-ai/dsh@latest
dsh web --no-open --port 3080
```
本机默认只监听 `127.0.0.1`,浏览器打开日志里的 `?token=` URL。管理插件需要 `corepack enable pnpm`。
查看可用版本:
```bash
npm view @deepseek-ai/dsh dist-tags
```
### npm 路径 vs Docker
| | `npx @latest` | Docker(本仓库) |
|---|---|---|
| 启动耗时 | 首次拉包约 15s–数分钟(视网络/cache) | 镜像已有工具链;每次启动装 dsh(有 cache 更快) |
| 构建 | 无 | 只装 apt/工具链,不编译 monorepo |
| 工具链 | 仅本机 Node | Python / gcc·g++ / pnpm / Rust 按需 |
| 升级 | 每次 `npx@latest` | 每次容器启动装 `@latest`(失败退出) |
| 数据 | `$DSH_HOME`(默认 `~/.dsh`) | `dsh-data` → `/home/dsh/.dsh` |
| 远程端口 | 只听 loopback | entrypoint `3080` → dsh `3081` |
## 二、本地构建并运行
```bash
docker compose build
docker compose up -d
```
构建不需要 `pnpm build`、`release:pack` 或 `dist/`。
### 基础镜像拉不动时
Docker Hub 在部分网络不可达。可先把官方 node 镜像同步到自己 registry,再:
```bash
docker buildx build \
--build-arg BASE_IMAGE=registry.cn-hangzhou.aliyuncs.com/skymirror/node:24.19.0-bookworm-slim \
--platform linux/arm64 \
-t dsh:local-arm64 --load .
```
### 清理 buildx 缓存
```bash
docker buildx du
docker buildx prune --filter until=24h
# 或
docker buildx prune --all
```
## 三、云效构建并推送
流水线「镜像构建」使用仓库根目录 `Dockerfile`,推送到 ACR。目标机:
```bash
docker pull registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest
docker run -d --name dsh \
-p 3080:3080 \
-v dsh-data:/home/dsh/.dsh \
-v /path/to/workspace:/workspace \
-e DSH_NPM_REGISTRY=https://registry.npmmirror.com \
registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest
```
注意:推上去的是**工具链底座**;运行时仍会拉 npm 上的 dsh。请保证部署机可访问所配置的 registry。
## 四、目录 / 端口映射
| 项目 | 说明 |
|------|------|
| 宿主机 `3080` → 容器 `3080` | entrypoint 的 `0.0.0.0` 转发口 |
| 容器内 dsh `3081` | 仅 `127.0.0.1`,不要单独 `-p` 映射 |
| `dsh-data` → `/home/dsh/.dsh` | 会话、settings、storages、profiles(插件)、npm-cache |
| `./workspace` → `/workspace` | agent 工作目录;目录选择器默认起点(`HOME`) |
| `$DSH_HOME/profiles/<name>` | 插件与 profile,卷内**持久化** |
| `dsh` 命令 | 启动时 `npm install -g` 装入 PATH,供 `docker exec` 管理插件 |
插件示例:
```bash
docker exec -it dsh dsh plugin --profile web add <package>
# 改完插件需重启容器
docker restart dsh
```
## 五、镜像内置语言环境
| 语言/工具 | 版本 | 说明 |
|-----------|------|------|
| Node.js | 24.19.0 | 基础镜像 |
| npm | 11.17.0 | 全局升级 |
| pnpm | 11.7.0 | corepack;`dsh plugin add` 使用 |
| Python | 3.11 | apt,含 pip/venv/Python.h |
| Rust | stable 按需 | 首次调用 `cargo`/`rustc`/`rustup` 时装进 `dsh-data` 卷 |
| gcc / g++ / make | bookworm | 原生模块编译 |
| git / curl | apt | |
不内置 JDK、Go(体积取舍)。需要时进容器自行安装。
> 构建默认走国内源:npm `npmmirror`、Debian 清华、rustup USTC、pip 清华。云效等可出网环境可用 `--build-arg NPM_REGISTRY=...` 等覆盖。
### Rust 按需安装
`/usr/local/bin/ensure-rust` 包装器在首次调用时把 toolchain 装进 `$RUSTUP_HOME` / `$CARGO_HOME`(均在 `dsh-data` 卷)。可提前 `docker exec dsh cargo --version` 触发。
## 六、自定义配置
### 修改端口
```yaml
environment:
- DSH_FORWARD_PORT=8080 # 容器 0.0.0.0 转发口
- DSH_INTERNAL_PORT=3081 # dsh 本机端口(一般不用改)
ports:
- "8080:8080"
```
### 从其它机器访问
1. **Host/Origin 围栏**:浏览器地址为 `http://<服务器IP>:3080` 时,Host 不是 loopback,需在 compose 中追加:
```yaml
command: ["--trusted-host", "<服务器IP或域名>"]
```
2. **浏览器认证**:仍必须用日志里的 `?token=` URL 打开一次,换 30 天 cookie。
3. **传输与入口**:DSH 可执行代码。公网暴露请在前面加带认证/TLS 的反向代理,不要裸奔。
### 挂载自己的数据目录
```yaml
volumes:
- /data/dsh:/home/dsh/.dsh
- /data/work:/workspace
```
## 七、常见问题
| 现象 | 处理 |
|------|------|
| 启动很慢或退出 | 看 `docker logs`:多半是装 `@latest` 网络失败;设 `DSH_NPM_REGISTRY=https://registry.npmmirror.com` |
| `authentication required; reopen the URL printed by dsh web` | 正常:用带 `?token=` 的 URL 打开一次;官方包**不能**免 token |
| `GET /` 401 | 同上 |
| `/api` 403 | Host 不在围栏内:给 `dsh web` 加 `--trusted-host <你的Host>` |
| 宿主机 3080 连不上 / connection reset | 确认映射的是转发口 `3080:3080`,且 logs 有 `forwarding 0.0.0.0:3080 -> 127.0.0.1:3081` |
| `--host 0.0.0.0 is intentionally not supported` | 官方限制;不要传 `--host 0.0.0.0`,依赖 entrypoint 转发 |
| 端口被占用 | 改 compose 的 `ports` 与 `DSH_FORWARD_PORT` |
| `Cannot find module .../dsh/lib/bin.js` | 自定义了 `entrypoint:`/`command:` 绕过安装入口;去掉覆盖后重建 |
| 插件重启后消失 | 插件应装在 `$DSH_HOME/profiles`(卷内);确认未挂错卷 |
| 设置了 `DSH_TRUST_ALL=1` 仍要 token | **预期行为**:官方包无此变量;历史 fork 镜像才有 |
## 附录:fork 私有 npm 发布(可选,当前 Docker 不用)
当前 Docker 路径**只消费官方 npm `@latest`**。若仍需维护 skymirror fork 并发到私有 registry,可继续用仓库内 release 脚本(与镜像构建解耦):
```bash
pnpm run release:dsh <version>
pnpm run build:official
pnpm run release:pack --family dsh --out dist/npm
# … vendor / landlock / verify / publish,见 scripts/release/
```
fork 的 `DSH_TRUST_ALL`、`DSH_TRUSTED_HOSTS` 环境变量、默认 `0.0.0.0` 绑定等部署补丁只存在于 fork 编译产物中;要在容器里用它们,需把 `DSH_PACKAGE` / `DSH_DIST_TAG` / `DSH_NPM_REGISTRY` 指到私有 registry 的 fork 包,并自行承担与官方 `@latest` 的行为差异。