From e796b73aa037414d628a1ebdf491c2853a675a00 Mon Sep 17 00:00:00 2001 From: "zhoujiahui.01" Date: Tue, 31 Mar 2026 18:32:25 +0800 Subject: [PATCH 1/3] docker: default to server plus console startup --- Dockerfile | 8 ++- docker-compose.yml | 1 + docker/openviking-console-entrypoint.sh | 64 ++++++++++++++++++++++ tests/misc/test_docker_console_defaults.py | 40 ++++++++++++++ 4 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 docker/openviking-console-entrypoint.sh create mode 100644 tests/misc/test_docker_console_defaults.py diff --git a/Dockerfile b/Dockerfile index b498ef166..64b71e04b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -76,14 +76,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ WORKDIR /app COPY --from=py-builder /app/.venv /app/.venv +COPY docker/openviking-console-entrypoint.sh /usr/local/bin/openviking-console-entrypoint +RUN chmod +x /usr/local/bin/openviking-console-entrypoint ENV PATH="/app/.venv/bin:$PATH" ENV OPENVIKING_CONFIG_FILE="/app/ov.conf" -EXPOSE 1933 +EXPOSE 1933 8020 HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \ CMD curl -fsS http://127.0.0.1:1933/health || exit 1 -# Default runs server; override command to run CLI, e.g.: +# Default runs server + console; override command to run CLI, e.g.: # docker run --rm -v "$HOME/.openviking/ovcli.conf:/root/.openviking/ovcli.conf" openviking --help -CMD ["openviking-server"] +CMD ["openviking-console-entrypoint"] diff --git a/docker-compose.yml b/docker-compose.yml index 03c979a65..307823db3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,7 @@ services: container_name: openviking ports: - "1933:1933" + - "8020:8020" volumes: # Mount the configuration and data directory to persist state - /var/lib/openviking/ov.conf:/app/ov.conf diff --git a/docker/openviking-console-entrypoint.sh b/docker/openviking-console-entrypoint.sh new file mode 100644 index 000000000..7eb0ebcf4 --- /dev/null +++ b/docker/openviking-console-entrypoint.sh @@ -0,0 +1,64 @@ +#!/bin/sh +set -eu + +SERVER_URL="http://127.0.0.1:1933" +SERVER_HEALTH_URL="${SERVER_URL}/health" +CONSOLE_PORT="${OPENVIKING_CONSOLE_PORT:-8020}" +CONSOLE_HOST="${OPENVIKING_CONSOLE_HOST:-0.0.0.0}" +SERVER_PID="" +CONSOLE_PID="" + +forward_signal() { + if [ -n "${SERVER_PID}" ] && kill -0 "${SERVER_PID}" 2>/dev/null; then + kill "${SERVER_PID}" 2>/dev/null || true + fi + if [ -n "${CONSOLE_PID}" ] && kill -0 "${CONSOLE_PID}" 2>/dev/null; then + kill "${CONSOLE_PID}" 2>/dev/null || true + fi +} + +trap 'forward_signal' INT TERM + +openviking-server & +SERVER_PID=$! + +attempt=0 +until curl -fsS "${SERVER_HEALTH_URL}" >/dev/null 2>&1; do + attempt=$((attempt + 1)) + if ! kill -0 "${SERVER_PID}" 2>/dev/null; then + echo "[openviking-console-entrypoint] openviking-server exited before becoming healthy" >&2 + wait "${SERVER_PID}" || true + exit 1 + fi + if [ "${attempt}" -ge 120 ]; then + echo "[openviking-console-entrypoint] timed out waiting for ${SERVER_HEALTH_URL}" >&2 + forward_signal + wait "${SERVER_PID}" || true + exit 1 + fi + sleep 1 +done + +python -m openviking.console.bootstrap \ + --host "${CONSOLE_HOST}" \ + --port "${CONSOLE_PORT}" \ + --openviking-url "${SERVER_URL}" & +CONSOLE_PID=$! + +while kill -0 "${SERVER_PID}" 2>/dev/null && kill -0 "${CONSOLE_PID}" 2>/dev/null; do + sleep 1 +done + +if ! kill -0 "${SERVER_PID}" 2>/dev/null; then + wait "${SERVER_PID}" || SERVER_STATUS=$? + SERVER_STATUS=${SERVER_STATUS:-1} + forward_signal + wait "${CONSOLE_PID}" || true + exit "${SERVER_STATUS}" +fi + +wait "${CONSOLE_PID}" || CONSOLE_STATUS=$? +CONSOLE_STATUS=${CONSOLE_STATUS:-0} +forward_signal +wait "${SERVER_PID}" || true +exit "${CONSOLE_STATUS}" diff --git a/tests/misc/test_docker_console_defaults.py b/tests/misc/test_docker_console_defaults.py new file mode 100644 index 000000000..1306c7c62 --- /dev/null +++ b/tests/misc/test_docker_console_defaults.py @@ -0,0 +1,40 @@ +# Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd. +# SPDX-License-Identifier: AGPL-3.0 + +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[2] + + +def _read_text(relative_path: str) -> str: + return (REPO_ROOT / relative_path).read_text(encoding="utf-8") + + +def test_dockerfile_defaults_to_console_entrypoint_runtime(): + dockerfile = _read_text("Dockerfile") + + assert ( + "COPY docker/openviking-console-entrypoint.sh /usr/local/bin/openviking-console-entrypoint" + in dockerfile + ) + assert "EXPOSE 1933 8020" in dockerfile + assert 'CMD ["openviking-console-entrypoint"]' in dockerfile + + +def test_console_entrypoint_starts_server_then_console(): + entrypoint = _read_text("docker/openviking-console-entrypoint.sh") + + assert "openviking-server" in entrypoint + assert 'SERVER_URL="http://127.0.0.1:1933"' in entrypoint + assert 'SERVER_HEALTH_URL="${SERVER_URL}/health"' in entrypoint + assert 'CONSOLE_PORT="${OPENVIKING_CONSOLE_PORT:-8020}"' in entrypoint + assert "python -m openviking.console.bootstrap" in entrypoint + assert '--port "${CONSOLE_PORT}"' in entrypoint + assert '--openviking-url "${SERVER_URL}"' in entrypoint + + +def test_docker_compose_exposes_console_port(): + compose = _read_text("docker-compose.yml") + + assert '- "1933:1933"' in compose + assert '- "8020:8020"' in compose From 9ebc2ccd82a8743fc082a30e569e1d825cc2344b Mon Sep 17 00:00:00 2001 From: "zhoujiahui.01" Date: Tue, 31 Mar 2026 19:16:19 +0800 Subject: [PATCH 2/3] docker: bundle and default-enable vikingbot --- Dockerfile | 6 ++-- docker/openviking-console-entrypoint.sh | 40 +++++++++++++++++++++- tests/misc/test_docker_console_defaults.py | 14 ++++++-- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 64b71e04b..0dd5fdb21 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,13 +50,13 @@ COPY third_party/ third_party/ RUN --mount=type=cache,target=/root/.cache/uv,id=uv-${TARGETPLATFORM} \ case "${UV_LOCK_STRATEGY}" in \ locked) \ - uv sync --locked --no-editable \ + uv sync --locked --no-editable --extra bot \ ;; \ auto) \ if ! uv lock --check; then \ uv lock; \ fi; \ - uv sync --locked --no-editable \ + uv sync --locked --no-editable --extra bot \ ;; \ *) \ echo "Unsupported UV_LOCK_STRATEGY: ${UV_LOCK_STRATEGY}" >&2; \ @@ -88,4 +88,4 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \ # Default runs server + console; override command to run CLI, e.g.: # docker run --rm -v "$HOME/.openviking/ovcli.conf:/root/.openviking/ovcli.conf" openviking --help -CMD ["openviking-console-entrypoint"] +ENTRYPOINT ["openviking-console-entrypoint"] diff --git a/docker/openviking-console-entrypoint.sh b/docker/openviking-console-entrypoint.sh index 7eb0ebcf4..38ac6f768 100644 --- a/docker/openviking-console-entrypoint.sh +++ b/docker/openviking-console-entrypoint.sh @@ -5,9 +5,43 @@ SERVER_URL="http://127.0.0.1:1933" SERVER_HEALTH_URL="${SERVER_URL}/health" CONSOLE_PORT="${OPENVIKING_CONSOLE_PORT:-8020}" CONSOLE_HOST="${OPENVIKING_CONSOLE_HOST:-0.0.0.0}" +WITH_BOT="${OPENVIKING_WITH_BOT:-1}" SERVER_PID="" CONSOLE_PID="" +normalize_with_bot() { + case "$1" in + 1|true|TRUE|yes|YES|on|ON) + WITH_BOT="1" + ;; + 0|false|FALSE|no|NO|off|OFF) + WITH_BOT="0" + ;; + *) + echo "[openviking-console-entrypoint] invalid OPENVIKING_WITH_BOT=${1}" >&2 + exit 2 + ;; + esac +} + +if [ "$#" -gt 0 ]; then + for arg in "$@"; do + case "${arg}" in + --with-bot) + WITH_BOT="1" + ;; + --without-bot) + WITH_BOT="0" + ;; + *) + exec "$@" + ;; + esac + done +fi + +normalize_with_bot "${WITH_BOT}" + forward_signal() { if [ -n "${SERVER_PID}" ] && kill -0 "${SERVER_PID}" 2>/dev/null; then kill "${SERVER_PID}" 2>/dev/null || true @@ -19,7 +53,11 @@ forward_signal() { trap 'forward_signal' INT TERM -openviking-server & +if [ "${WITH_BOT}" = "1" ]; then + openviking-server --with-bot & +else + openviking-server & +fi SERVER_PID=$! attempt=0 diff --git a/tests/misc/test_docker_console_defaults.py b/tests/misc/test_docker_console_defaults.py index 1306c7c62..b2c1bfcd3 100644 --- a/tests/misc/test_docker_console_defaults.py +++ b/tests/misc/test_docker_console_defaults.py @@ -17,14 +17,17 @@ def test_dockerfile_defaults_to_console_entrypoint_runtime(): "COPY docker/openviking-console-entrypoint.sh /usr/local/bin/openviking-console-entrypoint" in dockerfile ) + assert "uv sync --locked --no-editable --extra bot" in dockerfile assert "EXPOSE 1933 8020" in dockerfile - assert 'CMD ["openviking-console-entrypoint"]' in dockerfile + assert 'ENTRYPOINT ["openviking-console-entrypoint"]' in dockerfile def test_console_entrypoint_starts_server_then_console(): entrypoint = _read_text("docker/openviking-console-entrypoint.sh") - assert "openviking-server" in entrypoint + assert 'WITH_BOT="${OPENVIKING_WITH_BOT:-1}"' in entrypoint + assert "--without-bot" in entrypoint + assert "openviking-server --with-bot" in entrypoint assert 'SERVER_URL="http://127.0.0.1:1933"' in entrypoint assert 'SERVER_HEALTH_URL="${SERVER_URL}/health"' in entrypoint assert 'CONSOLE_PORT="${OPENVIKING_CONSOLE_PORT:-8020}"' in entrypoint @@ -33,6 +36,13 @@ def test_console_entrypoint_starts_server_then_console(): assert '--openviking-url "${SERVER_URL}"' in entrypoint +def test_console_entrypoint_passthroughs_custom_runtime_commands(): + entrypoint = _read_text("docker/openviking-console-entrypoint.sh") + + assert 'exec "$@"' in entrypoint + assert '"openviking"' not in entrypoint + + def test_docker_compose_exposes_console_port(): compose = _read_text("docker-compose.yml") From 2e0286d4d3830a1f8801dd869f50b223acc91bdc Mon Sep 17 00:00:00 2001 From: "zhoujiahui.01" Date: Tue, 31 Mar 2026 19:20:56 +0800 Subject: [PATCH 3/3] docs: document docker console and bot defaults --- Dockerfile | 1 + README.md | 2 + docs/en/getting-started/02-quickstart.md | 4 ++ docs/en/guides/03-deployment.md | 36 ++++++++++++++++ docs/zh/getting-started/02-quickstart.md | 4 ++ docs/zh/guides/03-deployment.md | 36 ++++++++++++++++ pyproject.toml | 2 +- setup.py | 1 + tests/misc/test_docker_console_defaults.py | 50 ---------------------- 9 files changed, 85 insertions(+), 51 deletions(-) delete mode 100644 tests/misc/test_docker_console_defaults.py diff --git a/Dockerfile b/Dockerfile index 0dd5fdb21..5659a0585 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,6 +37,7 @@ WORKDIR /app COPY Cargo.toml Cargo.lock ./ COPY pyproject.toml uv.lock setup.py README.md ./ COPY build_support/ build_support/ +COPY bot/ bot/ COPY crates/ crates/ COPY openviking/ openviking/ COPY openviking_cli/ openviking_cli/ diff --git a/README.md b/README.md index e7bcbec89..3ea775d60 100644 --- a/README.md +++ b/README.md @@ -496,6 +496,8 @@ openviking-server --with-bot ov chat ``` +If you use the official Docker image, `vikingbot` is already bundled in the image and starts by default together with the OpenViking server and console UI. You can disable it at runtime with either `--without-bot` or `-e OPENVIKING_WITH_BOT=0`. + --- ## Server Deployment Details diff --git a/docs/en/getting-started/02-quickstart.md b/docs/en/getting-started/02-quickstart.md index 137a36c16..0ce8113de 100644 --- a/docs/en/getting-started/02-quickstart.md +++ b/docs/en/getting-started/02-quickstart.md @@ -40,6 +40,7 @@ If you prefer to run OpenViking as a standalone service, Docker is recommended. container_name: openviking ports: - "1933:1933" + - "8020:8020" volumes: - ~/.openviking/ov.conf:/app/ov.conf - ~/.openviking/data:/app/data @@ -50,6 +51,8 @@ If you prefer to run OpenViking as a standalone service, Docker is recommended. docker-compose up -d ``` + By default, the container starts the OpenViking API server on `1933`, the Console UI on `8020`, and the bundled `vikingbot` gateway. If you need to disable `vikingbot`, add either `command: ["--without-bot"]` or `environment: ["OPENVIKING_WITH_BOT=0"]`. + > **💡 Mac Local Network Access Tip (Connection reset error):** > > By default, OpenViking only listens to `127.0.0.1` for security reasons. If you are using Docker on a Mac, your host machine may not be able to access it directly via `localhost:1933`. @@ -61,6 +64,7 @@ If you prefer to run OpenViking as a standalone service, Docker is recommended. > openviking: > image: ghcr.io/volcengine/openviking:main > ports: +> - "8020:8020" > - "1933:1934" # Map host 1933 to container 1934 > volumes: > - ~/.openviking/ov.conf:/app/ov.conf diff --git a/docs/en/guides/03-deployment.md b/docs/en/guides/03-deployment.md index c49406ed1..e5f8ea169 100644 --- a/docs/en/guides/03-deployment.md +++ b/docs/en/guides/03-deployment.md @@ -199,6 +199,38 @@ OpenViking provides pre-built Docker images published to GitHub Container Regist docker run -d \ --name openviking \ -p 1933:1933 \ + -p 8020:8020 \ + -v ~/.openviking/ov.conf:/app/ov.conf \ + -v /var/lib/openviking/data:/app/data \ + --restart unless-stopped \ + ghcr.io/volcengine/openviking:main +``` + +By default, the Docker image starts: +- OpenViking HTTP server on `1933` +- OpenViking Console on `8020` +- `vikingbot` gateway + +If you want to disable `vikingbot` for a specific container run, use either of the following: + +```bash +docker run -d \ + --name openviking \ + -p 1933:1933 \ + -p 8020:8020 \ + -v ~/.openviking/ov.conf:/app/ov.conf \ + -v /var/lib/openviking/data:/app/data \ + --restart unless-stopped \ + ghcr.io/volcengine/openviking:main \ + --without-bot +``` + +```bash +docker run -d \ + --name openviking \ + -e OPENVIKING_WITH_BOT=0 \ + -p 1933:1933 \ + -p 8020:8020 \ -v ~/.openviking/ov.conf:/app/ov.conf \ -v /var/lib/openviking/data:/app/data \ --restart unless-stopped \ @@ -211,6 +243,10 @@ You can also use Docker Compose with the `docker-compose.yml` provided in the pr docker compose up -d ``` +After startup, you can access: +- API server: `http://localhost:1933` +- Console UI: `http://localhost:8020` + To build the image yourself: `docker build -t openviking:latest .` ### Kubernetes + Helm diff --git a/docs/zh/getting-started/02-quickstart.md b/docs/zh/getting-started/02-quickstart.md index d9969308f..6ca39d263 100644 --- a/docs/zh/getting-started/02-quickstart.md +++ b/docs/zh/getting-started/02-quickstart.md @@ -40,6 +40,7 @@ pip install openviking --upgrade --force-reinstall container_name: openviking ports: - "1933:1933" + - "8020:8020" volumes: - ~/.openviking/ov.conf:/app/ov.conf - ~/.openviking/data:/app/data @@ -50,6 +51,8 @@ pip install openviking --upgrade --force-reinstall docker-compose up -d ``` + 默认情况下,容器会同时启动 OpenViking API 服务(`1933`)、Console 界面(`8020`)以及内置的 `vikingbot` gateway。如果你需要关闭 `vikingbot`,可以在 Compose 里增加 `command: ["--without-bot"]`,或者设置 `environment: ["OPENVIKING_WITH_BOT=0"]`。 + > **💡 Mac 本地网络访问提示 (Connection reset 报错):** > > 默认情况下,OpenViking 为了安全仅监听 `127.0.0.1`。如果你在 Mac 上使用 Docker,宿主机可能无法直接通过 `localhost:1933` 访问。 @@ -61,6 +64,7 @@ pip install openviking --upgrade --force-reinstall > openviking: > image: ghcr.io/volcengine/openviking:main > ports: +> - "8020:8020" > - "1933:1934" # 将宿主机 1933 映射到容器 1934 > volumes: > - ~/.openviking/ov.conf:/app/ov.conf diff --git a/docs/zh/guides/03-deployment.md b/docs/zh/guides/03-deployment.md index 278c3e863..a13408b2e 100644 --- a/docs/zh/guides/03-deployment.md +++ b/docs/zh/guides/03-deployment.md @@ -197,6 +197,38 @@ OpenViking 提供预构建的 Docker 镜像,发布在 GitHub Container Registr docker run -d \ --name openviking \ -p 1933:1933 \ + -p 8020:8020 \ + -v ~/.openviking/ov.conf:/app/ov.conf \ + -v /var/lib/openviking/data:/app/data \ + --restart unless-stopped \ + ghcr.io/volcengine/openviking:main +``` + +Docker 镜像默认会同时启动: +- OpenViking HTTP 服务,端口 `1933` +- OpenViking Console,端口 `8020` +- `vikingbot` gateway + +如果你希望本次容器启动时关闭 `vikingbot`,可以使用下面任一方式: + +```bash +docker run -d \ + --name openviking \ + -p 1933:1933 \ + -p 8020:8020 \ + -v ~/.openviking/ov.conf:/app/ov.conf \ + -v /var/lib/openviking/data:/app/data \ + --restart unless-stopped \ + ghcr.io/volcengine/openviking:main \ + --without-bot +``` + +```bash +docker run -d \ + --name openviking \ + -e OPENVIKING_WITH_BOT=0 \ + -p 1933:1933 \ + -p 8020:8020 \ -v ~/.openviking/ov.conf:/app/ov.conf \ -v /var/lib/openviking/data:/app/data \ --restart unless-stopped \ @@ -209,6 +241,10 @@ docker run -d \ docker compose up -d ``` +启动后可以访问: +- API 服务:`http://localhost:1933` +- Console 界面:`http://localhost:8020` + 如需自行构建镜像:`docker build -t openviking:latest .` ### Kubernetes + Helm diff --git a/pyproject.toml b/pyproject.toml index 72d759c4d..ee4153a32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -185,6 +185,7 @@ exclude = ["tests*", "docs*", "examples*"] [tool.setuptools.package-data] openviking = [ "prompts/templates/**/*.yaml", + "console/static/**/*", "bin/agfs-server", "bin/agfs-server.exe", "lib/libagfsbinding.so", @@ -199,7 +200,6 @@ vikingbot = [ "**/*.mjs", "skills/**/*.md", "skills/**/*.sh", - "console/static/**/*", "bridge/**/*", ] diff --git a/setup.py b/setup.py index f7baaf65c..b162775a6 100644 --- a/setup.py +++ b/setup.py @@ -480,6 +480,7 @@ def finalize_options(self): "lib/libagfsbinding.dll", "bin/ov", "bin/ov.exe", + "console/static/**/*", "storage/vectordb/engine/*.abi3.so", "storage/vectordb/engine/*.pyd", ], diff --git a/tests/misc/test_docker_console_defaults.py b/tests/misc/test_docker_console_defaults.py deleted file mode 100644 index b2c1bfcd3..000000000 --- a/tests/misc/test_docker_console_defaults.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd. -# SPDX-License-Identifier: AGPL-3.0 - -from pathlib import Path - -REPO_ROOT = Path(__file__).resolve().parents[2] - - -def _read_text(relative_path: str) -> str: - return (REPO_ROOT / relative_path).read_text(encoding="utf-8") - - -def test_dockerfile_defaults_to_console_entrypoint_runtime(): - dockerfile = _read_text("Dockerfile") - - assert ( - "COPY docker/openviking-console-entrypoint.sh /usr/local/bin/openviking-console-entrypoint" - in dockerfile - ) - assert "uv sync --locked --no-editable --extra bot" in dockerfile - assert "EXPOSE 1933 8020" in dockerfile - assert 'ENTRYPOINT ["openviking-console-entrypoint"]' in dockerfile - - -def test_console_entrypoint_starts_server_then_console(): - entrypoint = _read_text("docker/openviking-console-entrypoint.sh") - - assert 'WITH_BOT="${OPENVIKING_WITH_BOT:-1}"' in entrypoint - assert "--without-bot" in entrypoint - assert "openviking-server --with-bot" in entrypoint - assert 'SERVER_URL="http://127.0.0.1:1933"' in entrypoint - assert 'SERVER_HEALTH_URL="${SERVER_URL}/health"' in entrypoint - assert 'CONSOLE_PORT="${OPENVIKING_CONSOLE_PORT:-8020}"' in entrypoint - assert "python -m openviking.console.bootstrap" in entrypoint - assert '--port "${CONSOLE_PORT}"' in entrypoint - assert '--openviking-url "${SERVER_URL}"' in entrypoint - - -def test_console_entrypoint_passthroughs_custom_runtime_commands(): - entrypoint = _read_text("docker/openviking-console-entrypoint.sh") - - assert 'exec "$@"' in entrypoint - assert '"openviking"' not in entrypoint - - -def test_docker_compose_exposes_console_port(): - compose = _read_text("docker-compose.yml") - - assert '- "1933:1933"' in compose - assert '- "8020:8020"' in compose