Files
SKYMirror 4be0850529 docs: add docker / docker-compose run examples
Document ACR multi-arch image, compose minimal YAML, docker run
variants (pin version, custom port, --trusted-host), and token URL
handling.
2026-09-16 01:29:11 +08:00

373 lines
11 KiB
Markdown
Raw Permalink 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 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 包不受本仓库许可证变更影响。