Document ACR multi-arch image, compose minimal YAML, docker run variants (pin version, custom port, --trusted-host), and token URL handling.
373 lines
11 KiB
Markdown
373 lines
11 KiB
Markdown
# DeepSeek Harness Docker 部署
|
||
|
||
本仓库只包含 **Docker 部署封装**,不含 DSH 源码。运行时从 npm 安装官方 [`@deepseek-ai/dsh`](https://www.npmjs.com/package/@deepseek-ai/dsh)。
|
||
|
||
| | |
|
||
|---|---|
|
||
| 构建产出 | 工具链底座(Node 24 / Python 3.11 / gcc / pnpm / rustup 引导),约 750MB(arm64 实测) |
|
||
| 每次启动 | `npm install -g @deepseek-ai/dsh@latest`,失败则容器退出(无内置 dsh 兜底) |
|
||
| 宿主机端口 | `3080` |
|
||
| 数据 | 命名卷 `dsh-data` → `/home/dsh/.dsh`(会话、设置、插件、npm cache) |
|
||
|
||
## 快速开始
|
||
|
||
```bash
|
||
git clone <本仓库地址>
|
||
cd DSH
|
||
docker compose up -d --build
|
||
docker logs -f dsh
|
||
```
|
||
|
||
日志中会出现:
|
||
|
||
```text
|
||
dsh-entry: installed 0.1.5-rc.1 ← 版本以 npm 上 latest 为准
|
||
dsh-entry: forwarding 0.0.0.0:3080 -> 127.0.0.1:3081
|
||
dsh web: http://127.0.0.1:3081/?token=<一次性令牌>
|
||
```
|
||
|
||
1. 把 URL 里的 **`127.0.0.1:3081` 换成 `127.0.0.1:3080`**(或 `服务器IP:3080`)
|
||
2. 浏览器打开**一次**带 `?token=` 的地址 → 写入 30 天 cookie
|
||
3. 之后直接访问 `http://127.0.0.1:3080/` 即可
|
||
|
||
国内网络建议在 `docker-compose.yml` 的 `environment` 中启用:
|
||
|
||
```yaml
|
||
- DSH_NPM_REGISTRY=https://registry.npmmirror.com
|
||
```
|
||
|
||
> 官方 `@latest` **强制浏览器认证**,没有免 token 开关。`DSH_TRUST_ALL` 只存在于历史 fork 镜像,当前路径无效。
|
||
|
||
## 运行示例
|
||
|
||
已推送镜像(多架构 `linux/amd64` + `linux/arm64`):
|
||
|
||
```text
|
||
registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest
|
||
```
|
||
|
||
### 1. Docker Compose(推荐,本仓库源码构建)
|
||
|
||
```bash
|
||
git clone <本仓库地址>
|
||
cd DeepSeekHarnessDocker
|
||
|
||
# 国内网络:取消注释 docker-compose.yml 里的 DSH_NPM_REGISTRY
|
||
# - DSH_NPM_REGISTRY=https://registry.npmmirror.com
|
||
|
||
docker compose up -d --build
|
||
docker compose logs -f dsh
|
||
```
|
||
|
||
常用 compose 子命令:
|
||
|
||
```bash
|
||
docker compose ps # 状态
|
||
docker compose logs -f dsh # 跟日志(找 token URL)
|
||
docker compose restart dsh # 改完插件/配置后重启
|
||
docker compose down # 停容器,保留 dsh-data 卷
|
||
docker compose down -v # 连数据卷一起删(慎用)
|
||
docker compose build --no-cache # 强制重建镜像
|
||
```
|
||
|
||
完整 `docker-compose.yml` 可参考仓库内文件;最小可用示例:
|
||
|
||
```yaml
|
||
services:
|
||
dsh:
|
||
image: registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest
|
||
# 或本地构建:build: .
|
||
ports:
|
||
- "3080:3080"
|
||
volumes:
|
||
- dsh-data:/home/dsh/.dsh
|
||
- ./workspace:/workspace
|
||
environment:
|
||
- DSH_HOME=/home/dsh/.dsh
|
||
- HOME=/workspace
|
||
- DSH_NPM_REGISTRY=https://registry.npmmirror.com
|
||
# 远程用 IP 访问时打开(仍需 token cookie):
|
||
# command: ["--trusted-host", "your-server-ip"]
|
||
restart: unless-stopped
|
||
|
||
volumes:
|
||
dsh-data:
|
||
```
|
||
|
||
### 2. Docker Compose(直接用 ACR 预构建镜像,不 build)
|
||
|
||
```bash
|
||
mkdir -p dsh-docker && cd dsh-docker
|
||
# 把上面的 docker-compose.yml 存到当前目录后:
|
||
docker compose up -d
|
||
docker compose logs -f dsh
|
||
```
|
||
|
||
或一行拉起(无 compose):
|
||
|
||
```bash
|
||
docker pull registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest
|
||
|
||
docker run -d --name dsh \
|
||
--restart unless-stopped \
|
||
-p 3080:3080 \
|
||
-v dsh-data:/home/dsh/.dsh \
|
||
-v "$PWD/workspace":/workspace \
|
||
-e DSH_HOME=/home/dsh/.dsh \
|
||
-e HOME=/workspace \
|
||
-e DSH_NPM_REGISTRY=https://registry.npmmirror.com \
|
||
registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest
|
||
|
||
docker logs -f dsh
|
||
```
|
||
|
||
打开日志中的 URL(把 `:3081` 换成 `:3080`)。
|
||
|
||
### 3. `docker run` 变体
|
||
|
||
**钉住 dsh 版本(可复现):**
|
||
|
||
```bash
|
||
docker run -d --name dsh \
|
||
-p 3080:3080 \
|
||
-v dsh-data:/home/dsh/.dsh \
|
||
-e DSH_DIST_TAG=0.1.5-rc.1 \
|
||
-e DSH_NPM_REGISTRY=https://registry.npmmirror.com \
|
||
registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest
|
||
```
|
||
|
||
**改宿主机端口(例如 18080):**
|
||
|
||
```bash
|
||
docker run -d --name dsh \
|
||
-p 18080:18080 \
|
||
-v dsh-data:/home/dsh/.dsh \
|
||
-e DSH_FORWARD_PORT=18080 \
|
||
registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest
|
||
```
|
||
|
||
**其它机器通过服务器 IP 访问:**
|
||
|
||
```bash
|
||
docker run -d --name dsh \
|
||
-p 3080:3080 \
|
||
-v dsh-data:/home/dsh/.dsh \
|
||
-e DSH_NPM_REGISTRY=https://registry.npmmirror.com \
|
||
registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest \
|
||
--trusted-host 203.0.113.10
|
||
```
|
||
|
||
浏览器仍须先用日志里带 `?token=` 的 `http://203.0.113.10:3080/?token=…` 打开一次。
|
||
|
||
**前台调试(不 detach):**
|
||
|
||
```bash
|
||
docker run --rm -it \
|
||
-p 3080:3080 \
|
||
-v dsh-data:/home/dsh/.dsh \
|
||
-e DSH_NPM_REGISTRY=https://registry.npmmirror.com \
|
||
registry.cn-hangzhou.aliyuncs.com/skymirror/dsh:latest
|
||
```
|
||
|
||
### 4. 进入容器
|
||
|
||
```bash
|
||
docker exec -it dsh sh
|
||
docker exec -it dsh dsh --version
|
||
docker exec -it dsh dsh plugin --profile web list
|
||
```
|
||
|
||
## 端口拓扑
|
||
|
||
官方 `dsh web` 只监听 `127.0.0.1`,并拒绝 `--host 0.0.0.0`。Docker `-p` 打不到容器内 loopback,因此 entrypoint 做 L4 转发:
|
||
|
||
```text
|
||
宿主机 :3080
|
||
→ 容器 0.0.0.0:3080 (entrypoint 转发)
|
||
→ 127.0.0.1:3081 (dsh web --no-open --port 3081)
|
||
```
|
||
|
||
```text
|
||
浏览器 ──http://host:3080/?token=…──▶ 0.0.0.0:3080 ──▶ 127.0.0.1:3081
|
||
│
|
||
┌─────────────────────────┴─────────────────────────┐
|
||
│ dsh-data:/home/dsh/.dsh ./workspace:/workspace │
|
||
│ 会话/设置/插件/npm-cache agent 工作目录 │
|
||
└───────────────────────────────────────────────────┘
|
||
```
|
||
|
||
**不要**单独 `-p` 映射容器内 `3081`;Docker 映射的应是转发口 `3080`。
|
||
|
||
## 配置参考
|
||
|
||
### 环境变量(entrypoint)
|
||
|
||
| 变量 | 默认 | 说明 |
|
||
|------|------|------|
|
||
| `DSH_PACKAGE` | `@deepseek-ai/dsh` | npm 包名 |
|
||
| `DSH_DIST_TAG` | `latest` | dist-tag 或精确版本(如 `0.1.5-rc.1`) |
|
||
| `DSH_NPM_REGISTRY` | `https://registry.npmjs.org` | 安装用 registry |
|
||
| `DSH_NPM_CACHE` | `$DSH_HOME/npm-cache` | npm cache(卷内,加速重启) |
|
||
| `DSH_INTERNAL_PORT` | `3081` | dsh 监听端口(仅 loopback) |
|
||
| `DSH_FORWARD_PORT` | `3080` | `0.0.0.0` 转发端口;与 compose `ports` 一致 |
|
||
|
||
### 传给 `dsh web` 的参数
|
||
|
||
entrypoint 固定执行:
|
||
|
||
```text
|
||
dsh web --no-open --port $DSH_INTERNAL_PORT <compose command...>
|
||
```
|
||
|
||
compose 的 `command` 会追加在后面。常用:
|
||
|
||
```yaml
|
||
# 从其它机器用 IP/域名访问时,声明 Host/Origin 围栏权威(仍需 token cookie)
|
||
command: ["--trusted-host", "203.0.113.10"]
|
||
```
|
||
|
||
| 不要通过 command 传 | 原因 |
|
||
|---------------------|------|
|
||
| `--host 0.0.0.0` | 官方明确拒绝 |
|
||
| `--port` | 用 `DSH_INTERNAL_PORT` |
|
||
| `--no-open` | entrypoint 已固定 |
|
||
|
||
### 改端口
|
||
|
||
```yaml
|
||
environment:
|
||
- DSH_FORWARD_PORT=8080
|
||
ports:
|
||
- "8080:8080"
|
||
```
|
||
|
||
### 持久化与工作区
|
||
|
||
```yaml
|
||
volumes:
|
||
- dsh-data:/home/dsh/.dsh # 会话/设置/插件(保留)
|
||
- ./workspace:/workspace # agent 工作目录;HOME 指向这里
|
||
```
|
||
|
||
插件装在 `$DSH_HOME/profiles/<name>/`,**在卷内,重启不丢**:
|
||
|
||
```bash
|
||
docker exec -it dsh dsh plugin --profile web add <package>
|
||
docker restart dsh # 插件变更需重启容器
|
||
```
|
||
|
||
## 从其它机器访问
|
||
|
||
1. **围栏**:Host 为 `http://<IP>:3080` 时不是 loopback,需
|
||
`command: ["--trusted-host", "<IP或域名>"]`
|
||
2. **认证**:仍须用日志里的 `?token=` URL 打开一次
|
||
3. **安全**:DSH 可执行代码。公网请前置带认证/TLS 的反向代理,不要裸暴露
|
||
|
||
## 前置条件
|
||
|
||
- Docker Engine 20.10+(BuildKit)
|
||
- Docker Compose v2
|
||
- 容器启动时能访问所配置的 npm registry
|
||
|
||
## 构建说明
|
||
|
||
```bash
|
||
docker compose build # 只装 apt/工具链,无 monorepo 编译
|
||
docker compose up -d
|
||
```
|
||
|
||
### 基础镜像
|
||
|
||
默认 `ARG BASE_IMAGE=registry.cn-hangzhou.aliyuncs.com/skymirror/node:24.19.0-bookworm-slim`(与 Docker Hub `node:24.19.0-bookworm-slim` 同源)。Docker Hub 不可达时可继续用该 ACR 地址,或自建同步后:
|
||
|
||
```bash
|
||
docker buildx build \
|
||
--build-arg BASE_IMAGE=<你的registry>/node:24.19.0-bookworm-slim \
|
||
--platform linux/arm64 -t dsh:local --load .
|
||
```
|
||
|
||
### 构建源(国内默认)
|
||
|
||
| 组件 | 默认源 |
|
||
|------|--------|
|
||
| apt | 清华 Debian |
|
||
| npm(构建期 npm/pnpm) | npmmirror |
|
||
| rustup 引导 | USTC / rsproxy |
|
||
| pip | 清华 |
|
||
|
||
可用 `--build-arg NPM_REGISTRY=...`、`APT_MIRROR=...` 覆盖。
|
||
|
||
### 清理 buildx 缓存
|
||
|
||
```bash
|
||
docker buildx du
|
||
docker buildx prune --filter until=24h
|
||
# docker buildx prune --all
|
||
```
|
||
|
||
## 镜像内置环境
|
||
|
||
| 工具 | 版本 | 说明 |
|
||
|------|------|------|
|
||
| Node.js | 24.19.0 | 基础镜像 |
|
||
| npm | 11.17.0 | 构建期升级 |
|
||
| pnpm | 11.7.0 | `dsh plugin add` 依赖 |
|
||
| Python | 3.11 | apt;含 pip / venv / Python.h |
|
||
| gcc / g++ / make | bookworm | 原生模块编译 |
|
||
| Rust | stable,按需 | 首次 `cargo`/`rustc`/`rustup` 时装入 `dsh-data` 卷 |
|
||
| git / curl | apt | |
|
||
|
||
不内置 JDK、Go。需要时进容器安装。
|
||
|
||
```bash
|
||
# 预触发 Rust 安装(可选)
|
||
docker exec dsh cargo --version
|
||
```
|
||
|
||
## 不用 Docker
|
||
|
||
```bash
|
||
# Node ^22.19 || >=24
|
||
npx --yes @deepseek-ai/dsh@latest web
|
||
npm view @deepseek-ai/dsh dist-tags
|
||
```
|
||
|
||
本机只监听 `127.0.0.1`,打开日志中的 `?token=` URL。插件管理需 `corepack enable pnpm`。
|
||
|
||
| | `npx` | 本仓库 Docker |
|
||
|---|---|---|
|
||
| 工具链 | 仅本机 Node | Python / gcc / pnpm / Rust 按需 |
|
||
| 升级 | 每次 `@latest` | 每次容器启动 `@latest` |
|
||
| 数据 | `~/.dsh` | `dsh-data` 卷 |
|
||
| 远程访问 | 仅 loopback | `3080` 转发进容器 |
|
||
|
||
## 仓库布局
|
||
|
||
```text
|
||
Dockerfile 工具链镜像 + entrypoint
|
||
docker-compose.yml 端口 / 卷 / 环境变量
|
||
docker/entrypoint.sh 安装 @latest → 转发 → dsh web
|
||
docker/ensure-rust.sh Rust 按需安装包装器
|
||
DEPLOY.md 本文档
|
||
LICENSE GPL-3.0
|
||
```
|
||
|
||
## 常见问题
|
||
|
||
| 现象 | 处理 |
|
||
|------|------|
|
||
| 启动慢或立刻退出 | `docker logs`:多半 npm 安装失败。设 `DSH_NPM_REGISTRY=https://registry.npmmirror.com`,或钉版本 `DSH_DIST_TAG=0.1.5-rc.1` |
|
||
| `authentication required; reopen the URL printed by dsh web` | 正常。用带 `?token=` 的 URL 打开一次;官方包不能免 token |
|
||
| `GET /` 返回 401 | 同上 |
|
||
| `/api` 返回 403 | Host 不在围栏:`command: ["--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` | 官方限制。不要传该参数,依赖转发 |
|
||
| 端口占用 | 同时改 `ports` 与 `DSH_FORWARD_PORT` |
|
||
| `Cannot find module .../dsh/lib/bin.js` | 覆盖了 `entrypoint:`/`command:`,绕过了安装入口;去掉覆盖后重建 |
|
||
| 插件重启后消失 | 确认插件装在 `$DSH_HOME/profiles`,且 `dsh-data` 卷未挂错 |
|
||
| 设置了 `DSH_TRUST_ALL=1` 仍要 token | 预期行为。官方包无此变量 |
|
||
|
||
## 许可
|
||
|
||
本仓库部署封装为 [GPL-3.0](LICENSE)。上游 DeepSeek Harness 为 MIT,运行时安装的官方 npm 包不受本仓库许可证变更影响。
|