mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-26 23:27:51 +00:00
docker: support optional pip packages in local builds (#83850)
Summary: - Adds `OPENCLAW_IMAGE_PIP_PACKAGES` as an opt-in Dockerfile build arg, passes it through Docker and Podman local setup, and documents/tests the new local image-build option. - Reproducibility: not applicable. this is an additive Docker/Podman build capability, not a bug report. The s ... image importing requested Python packages, and the branch diff wires the renamed arg through Docker/Podman. Automerge notes: - PR branch already contained follow-up commit before automerge: docker: support optional pip packages in local builds Validation: - ClawSweeper review passed for head0ccec19206. - Required merge gates passed before the squash merge. Prepared head SHA:0ccec19206Review: https://github.com/openclaw/openclaw/pull/83850#issuecomment-4483676614 Co-authored-by: Stephen Redmond <stephen.redmond@straiteis.ie> Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -21,6 +21,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Browser: surface pending and recently handled modal dialogs in snapshots, return `blockedByDialog` when an action opens a modal, and allow `browser dialog --dialog-id` to answer pending dialogs.
|
||||
- Browser CLI: add `openclaw browser evaluate --timeout-ms` so long-running page functions can extend both the evaluate action and request timeout budgets. (#83447) Thanks @eefreenyc.
|
||||
- Codex app-server: scope OpenClaw prompt guidance by runtime surface so native Codex keeps Codex-owned base/personality instructions while OpenClaw contributes only runtime context, delivery guidance, and explicitly scoped command hints. (#83454) Thanks @100yenadmin.
|
||||
- Docker/Podman: add `OPENCLAW_IMAGE_PIP_PACKAGES` for opt-in Python package installation in local image builds. (#83771) Thanks @stephenredmond-straiteis.
|
||||
- Agents/tools: shorten built-in tool descriptions and schema hints across media, messaging, sessions, cron, Gateway, web, image/PDF, TTS, nodes, and plan tools while preserving routing guardrails.
|
||||
- Skills: add node inspector debugging, fused diagram generation, and throwaway spike workflow skills.
|
||||
- CLI/plugins: add `defineToolPlugin` plus `openclaw plugins build`, `validate`, and `init` for typed simple tool plugins with generated manifest metadata, optional tool declarations, and context factories.
|
||||
|
||||
13
Dockerfile
13
Dockerfile
@@ -210,6 +210,19 @@ RUN --mount=type=cache,id=openclaw-bookworm-apt-cache,target=/var/cache/apt,shar
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $packages; \
|
||||
fi
|
||||
|
||||
# Install additional Python packages needed by your plugins or skills.
|
||||
# Example: docker build --build-arg OPENCLAW_IMAGE_PIP_PACKAGES="requests humanize" .
|
||||
ARG OPENCLAW_IMAGE_PIP_PACKAGES=""
|
||||
RUN --mount=type=cache,id=openclaw-bookworm-apt-cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,id=openclaw-bookworm-apt-lists,target=/var/lib/apt,sharing=locked \
|
||||
if [ -n "$OPENCLAW_IMAGE_PIP_PACKAGES" ]; then \
|
||||
if ! python3 -m pip --version >/dev/null 2>&1; then \
|
||||
apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends python3-pip; \
|
||||
fi && \
|
||||
python3 -m pip install --no-cache-dir --break-system-packages $OPENCLAW_IMAGE_PIP_PACKAGES; \
|
||||
fi
|
||||
|
||||
# Optionally install Chromium and Xvfb for browser automation.
|
||||
# Build with: docker build --build-arg OPENCLAW_INSTALL_BROWSER=1 ...
|
||||
# Adds ~300MB but eliminates the 60-90s Playwright install on every container start.
|
||||
|
||||
@@ -127,6 +127,7 @@ The setup script accepts these optional environment variables:
|
||||
| ------------------------------------------ | --------------------------------------------------------------------- |
|
||||
| `OPENCLAW_IMAGE` | Use a remote image instead of building locally |
|
||||
| `OPENCLAW_IMAGE_APT_PACKAGES` | Install extra apt packages during build (space-separated) |
|
||||
| `OPENCLAW_IMAGE_PIP_PACKAGES` | Install extra Python packages during build (space-separated) |
|
||||
| `OPENCLAW_EXTENSIONS` | Pre-install plugin dependencies at build time (space-separated names) |
|
||||
| `OPENCLAW_EXTRA_MOUNTS` | Extra host bind mounts (comma-separated `source:target[:opts]`) |
|
||||
| `OPENCLAW_HOME_VOLUME` | Persist `/home/node` in a named Docker volume |
|
||||
@@ -148,6 +149,9 @@ container without `brew`; those dependencies must be provided by a custom image
|
||||
or installed manually. For dependencies available from Debian packages, use
|
||||
`OPENCLAW_IMAGE_APT_PACKAGES` during image build. The legacy
|
||||
`OPENCLAW_DOCKER_APT_PACKAGES` name is still accepted.
|
||||
For Python dependencies, use `OPENCLAW_IMAGE_PIP_PACKAGES`. This runs
|
||||
`python3 -m pip install --break-system-packages` during the image build, so pin
|
||||
package versions and use only package indexes you trust.
|
||||
|
||||
Maintainers can test bundled plugin source against a packaged image by mounting
|
||||
one plugin source directory over its packaged source path, for example
|
||||
@@ -423,13 +427,14 @@ See [ClawDock](/install/clawdock) for the full helper guide.
|
||||
|
||||
1. **Persist `/home/node`**: `export OPENCLAW_HOME_VOLUME="openclaw_home"`
|
||||
2. **Bake system deps**: `export OPENCLAW_IMAGE_APT_PACKAGES="git curl jq"`
|
||||
3. **Bake Playwright Chromium**: `export OPENCLAW_INSTALL_BROWSER=1`
|
||||
4. **Or install Playwright browsers into a persisted volume**:
|
||||
3. **Bake Python deps**: `export OPENCLAW_IMAGE_PIP_PACKAGES="requests==2.32.5 humanize==4.14.0"`
|
||||
4. **Bake Playwright Chromium**: `export OPENCLAW_INSTALL_BROWSER=1`
|
||||
5. **Or install Playwright browsers into a persisted volume**:
|
||||
```bash
|
||||
docker compose run --rm openclaw-cli \
|
||||
node /app/node_modules/playwright-core/cli.js install chromium
|
||||
```
|
||||
5. **Persist browser downloads**: use `OPENCLAW_HOME_VOLUME` or
|
||||
6. **Persist browser downloads**: use `OPENCLAW_HOME_VOLUME` or
|
||||
`OPENCLAW_EXTRA_MOUNTS`. OpenClaw auto-detects the Docker image's
|
||||
Playwright-managed Chromium on Linux.
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ Optional build/setup env vars:
|
||||
|
||||
- `OPENCLAW_IMAGE` or `OPENCLAW_PODMAN_IMAGE` -- use an existing/pulled image instead of building `openclaw:local`
|
||||
- `OPENCLAW_IMAGE_APT_PACKAGES` -- install extra apt packages during image build (also accepts legacy `OPENCLAW_DOCKER_APT_PACKAGES`)
|
||||
- `OPENCLAW_IMAGE_PIP_PACKAGES` -- install extra Python packages during image build; pin versions and use only package indexes you trust
|
||||
- `OPENCLAW_EXTENSIONS` -- pre-install plugin dependencies at build time
|
||||
- `OPENCLAW_INSTALL_BROWSER` -- pre-install Chromium and Xvfb for browser automation (set to `1` to enable)
|
||||
|
||||
|
||||
@@ -180,9 +180,10 @@ vim ~/.openclaw/.env
|
||||
|
||||
See `.env.example` for all supported keys.
|
||||
|
||||
The `Dockerfile` supports two optional build args:
|
||||
The `Dockerfile` supports optional build args:
|
||||
|
||||
- `OPENCLAW_IMAGE_APT_PACKAGES` — extra apt packages to install (e.g. `ffmpeg`); also accepts legacy `OPENCLAW_DOCKER_APT_PACKAGES`
|
||||
- `OPENCLAW_IMAGE_PIP_PACKAGES` — extra Python packages to install (e.g. `requests==2.32.5`); pin versions and use only package indexes you trust
|
||||
- `OPENCLAW_INSTALL_BROWSER=1` — pre-install Chromium for browser automation (adds ~300MB, but skips the 60-90s Playwright install on each container start)
|
||||
|
||||
### How It Works in Docker
|
||||
|
||||
@@ -297,6 +297,7 @@ export OPENCLAW_GATEWAY_BIND="${OPENCLAW_GATEWAY_BIND:-lan}"
|
||||
export OPENCLAW_DISABLE_BONJOUR="${OPENCLAW_DISABLE_BONJOUR:-}"
|
||||
export OPENCLAW_IMAGE="$IMAGE_NAME"
|
||||
export OPENCLAW_IMAGE_APT_PACKAGES="${OPENCLAW_IMAGE_APT_PACKAGES-${OPENCLAW_DOCKER_APT_PACKAGES:-}}"
|
||||
export OPENCLAW_IMAGE_PIP_PACKAGES="${OPENCLAW_IMAGE_PIP_PACKAGES:-}"
|
||||
export OPENCLAW_EXTENSIONS="${OPENCLAW_EXTENSIONS:-}"
|
||||
export OPENCLAW_INSTALL_BROWSER="${OPENCLAW_INSTALL_BROWSER:-}"
|
||||
export OPENCLAW_EXTRA_MOUNTS="$EXTRA_MOUNTS"
|
||||
@@ -501,6 +502,7 @@ upsert_env "$ENV_FILE" \
|
||||
OPENCLAW_EXTRA_MOUNTS \
|
||||
OPENCLAW_HOME_VOLUME \
|
||||
OPENCLAW_IMAGE_APT_PACKAGES \
|
||||
OPENCLAW_IMAGE_PIP_PACKAGES \
|
||||
OPENCLAW_EXTENSIONS \
|
||||
OPENCLAW_INSTALL_BROWSER \
|
||||
OPENCLAW_SANDBOX \
|
||||
@@ -523,6 +525,7 @@ if [[ "$IMAGE_NAME" == "openclaw:local" ]]; then
|
||||
echo "==> Building Docker image: $IMAGE_NAME"
|
||||
run_docker_build \
|
||||
--build-arg "OPENCLAW_IMAGE_APT_PACKAGES=${OPENCLAW_IMAGE_APT_PACKAGES}" \
|
||||
--build-arg "OPENCLAW_IMAGE_PIP_PACKAGES=${OPENCLAW_IMAGE_PIP_PACKAGES}" \
|
||||
--build-arg "OPENCLAW_EXTENSIONS=${OPENCLAW_EXTENSIONS}" \
|
||||
--build-arg "OPENCLAW_INSTALL_BROWSER=${OPENCLAW_INSTALL_BROWSER}" \
|
||||
--build-arg "OPENCLAW_INSTALL_DOCKER_CLI=${OPENCLAW_INSTALL_DOCKER_CLI:-}" \
|
||||
|
||||
@@ -359,10 +359,14 @@ ensure_private_existing_dir_owned_by_user "config directory" "$OPENCLAW_CONFIG_D
|
||||
ensure_private_existing_dir_owned_by_user "workspace directory" "$OPENCLAW_WORKSPACE_DIR"
|
||||
|
||||
OPENCLAW_IMAGE_APT_PACKAGES="${OPENCLAW_IMAGE_APT_PACKAGES-${OPENCLAW_DOCKER_APT_PACKAGES:-}}"
|
||||
OPENCLAW_IMAGE_PIP_PACKAGES="${OPENCLAW_IMAGE_PIP_PACKAGES:-}"
|
||||
BUILD_ARGS=()
|
||||
if [[ -n "$OPENCLAW_IMAGE_APT_PACKAGES" ]]; then
|
||||
BUILD_ARGS+=(--build-arg "OPENCLAW_IMAGE_APT_PACKAGES=${OPENCLAW_IMAGE_APT_PACKAGES}")
|
||||
fi
|
||||
if [[ -n "$OPENCLAW_IMAGE_PIP_PACKAGES" ]]; then
|
||||
BUILD_ARGS+=(--build-arg "OPENCLAW_IMAGE_PIP_PACKAGES=${OPENCLAW_IMAGE_PIP_PACKAGES}")
|
||||
fi
|
||||
if [[ -n "${OPENCLAW_EXTENSIONS:-}" ]]; then
|
||||
BUILD_ARGS+=(--build-arg "OPENCLAW_EXTENSIONS=${OPENCLAW_EXTENSIONS}")
|
||||
fi
|
||||
|
||||
@@ -3,6 +3,7 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
const SCRIPT_PATH = "scripts/test-install-sh-docker.sh";
|
||||
const DOCKER_SETUP_PATH = "scripts/docker/setup.sh";
|
||||
const PODMAN_SETUP_PATH = "scripts/podman/setup.sh";
|
||||
const SMOKE_RUNNER_PATH = "scripts/docker/install-sh-smoke/run.sh";
|
||||
const BUN_GLOBAL_SMOKE_PATH = "scripts/e2e/bun-global-install-smoke.sh";
|
||||
const BUN_GLOBAL_ASSERTIONS_PATH = "scripts/e2e/lib/bun-global-install/assertions.mjs";
|
||||
@@ -95,6 +96,30 @@ describe("test-install-sh-docker", () => {
|
||||
expect(script).toContain('--build-arg "OPENCLAW_INSTALL_BROWSER=${OPENCLAW_INSTALL_BROWSER}"');
|
||||
});
|
||||
|
||||
it("passes image-scoped pip packages through Docker and Podman setup", () => {
|
||||
const dockerSetup = readFileSync(DOCKER_SETUP_PATH, "utf8");
|
||||
const podmanSetup = readFileSync(PODMAN_SETUP_PATH, "utf8");
|
||||
const dockerfile = readFileSync("Dockerfile", "utf8");
|
||||
|
||||
expect(dockerfile).toContain("ARG OPENCLAW_IMAGE_PIP_PACKAGES");
|
||||
expect(dockerfile).toContain(
|
||||
"python3 -m pip install --no-cache-dir --break-system-packages $OPENCLAW_IMAGE_PIP_PACKAGES",
|
||||
);
|
||||
expect(dockerSetup).toContain(
|
||||
'export OPENCLAW_IMAGE_PIP_PACKAGES="${OPENCLAW_IMAGE_PIP_PACKAGES:-}"',
|
||||
);
|
||||
expect(dockerSetup).toContain("OPENCLAW_IMAGE_PIP_PACKAGES \\");
|
||||
expect(dockerSetup).toContain(
|
||||
'--build-arg "OPENCLAW_IMAGE_PIP_PACKAGES=${OPENCLAW_IMAGE_PIP_PACKAGES}"',
|
||||
);
|
||||
expect(dockerSetup).not.toContain("OPENCLAW_DOCKER_PIP_PACKAGES");
|
||||
expect(podmanSetup).toContain('OPENCLAW_IMAGE_PIP_PACKAGES="${OPENCLAW_IMAGE_PIP_PACKAGES:-}"');
|
||||
expect(podmanSetup).toContain(
|
||||
'BUILD_ARGS+=(--build-arg "OPENCLAW_IMAGE_PIP_PACKAGES=${OPENCLAW_IMAGE_PIP_PACKAGES}")',
|
||||
);
|
||||
expect(podmanSetup).not.toContain("OPENCLAW_DOCKER_PIP_PACKAGES");
|
||||
});
|
||||
|
||||
it("allows repository branch history and release tags for secret-backed Docker release checks", () => {
|
||||
const workflow = readFileSync(LIVE_E2E_WORKFLOW_PATH, "utf8");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user