mirror of
https://github.com/TencentCloud/Octop.git
synced 2026-10-20 06:19:17 +08:00
Agent grep with path=None walks from backend root `/`. Without ripgrep, deepagents' readline() on /proc/pagemap can grow RSS until the kernel OOM-kills Octop. Install rg in the images and replace the fallback at process start with a walk that skips virtual filesystems and bounds each read (#2101).
147 lines
5.7 KiB
Docker
147 lines
5.7 KiB
Docker
# syntax=docker/dockerfile:1
|
||
# =============================================================================
|
||
# Octop — 多阶段 Docker 构建
|
||
#
|
||
# 阶段 1: 构建 React/TypeScript 前端
|
||
# 阶段 2: Python 运行时 + 预构建前端
|
||
#
|
||
# 用法(在仓库根目录执行,构建上下文为根目录):
|
||
# docker build -f docker/Dockerfile -t octop:latest .
|
||
# docker run -d -p 8088:8088 -v octop-data:/data/.octop -e HOME=/data octop:latest
|
||
#
|
||
# 国内加速(可选,需 BuildKit,docker/docker_build.sh 默认已开启):
|
||
# PIP_INDEX_URL=https://mirrors.cloud.tencent.com/pypi/simple \
|
||
# PIP_TRUSTED_HOST=mirrors.cloud.tencent.com \
|
||
# NPM_REGISTRY=https://mirrors.cloud.tencent.com/npm/ \
|
||
# APT_MIRROR=mirrors.cloud.tencent.com \
|
||
# bash docker/docker_build.sh
|
||
#
|
||
# 或直接传 build-arg:
|
||
# docker build \
|
||
# -f docker/Dockerfile \
|
||
# --build-arg PIP_INDEX_URL=https://mirrors.cloud.tencent.com/pypi/simple \
|
||
# --build-arg PIP_TRUSTED_HOST=mirrors.cloud.tencent.com \
|
||
# --build-arg NPM_REGISTRY=https://mirrors.cloud.tencent.com/npm/ \
|
||
# --build-arg APT_MIRROR=mirrors.cloud.tencent.com \
|
||
# --build-arg NODE_MAX_OLD_SPACE_SIZE=1024 \
|
||
# -t octop:latest .
|
||
#
|
||
# 或使用 Compose:
|
||
# docker compose -f docker/docker-compose.yml up -d
|
||
# =============================================================================
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 阶段 1 — 前端构建
|
||
# ---------------------------------------------------------------------------
|
||
FROM node:20-slim AS frontend-builder
|
||
|
||
ARG NPM_REGISTRY=
|
||
# Node heap ceiling for the vite build. Lower this (e.g. 1024) on low-memory
|
||
# build hosts (< 4G RAM) to avoid OOM kills — the value only caps the max,
|
||
# it is not pre-allocated.
|
||
ARG NODE_MAX_OLD_SPACE_SIZE=2048
|
||
WORKDIR /build/dashboard
|
||
|
||
COPY dashboard/package.json dashboard/package-lock.json ./
|
||
RUN --mount=type=cache,target=/root/.npm,sharing=locked \
|
||
set -eu; \
|
||
if [ -n "$NPM_REGISTRY" ]; then npm config set registry "$NPM_REGISTRY"; fi; \
|
||
npm ci --no-audit \
|
||
|| { echo "npm ci failed — retrying clean"; rm -rf node_modules; npm ci --no-audit; }; \
|
||
test -x node_modules/.bin/vite
|
||
|
||
COPY dashboard/ ./
|
||
|
||
RUN mkdir -p ../src/octop/dashboard
|
||
|
||
# 镜像构建跳过完整 tsc;生产打包由 vite/esbuild 完成(使用 lockfile 中的 vite,不用 npx)
|
||
RUN NODE_ENV=production NODE_OPTIONS="--max-old-space-size=${NODE_MAX_OLD_SPACE_SIZE}" npm run build:docker
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 阶段 2 — Python 运行时
|
||
# ---------------------------------------------------------------------------
|
||
FROM python:3.12-slim AS runtime
|
||
|
||
LABEL maintainer="OrcaKit Team"
|
||
LABEL org.opencontainers.image.title="Octop"
|
||
LABEL org.opencontainers.image.description="Smarter self-hosted AI assistant — multi-user, multi-agent."
|
||
LABEL org.opencontainers.image.source="https://github.com/TencentCloud/orca"
|
||
LABEL org.opencontainers.image.licenses="MIT"
|
||
|
||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||
PYTHONUNBUFFERED=1 \
|
||
HOME=/data \
|
||
OCTOP_BIND_HOST=0.0.0.0 \
|
||
OCTOP_PORT=8088 \
|
||
OCTOP_LOG_LEVEL=info \
|
||
UV_COMPILE_BYTECODE=1 \
|
||
UV_LINK_MODE=copy \
|
||
UV_PYTHON_DOWNLOADS=never
|
||
|
||
ARG PIP_INDEX_URL=
|
||
ARG PIP_TRUSTED_HOST=
|
||
ARG APT_MIRROR=
|
||
|
||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||
if [ -n "$APT_MIRROR" ]; then \
|
||
printf 'Types: deb\nURIs: https://%s/debian\nSuites: trixie trixie-updates\nComponents: main contrib non-free non-free-firmware\n\nTypes: deb\nURIs: https://%s/debian-security\nSuites: trixie-security\nComponents: main contrib non-free non-free-firmware\n' \
|
||
"$APT_MIRROR" "$APT_MIRROR" > /etc/apt/sources.list.d/debian.sources; \
|
||
fi \
|
||
&& apt-get update && apt-get install -y --no-install-recommends \
|
||
build-essential \
|
||
libffi-dev \
|
||
libgl1 \
|
||
libglib2.0-0 \
|
||
curl \
|
||
git \
|
||
ripgrep \
|
||
&& rm -rf /var/lib/apt/lists/*
|
||
|
||
COPY --from=ghcr.io/astral-sh/uv:0.7 /uv /uvx /bin/
|
||
|
||
WORKDIR /app
|
||
|
||
# 先安装锁定依赖,仅改源码时可复用此层缓存
|
||
COPY pyproject.toml uv.lock README.md LICENSE ./
|
||
RUN --mount=type=cache,target=/root/.cache/uv \
|
||
if [ -n "$PIP_INDEX_URL" ]; then \
|
||
export UV_INDEX_URL="$PIP_INDEX_URL"; \
|
||
if [ -n "$PIP_TRUSTED_HOST" ]; then export UV_INSECURE_HOST="$PIP_TRUSTED_HOST"; fi; \
|
||
fi \
|
||
&& uv sync --frozen --no-install-project --no-dev \
|
||
--extra browser --extra local-embedding --extra knowledge-ocr
|
||
|
||
ENV PATH="/app/.venv/bin:$PATH" \
|
||
PLAYWRIGHT_BROWSERS_PATH=/root/.cache/ms-playwright
|
||
|
||
COPY src/ ./src/
|
||
COPY --from=frontend-builder /build/src/octop/dashboard/ ./src/octop/dashboard/
|
||
|
||
COPY .env.example ./
|
||
COPY docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
||
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
||
|
||
RUN --mount=type=cache,target=/root/.cache/uv \
|
||
if [ -n "$PIP_INDEX_URL" ]; then \
|
||
export UV_INDEX_URL="$PIP_INDEX_URL"; \
|
||
if [ -n "$PIP_TRUSTED_HOST" ]; then export UV_INSECURE_HOST="$PIP_TRUSTED_HOST"; fi; \
|
||
fi \
|
||
&& uv sync --frozen --no-dev \
|
||
--extra browser --extra local-embedding --extra knowledge-ocr \
|
||
&& .venv/bin/python -c "import cv2, fastembed, huggingface_hub, rapidocr, onnxruntime, pymupdf" \
|
||
&& apt-get update && apt-get install -y --no-install-recommends fonts-noto-cjk \
|
||
&& apt-get purge -y --auto-remove build-essential \
|
||
&& rm -rf /var/lib/apt/lists/* /tmp/*
|
||
|
||
RUN mkdir -p /data/.octop
|
||
|
||
EXPOSE 8088
|
||
|
||
HEALTHCHECK --interval=30s --timeout=10s --start-period=90s --retries=3 \
|
||
CMD ["sh", "-c", "curl -f http://localhost:${OCTOP_PORT:-8088}/api/health || exit 1"]
|
||
|
||
ENTRYPOINT ["docker-entrypoint.sh"]
|
||
CMD []
|