# ── DeepSeek Harness — 运行时拉取最新版镜像 ────────────────────────────────── # 镜像只装运行时工具链(Node/Python/gcc/pnpm/Rust 引导),不把 dsh 钉死在 # 构建层。容器每次启动由 docker/entrypoint.sh 从 npm 安装 # @deepseek-ai/dsh@latest(可用 DSH_DIST_TAG / DSH_NPM_REGISTRY 覆盖), # 安装失败直接退出,不回退到镜像内置版本。 # 构建不再需要本地 dist/ pack 产物。 # # npm registry / apt 源可通过 --build-arg 覆盖;默认走国内镜像 # (本机/国内构建环境通常无法直连官方源)。 ARG NPM_REGISTRY=https://registry.npmmirror.com # Debian 软件源可通过 --build-arg APT_MIRROR=... 覆盖;默认走清华镜像 # (deb.debian.org 在国内网络极慢)。 ARG APT_MIRROR=mirrors.tuna.tsinghua.edu.cn # 基础镜像:默认 ACR 上的 node(由 docker.io/library/node:24.19.0-bookworm-slim 同步) ARG BASE_IMAGE=registry.cn-hangzhou.aliyuncs.com/skymirror/node:24.19.0-bookworm-slim FROM ${BASE_IMAGE} ARG NPM_REGISTRY ARG APT_MIRROR ARG TARGETARCH ENV NPM_CONFIG_REGISTRY=${NPM_REGISTRY} \ COREPACK_NPM_REGISTRY=${NPM_REGISTRY} \ NODEJS_ORG_MIRROR=https://npmmirror.com/mirrors/node \ npm_config_userconfig=/home/dsh/.dsh/.npmrc # 切换到国内 Debian 镜像(bookworm 的 deb822 源),否则 apt 下载极慢 RUN sed -i "s|deb.debian.org|${APT_MIRROR}|g" /etc/apt/sources.list.d/debian.sources # 基础工具 + node-gyp/插件编译链(build-essential + python3)+ Python 3.11(apt 预编译,glibc 一致)。 # python3-dev 提供 Python.h,供 agent 编译带 C 扩展的 Python 包。 # 工具链保留(npm 路径镜像):koffi 优先用包内预编译平台二进制,landlock 等无预编译的 # 原生件在安装期按 arch 编译。JDK/Go 不再内置(旧全量镜像的能力,npm 路径按需安装)。 RUN apt-get update && apt-get install -y --no-install-recommends \ curl ca-certificates git xz-utils \ build-essential \ python3 python3-dev python3-pip python3-venv \ && rm -rf /var/lib/apt/lists/* # npm 精确版本 + pnpm(`dsh plugin add` 内部走 pnpm,allowBuilds 预置在安装期生效) RUN npm install -g npm@11.17.0 \ && corepack enable \ && corepack prepare pnpm@11.7.0 --activate # Rust 按需安装:只内置 rustup-init 引导程序(几 MB),首次调用 cargo/rustc/rustup 时 # 由 /usr/local/bin/ensure-rust 把最小 stable toolchain 装进 dsh-data 持久卷,镜像省下 ~1GB。 RUN case "$TARGETARCH" in \ amd64) RUSTUP_TRIPLE=x86_64-unknown-linux-gnu ;; \ arm64) RUSTUP_TRIPLE=aarch64-unknown-linux-gnu ;; \ *) echo "unsupported arch: $TARGETARCH" >&2; exit 1 ;; \ esac \ && (curl -fsSL "https://mirrors.ustc.edu.cn/rust-static/rustup/dist/${RUSTUP_TRIPLE}/rustup-init" -o /usr/local/bin/rustup-init \ || curl -fsSL "https://rsproxy.cn/rustup/dist/${RUSTUP_TRIPLE}/rustup-init" -o /usr/local/bin/rustup-init) \ && chmod +x /usr/local/bin/rustup-init # Rust toolchain 下载走 USTC 镜像(清华 rustup 镜像已下线该路径);toolchain 与 cargo 家目录落在 dsh-data 卷内(重启后保留) ENV RUSTUP_HOME=/home/dsh/.dsh/rustup \ CARGO_HOME=/home/dsh/.dsh/cargo \ RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static \ RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup # cargo 默认走清华 crates 稀疏索引(写入持久卷,首次挂载空卷时随镜像复制进去) RUN mkdir -p /home/dsh/.dsh/cargo \ && printf '%s\n' \ '[source.crates-io]' \ 'replace-with = "tuna"' \ '[source.tuna]' \ 'registry = "sparse+https://mirrors.tuna.tsinghua.edu.cn/crates.io-index/"' \ > /home/dsh/.dsh/cargo/config.toml # Rust 包装器 + python 软链接(python/pip 与 python3/pip3 同名可互换) COPY docker/ensure-rust.sh /usr/local/bin/ensure-rust RUN chmod +x /usr/local/bin/ensure-rust \ && ln -sf /usr/local/bin/ensure-rust /usr/local/bin/cargo \ && ln -sf /usr/local/bin/ensure-rust /usr/local/bin/rustc \ && ln -sf /usr/local/bin/ensure-rust /usr/local/bin/rustup \ && ln -sf /usr/bin/python3 /usr/local/bin/python \ && ln -sf /usr/bin/pip3 /usr/local/bin/pip # DSH 数据目录(会话/设置/配置/插件)与 agent 工作目录 # 写一份 npmrc 让运行时 npm / `dsh plugin add`(内部走 pnpm)默认用同一镜像; # 放在 dsh-data 卷内,首次挂载空卷时 Docker 会复制进去,之后仍可被用户覆盖。 # 运行时 ENV 的 npm_config_userconfig 指向这里(HOME=/workspace 使 /root/.npmrc 不生效)。 RUN mkdir -p /home/dsh/.dsh /workspace \ && printf "registry=%s\n" "${NPM_REGISTRY}" > /home/dsh/.dsh/.npmrc \ && printf "registry=%s\n" "${NPM_REGISTRY}" > /root/.npmrc # GOROOT/GOPATH/JAVA_HOME 已随 JDK/Go 移除;PATH 恢复标准顺序(含 /usr/local/bin 供 dsh 等软链) ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # pip 默认走清华镜像(供 agent 在 venv 里 pip install) ENV PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple ENV DSH_HOME=/home/dsh/.dsh ENV NODE_ENV=production # 让目录选择器默认起始目录为 /workspace(os.homedir() 读 HOME) ENV HOME=/workspace # pnpm 全局目录放进 dsh-data 卷,避免 HOME=/workspace 未挂载时全局包/状态丢失 ENV PNPM_HOME=/home/dsh/.dsh/pnpm # 3081 = dsh 内部 127.0.0.1;3080 = entrypoint 的 0.0.0.0 转发(Docker -p 映射 3080) EXPOSE 3080 # 启动时安装最新版 dsh,起 3080→127.0.0.1:3081 转发后 exec web;失败则非零退出 # (见 docker/entrypoint.sh) COPY docker/entrypoint.sh /usr/local/bin/dsh-entrypoint RUN chmod +x /usr/local/bin/dsh-entrypoint ENTRYPOINT ["/usr/local/bin/dsh-entrypoint"] # 额外参数追加给 dsh web;--no-open 与端口由 entrypoint 固定(内部 3081 / 转发 3080) CMD []