mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
container builds: opt-in extension deps via OPENCLAW_EXTENSIONS build arg (#32223)
* Docker: opt-in extension deps via OPENCLAW_EXTENSIONS build arg Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: sallyom <somalley@redhat.com> * CI: clarify extension smoke scope * Tests: allow digest-pinned multi-stage FROM lines * Changelog: note container extension preinstall option --------- Signed-off-by: sallyom <somalley@redhat.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
10
.github/workflows/install-smoke.yml
vendored
10
.github/workflows/install-smoke.yml
vendored
@@ -41,6 +41,16 @@ jobs:
|
||||
docker build -t openclaw-dockerfile-smoke:local -f Dockerfile .
|
||||
docker run --rm --entrypoint sh openclaw-dockerfile-smoke:local -lc 'which openclaw && openclaw --version'
|
||||
|
||||
# This smoke only validates that the build-arg path preinstalls selected
|
||||
# extension deps without breaking image build or basic CLI startup. It
|
||||
# does not exercise runtime loading/registration of diagnostics-otel.
|
||||
- name: Smoke test Dockerfile with extension build arg
|
||||
run: |
|
||||
docker build \
|
||||
--build-arg OPENCLAW_EXTENSIONS="diagnostics-otel" \
|
||||
-t openclaw-ext-smoke:local -f Dockerfile .
|
||||
docker run --rm --entrypoint sh openclaw-ext-smoke:local -lc 'which openclaw && openclaw --version'
|
||||
|
||||
- name: Run installer docker tests
|
||||
env:
|
||||
CLAWDBOT_INSTALL_URL: https://openclaw.ai/install.sh
|
||||
|
||||
@@ -25,6 +25,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Hooks/Compaction lifecycle: emit `session:compact:before` and `session:compact:after` internal events plus plugin compaction callbacks with session/count metadata, so automations can react to compaction runs consistently. (#16788) thanks @vincentkoc.
|
||||
- Agents/context engine plugin interface: add `ContextEngine` plugin slot with full lifecycle hooks (`bootstrap`, `ingest`, `assemble`, `compact`, `afterTurn`, `prepareSubagentSpawn`, `onSubagentEnded`), slot-based registry with config-driven resolution, `LegacyContextEngine` wrapper preserving existing compaction behavior, scoped subagent runtime for plugin runtimes via `AsyncLocalStorage`, and `sessions.get` gateway method. Enables plugins like `lossless-claw` to provide alternative context management strategies without modifying core compaction logic. Zero behavior change when no context engine plugin is configured. (#22201) thanks @jalehman.
|
||||
- CLI: make read-only SecretRef status flows degrade safely (#37023) thanks @joshavant.
|
||||
- Docker/Podman extension dependency baking: add `OPENCLAW_EXTENSIONS` so container builds can preinstall selected bundled extension npm dependencies into the image for faster and more reproducible startup in container deployments. (#32223) Thanks @sallyom.
|
||||
|
||||
### Breaking
|
||||
|
||||
|
||||
21
Dockerfile
21
Dockerfile
@@ -1,3 +1,22 @@
|
||||
# Opt-in extension dependencies at build time (space-separated directory names).
|
||||
# Example: docker build --build-arg OPENCLAW_EXTENSIONS="diagnostics-otel matrix" .
|
||||
#
|
||||
# A multi-stage build is used instead of `RUN --mount=type=bind` because
|
||||
# bind mounts require BuildKit, which is not available in plain Docker.
|
||||
# This stage extracts only the package.json files we need from extensions/,
|
||||
# so the main build layer is not invalidated by unrelated extension source changes.
|
||||
ARG OPENCLAW_EXTENSIONS=""
|
||||
FROM node:22-bookworm@sha256:cd7bcd2e7a1e6f72052feb023c7f6b722205d3fcab7bbcbd2d1bfdab10b1e935 AS ext-deps
|
||||
ARG OPENCLAW_EXTENSIONS
|
||||
COPY extensions /tmp/extensions
|
||||
RUN mkdir -p /out && \
|
||||
for ext in $OPENCLAW_EXTENSIONS; do \
|
||||
if [ -f "/tmp/extensions/$ext/package.json" ]; then \
|
||||
mkdir -p "/out/$ext" && \
|
||||
cp "/tmp/extensions/$ext/package.json" "/out/$ext/package.json"; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
FROM node:22-bookworm@sha256:cd7bcd2e7a1e6f72052feb023c7f6b722205d3fcab7bbcbd2d1bfdab10b1e935
|
||||
|
||||
# OCI base-image metadata for downstream image consumers.
|
||||
@@ -35,6 +54,8 @@ COPY --chown=node:node ui/package.json ./ui/package.json
|
||||
COPY --chown=node:node patches ./patches
|
||||
COPY --chown=node:node scripts ./scripts
|
||||
|
||||
COPY --from=ext-deps --chown=node:node /out/ ./extensions/
|
||||
|
||||
USER node
|
||||
# Reduce OOM risk on low-memory hosts during dependency installation.
|
||||
# Docker builds on small VMs may otherwise fail with "Killed" (exit 137).
|
||||
|
||||
@@ -200,6 +200,7 @@ export OPENCLAW_BRIDGE_PORT="${OPENCLAW_BRIDGE_PORT:-18790}"
|
||||
export OPENCLAW_GATEWAY_BIND="${OPENCLAW_GATEWAY_BIND:-lan}"
|
||||
export OPENCLAW_IMAGE="$IMAGE_NAME"
|
||||
export OPENCLAW_DOCKER_APT_PACKAGES="${OPENCLAW_DOCKER_APT_PACKAGES:-}"
|
||||
export OPENCLAW_EXTENSIONS="${OPENCLAW_EXTENSIONS:-}"
|
||||
export OPENCLAW_EXTRA_MOUNTS="$EXTRA_MOUNTS"
|
||||
export OPENCLAW_HOME_VOLUME="$HOME_VOLUME_NAME"
|
||||
export OPENCLAW_ALLOW_INSECURE_PRIVATE_WS="${OPENCLAW_ALLOW_INSECURE_PRIVATE_WS:-}"
|
||||
@@ -378,6 +379,7 @@ upsert_env "$ENV_FILE" \
|
||||
OPENCLAW_EXTRA_MOUNTS \
|
||||
OPENCLAW_HOME_VOLUME \
|
||||
OPENCLAW_DOCKER_APT_PACKAGES \
|
||||
OPENCLAW_EXTENSIONS \
|
||||
OPENCLAW_SANDBOX \
|
||||
OPENCLAW_DOCKER_SOCKET \
|
||||
DOCKER_GID \
|
||||
@@ -388,6 +390,7 @@ if [[ "$IMAGE_NAME" == "openclaw:local" ]]; then
|
||||
echo "==> Building Docker image: $IMAGE_NAME"
|
||||
docker build \
|
||||
--build-arg "OPENCLAW_DOCKER_APT_PACKAGES=${OPENCLAW_DOCKER_APT_PACKAGES}" \
|
||||
--build-arg "OPENCLAW_EXTENSIONS=${OPENCLAW_EXTENSIONS}" \
|
||||
--build-arg "OPENCLAW_INSTALL_DOCKER_CLI=${OPENCLAW_INSTALL_DOCKER_CLI:-}" \
|
||||
-t "$IMAGE_NAME" \
|
||||
-f "$ROOT_DIR/Dockerfile" \
|
||||
|
||||
@@ -60,6 +60,7 @@ Optional env vars:
|
||||
|
||||
- `OPENCLAW_IMAGE` — use a remote image instead of building locally (e.g. `ghcr.io/openclaw/openclaw:latest`)
|
||||
- `OPENCLAW_DOCKER_APT_PACKAGES` — install extra apt packages during build
|
||||
- `OPENCLAW_EXTENSIONS` — pre-install extension dependencies at build time (space-separated extension names, e.g. `diagnostics-otel matrix`)
|
||||
- `OPENCLAW_EXTRA_MOUNTS` — add extra host bind mounts
|
||||
- `OPENCLAW_HOME_VOLUME` — persist `/home/node` in a named volume
|
||||
- `OPENCLAW_SANDBOX` — opt in to Docker gateway sandbox bootstrap. Only explicit truthy values enable it: `1`, `true`, `yes`, `on`
|
||||
@@ -320,6 +321,31 @@ Notes:
|
||||
- If you change `OPENCLAW_DOCKER_APT_PACKAGES`, rerun `docker-setup.sh` to rebuild
|
||||
the image.
|
||||
|
||||
### Pre-install extension dependencies (optional)
|
||||
|
||||
Extensions with their own `package.json` (e.g. `diagnostics-otel`, `matrix`,
|
||||
`msteams`) install their npm dependencies on first load. To bake those
|
||||
dependencies into the image instead, set `OPENCLAW_EXTENSIONS` before
|
||||
running `docker-setup.sh`:
|
||||
|
||||
```bash
|
||||
export OPENCLAW_EXTENSIONS="diagnostics-otel matrix"
|
||||
./docker-setup.sh
|
||||
```
|
||||
|
||||
Or when building directly:
|
||||
|
||||
```bash
|
||||
docker build --build-arg OPENCLAW_EXTENSIONS="diagnostics-otel matrix" .
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- This accepts a space-separated list of extension directory names (under `extensions/`).
|
||||
- Only extensions with a `package.json` are affected; lightweight plugins without one are ignored.
|
||||
- If you change `OPENCLAW_EXTENSIONS`, rerun `docker-setup.sh` to rebuild
|
||||
the image.
|
||||
|
||||
### Power-user / full-featured container (opt-in)
|
||||
|
||||
The default Docker image is **security-first** and runs as the non-root `node`
|
||||
|
||||
@@ -32,6 +32,11 @@ By default the container is **not** installed as a systemd service, you start it
|
||||
|
||||
(Or set `OPENCLAW_PODMAN_QUADLET=1`; use `--container` to install only the container and launch script.)
|
||||
|
||||
Optional build-time env vars (set before running `setup-podman.sh`):
|
||||
|
||||
- `OPENCLAW_DOCKER_APT_PACKAGES` — install extra apt packages during image build
|
||||
- `OPENCLAW_EXTENSIONS` — pre-install extension dependencies (space-separated extension names, e.g. `diagnostics-otel matrix`)
|
||||
|
||||
**2. Start gateway** (manual, for quick smoke testing):
|
||||
|
||||
```bash
|
||||
|
||||
@@ -209,7 +209,10 @@ if ! run_as_openclaw test -f "$OPENCLAW_JSON"; then
|
||||
fi
|
||||
|
||||
echo "Building image from $REPO_PATH..."
|
||||
podman build -t openclaw:local -f "$REPO_PATH/Dockerfile" "$REPO_PATH"
|
||||
BUILD_ARGS=()
|
||||
[[ -n "${OPENCLAW_DOCKER_APT_PACKAGES:-}" ]] && BUILD_ARGS+=(--build-arg "OPENCLAW_DOCKER_APT_PACKAGES=${OPENCLAW_DOCKER_APT_PACKAGES}")
|
||||
[[ -n "${OPENCLAW_EXTENSIONS:-}" ]] && BUILD_ARGS+=(--build-arg "OPENCLAW_EXTENSIONS=${OPENCLAW_EXTENSIONS}")
|
||||
podman build ${BUILD_ARGS[@]+"${BUILD_ARGS[@]}"} -t openclaw:local -f "$REPO_PATH/Dockerfile" "$REPO_PATH"
|
||||
|
||||
echo "Loading image into $OPENCLAW_USER's Podman store..."
|
||||
TMP_IMAGE="$(mktemp -p /tmp openclaw-image.XXXXXX.tar)"
|
||||
|
||||
@@ -42,7 +42,7 @@ describe("docker base image pinning", () => {
|
||||
.find((line) => line.trimStart().startsWith("FROM "));
|
||||
expect(fromLine, `${dockerfilePath} should define a FROM line`).toBeDefined();
|
||||
expect(fromLine, `${dockerfilePath} FROM must be digest-pinned`).toMatch(
|
||||
/^FROM\s+\S+@sha256:[a-f0-9]{64}$/,
|
||||
/^FROM\s+\S+@sha256:[a-f0-9]{64}(?:\s+AS\s+\S+)?$/,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user