86 lines
4.1 KiB
Docker
86 lines
4.1 KiB
Docker
# Per-user sandbox base image (DESIGN §7.5).
|
|
# 长驻 per-user 容器,工具调用走 `docker exec --user 1000:1000 --workdir /workspace/<wd> setsid <cmd>`(Step 3 接入)。
|
|
#
|
|
# 启动协议:tini(PID 1,reap 僵尸) → init.sh(root,跑 iptables 配 blocklist) → sleep infinity。
|
|
# `docker exec` 进来的进程由 --user flag 决定身份 ── 应用层(DockerExecutor)硬编 --user 1000,
|
|
# 不继承 PID 1 的 root 上下文。
|
|
#
|
|
# 构建上下文 = repo 根(用 -f 指定 Dockerfile 路径):
|
|
# docker build -f deploy/sandbox/Dockerfile -t zcbot-sandbox \
|
|
# --build-arg HOST_UID=$(id -u zcbot) --build-arg HOST_GID=$(id -g zcbot) .
|
|
FROM python:3.11-slim
|
|
|
|
# - iptables / ip6tables: init.sh 配 blocklist 需要(NET_ADMIN cap 在 docker run 处加)
|
|
# - iproute2: ip 命令(调试 / 排查)
|
|
# - netbase: /etc/protocols /etc/services(curl / 多数网络库依赖)
|
|
# - ca-certificates: HTTPS 出网(经 proxy 也要,Step 4)
|
|
# - tini: PID 1 信号转发 + 僵尸 reaper(setsid 包出的进程组结束时 PID 1 兜底回收)
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
iptables iproute2 netbase ca-certificates tini \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# 容器内非 root 用户的 uid/gid 必须与 host 上 `zcbot` 用户对齐(bind mount 保 host owner;
|
|
# 错配会导致 exec 进来后 write /workspace 时 EACCES)。build-arg 默认 1000,部署时按
|
|
# `id -u zcbot` 实际值显式传(详 RUN.md "sandbox 部署"段)。
|
|
ARG HOST_UID=1000
|
|
ARG HOST_GID=1000
|
|
RUN groupadd -g ${HOST_GID} zcbot && useradd -u ${HOST_UID} -g ${HOST_GID} -m -s /bin/bash zcbot
|
|
|
|
# 装全套 requirements ── 模型在 run_python 里写的脚本可能用 fastapi / sqlalchemy / litellm
|
|
# 等,装齐免 "ModuleNotFoundError" 摩擦。镜像偏大(~1G)是接受成本。
|
|
#
|
|
# pip 源可配(境内访问 files.pythonhosted.org 慢 / ReadTimeout):
|
|
# --build-arg PIP_INDEX_URL=https://mirrors.cloud.tencent.com/pypi/simple/ # 腾讯云内网
|
|
# --build-arg PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/ # 阿里云
|
|
# --build-arg PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple/ # 清华
|
|
# 默 PyPI 官方;timeout 拉到 60s 兜底抖动。
|
|
ARG PIP_INDEX_URL=https://pypi.org/simple/
|
|
ARG PIP_TRUSTED_HOST=
|
|
COPY requirements.txt /tmp/requirements.txt
|
|
RUN pip install --no-cache-dir \
|
|
--index-url ${PIP_INDEX_URL} \
|
|
${PIP_TRUSTED_HOST:+--trusted-host ${PIP_TRUSTED_HOST}} \
|
|
--timeout 60 \
|
|
-r /tmp/requirements.txt \
|
|
&& rm /tmp/requirements.txt
|
|
|
|
# Node + mermaid-cli + Chromium ── proposal / patent skill 渲 mermaid 图必备
|
|
# 镜像膨胀约 +400MB,接受成本(ASCII fallback 出 docx 没图不能用)
|
|
# Debian bookworm 自带 nodejs 18.x + chromium,够新;不走 NodeSource repo 减一步外网
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
chromium nodejs npm \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# npm 源可配(同 pip 一样,境内访问 registry.npmjs.org 慢):
|
|
# --build-arg NPM_REGISTRY=https://mirrors.cloud.tencent.com/npm/ # 腾讯云
|
|
# --build-arg NPM_REGISTRY=https://registry.npmmirror.com/ # 阿里
|
|
ARG NPM_REGISTRY=https://registry.npmjs.org/
|
|
|
|
# Puppeteer 用容器内已装的 chromium 而非自带下载(省 ~300MB + 避免下载失败)
|
|
ENV PUPPETEER_SKIP_DOWNLOAD=true
|
|
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
|
ENV MERMAID_PUPPETEER_CONFIG=/sandbox/puppeteer-config.json
|
|
|
|
RUN npm config set registry ${NPM_REGISTRY} \
|
|
&& npm install -g @mermaid-js/mermaid-cli@latest \
|
|
&& npm cache clean --force
|
|
|
|
# 容器内 puppeteer 启动 chromium 必备:no-sandbox(容器已 hardening 不需要 chromium 自家
|
|
# sandbox 再叠一层 setuid)、disable-setuid-sandbox(同上)、disable-dev-shm-usage
|
|
# (容器 /dev/shm 默 64MB 不够 chromium,让它走 /tmp)
|
|
RUN mkdir -p /sandbox && cat > /sandbox/puppeteer-config.json <<'EOF'
|
|
{
|
|
"executablePath": "/usr/bin/chromium",
|
|
"args": ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage"]
|
|
}
|
|
EOF
|
|
|
|
COPY deploy/sandbox/init.sh /init.sh
|
|
RUN chmod +x /init.sh
|
|
|
|
# 默认 cwd /workspace ── 但每次 `docker exec --workdir /workspace/<wd>` 会覆盖
|
|
WORKDIR /workspace
|
|
|
|
ENTRYPOINT ["/usr/bin/tini", "--"]
|
|
CMD ["/init.sh"]
|