Files
WeKnora/docker/Dockerfile.app
T
wizardchen 7dc17a6d92 feat(plugin): run code plugins in an embedded plugin host
Host-runtime plugins (runtime: { type: host, kind: binary }) now install and
run. Each node's host starts the package's binary for its OS and arch as a
child process and only lets calls through once the process printed its
handshake, answers health checks, and reports the installed plugin ID,
version and protocol and every code contribution plugin.yaml declares. A
crash or three failed health checks restarts it with backoff; the node
reports the plugin degraded meanwhile. An upgrade starts the new process
before stopping the old one. Linux children die with WeKnora.

Isolation: the child gets a private unix socket and a random token, an
environment built from scratch so WeKnora's own secrets never reach plugin
code, and HTTP(S)_PROXY pointing at a per-plugin egress proxy that forwards
only to the hosts in permissions.egress, through the SSRF-safe dialer.

Manifests of code plugins must declare apiVersion weknora.plugin/v1, and
egress entries must be host names or *.domain wildcards. Web search and data
source connectors are open to third-party code plugins. The installer
accepts host packages that carry a binary for the server's OS and arch.
2026-09-25 22:33:48 +08:00

159 lines
5.7 KiB
Docker

# Build extension and daemon from the same pinned source on the runtime architecture.
FROM --platform=$TARGETPLATFORM node:24-bookworm-slim@sha256:ba849c60be29959425b8734d57b8b4b7d56f98edd9504c9af091d5281095a71e AS browserskill
WORKDIR /build
RUN apt-get update && \
apt-get install -y --no-install-recommends git python3 ca-certificates curl build-essential cmake pkg-config && \
rm -rf /var/lib/apt/lists/*
ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo
ENV PATH=/usr/local/cargo/bin:$PATH
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable
COPY scripts/build_browserskill.sh scripts/browserskill-release.json ./scripts/
ARG TARGETOS
ARG TARGETARCH
RUN bash scripts/build_browserskill.sh /opt/weknora/browserskill "${TARGETOS}/${TARGETARCH}"
# Build stage
FROM golang:1.26-bookworm AS builder
WORKDIR /app
# 通过构建参数接收敏感信息
ARG GOPRIVATE_ARG
ARG GOPROXY_ARG
ARG GOSUMDB_ARG=off
ARG APK_MIRROR_ARG
# 设置Go环境变量
ENV GOPRIVATE=${GOPRIVATE_ARG}
ENV GOPROXY=${GOPROXY_ARG}
ENV GOSUMDB=${GOSUMDB_ARG}
# Install dependencies
RUN if [ -n "$APK_MIRROR_ARG" ]; then \
sed -i "s@deb.debian.org@${APK_MIRROR_ARG}@g" /etc/apt/sources.list.d/debian.sources; \
fi && \
apt-get update && \
apt-get install -y git build-essential libsqlite3-dev curl
# Install migrate tool
RUN go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
# Copy go mod files. go.mod replace-points anydoc at ./third_party/anydoc-go
# and the plugin SDK at ./pluginsdk, so their go.mod files must exist before
# `go mod download`.
COPY go.mod go.sum ./
COPY third_party/anydoc-go/go.mod third_party/anydoc-go/go.mod
COPY pluginsdk/go.mod pluginsdk/go.mod
RUN --mount=type=cache,target=/go/pkg/mod go mod download
COPY cmd/download cmd/download
RUN go run cmd/download/duckdb/duckdb.go
COPY . .
RUN --mount=type=cache,target=/go/pkg/mod bash ./scripts/copy-licenses.sh /license-bundle
# Get version and commit info for build injection
ARG VERSION_ARG
ARG COMMIT_ID_ARG
ARG BUILD_TIME_ARG
ARG GO_VERSION_ARG
# Set build-time variables
ENV VERSION=${VERSION_ARG}
ENV COMMIT_ID=${COMMIT_ID_ARG}
ENV BUILD_TIME=${BUILD_TIME_ARG}
ENV GO_VERSION=${GO_VERSION_ARG}
# Link the anydoc parser engine (office docs converted in-process, no
# Python docreader). Default on so Hub / compose images ship a working
# engine; pass WITH_ANYDOC=0 to skip the Rust toolchain (~few minutes and
# ~1 GB of build-stage layers).
ARG WITH_ANYDOC=1
ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo
ENV PATH=/usr/local/cargo/bin:$PATH
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/usr/local/cargo/git \
if [ "$WITH_ANYDOC" = "1" ]; then \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --profile minimal --default-toolchain stable && \
./scripts/build-anydoc-lib.sh; \
fi
# Build the application with version info
RUN --mount=type=cache,target=/go/pkg/mod \
if [ "$WITH_ANYDOC" = "1" ]; then \
make build-prod GO_BUILD_TAGS=anydoc; \
else \
make build-prod; \
fi
RUN --mount=type=cache,target=/go/pkg/mod cp -r /go/pkg/mod/github.com/yanyiwu/ /app/yanyiwu/
# Final stage
FROM debian:12.12-slim
WORKDIR /app
ARG APK_MIRROR_ARG
# Pairing derives the gateway URL from the user's page origin by default.
ENV BROWSERSKILL_BINARY=/opt/weknora/browserskill/bsk \
BROWSERSKILL_EXTENSION_PATH=/opt/weknora/browserskill/browser-skill-weknora-0.3.1.zip
COPY --from=browserskill /opt/weknora/browserskill /opt/weknora/browserskill
# Create a non-root user first
RUN useradd -m -s /bin/bash appuser
# First, install ca-certificates without mirror to ensure HTTPS works
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates && \
rm -rf /var/lib/apt/lists/*
# Then switch to mirror if specified and install other packages
RUN if [ -n "$APK_MIRROR_ARG" ]; then \
sed -i "s@deb.debian.org@${APK_MIRROR_ARG}@g" /etc/apt/sources.list.d/debian.sources; \
fi && \
apt-get update && \
apt-get install -y --no-install-recommends \
build-essential postgresql-client default-mysql-client tzdata sed curl bash vim wget \
libsqlite3-0 \
python3 python3-pip python3-dev libffi-dev libssl-dev \
nodejs npm \
gosu \
ffmpeg && \
python3 -m pip install --break-system-packages --upgrade pip setuptools wheel && \
mkdir -p /home/appuser/.local/bin && \
curl -LsSf https://astral.sh/uv/install.sh | CARGO_HOME=/home/appuser/.cargo UV_INSTALL_DIR=/home/appuser/.local/bin sh && \
chown -R appuser:appuser /home/appuser && \
ln -sf /home/appuser/.local/bin/uvx /usr/local/bin/uvx && \
chmod +x /usr/local/bin/uvx && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Create data directories and set permissions
RUN mkdir -p /data/files && \
chown -R appuser:appuser /app /data/files
# Copy migrate tool from builder stage
COPY --from=builder /go/bin/migrate /usr/local/bin/
COPY --from=builder /app/yanyiwu/ /go/pkg/mod/github.com/yanyiwu/
# Copy the binary from the builder stage
COPY --from=builder /app/config ./config
COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/migrations ./migrations
COPY --from=builder /app/dataset/samples ./dataset/samples
COPY --from=builder /root/.duckdb /home/appuser/.duckdb
COPY --from=builder /app/WeKnora .
COPY --from=builder /license-bundle/ ./
# Copy and make entrypoint script executable
COPY --from=builder /app/scripts/docker-entrypoint.sh ./scripts/docker-entrypoint.sh
# Make scripts executable
RUN chmod +x ./scripts/*.sh
# Expose ports
EXPOSE 8080
ENTRYPOINT ["./scripts/docker-entrypoint.sh"]
CMD ["./WeKnora"]