# ============================================================================= # AstroResearch Dockerfile — Mode A (外部 obscura 二进制) # ============================================================================= # # 构建: # docker build -t astroresearch:latest . # # 海外网络构建: # docker build --build-arg USE_MIRRORS=0 -t astroresearch:latest . # # 运行: # docker run -d --name astro -p 8000:8000 --env-file .env \ # -v ./library:/app/library \ # -v ./logs:/app/logs \ # -v ./skills:/app/skills:ro \ # -v ./bin:/app/bin:ro \ # astroresearch:latest # ============================================================================= # ─── Stage 1: 前端 ─────────────────────────────────────────────────────────── FROM node:22-alpine AS frontend-builder ARG USE_MIRRORS=1 WORKDIR /app/dashboard RUN if [ "$USE_MIRRORS" = "1" ]; then \ npm config set registry https://registry.npmmirror.com; \ fi COPY dashboard/package.json dashboard/package-lock.json ./ RUN npm ci COPY dashboard/ ./ RUN npm run build # ─── Stage 2: Rust 后端 (musl 静态链接) ────────────────────────────────────── FROM rust:1.94-alpine AS backend-builder ARG USE_MIRRORS=1 RUN if [ "$USE_MIRRORS" = "1" ]; then \ sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories; \ fi RUN apk add --no-cache musl-dev cmake pkgconfig openssl-dev openssl-libs-static # sqlite-vec v0.1.9 与 musl 不兼容: musl 无 BSD u_int*_t 类型 # typedef u_int8_t uint8_t → typedef uint8_t uint8_t (C11 合法) ENV CFLAGS="-Du_int8_t=uint8_t -Du_int16_t=uint16_t -Du_int64_t=uint64_t" WORKDIR /app # Cargo 解析阶段就需要可选 path 依赖存在,即使不启用对应 feature RUN mkdir -p libs/obscura/crates/obscura-browser/src && \ printf '[package]\nname = "obscura-browser"\nversion = "0.1.0"\nedition = "2021"\n\n[features]\nstealth = []\n' \ > libs/obscura/crates/obscura-browser/Cargo.toml && \ echo '' > libs/obscura/crates/obscura-browser/src/lib.rs && \ mkdir -p libs/obscura/crates/obscura-net/src && \ printf '[package]\nname = "obscura-net"\nversion = "0.1.0"\nedition = "2021"\n\n[features]\nstealth = []\n' \ > libs/obscura/crates/obscura-net/Cargo.toml && \ echo '' > libs/obscura/crates/obscura-net/src/lib.rs ENV SKIP_DASHBOARD_BUILD=1 COPY Cargo.toml Cargo.lock build.rs ./ COPY src/ ./src/ COPY migrations/ ./migrations/ COPY --from=frontend-builder /app/dashboard/dist/ ./dashboard/dist/ RUN cargo build --profile release-min && \ cp /app/target/release-min/astroresearch /usr/local/bin/astroresearch # ─── Stage 3: 运行时 ───────────────────────────────────────────────────────── FROM alpine:3.21 ARG USE_MIRRORS=1 RUN if [ "$USE_MIRRORS" = "1" ]; then \ sed -i 's|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g' /etc/apk/repositories; \ fi RUN apk add --no-cache ca-certificates tzdata RUN addgroup -g 65532 -S astro && adduser -u 65532 -S astro -G astro WORKDIR /app COPY --from=backend-builder /usr/local/bin/astroresearch /app/ COPY --from=frontend-builder /app/dashboard/dist/ ./dashboard/dist/ COPY skills/ ./skills/ COPY migrations/ ./migrations/ COPY dictionary.txt ./ RUN mkdir -p /app/library /app/logs /app/bin VOLUME ["/app/library", "/app/logs", "/app/skills", "/app/bin"] USER astro EXPOSE 8000 HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \ CMD wget -q --spider http://localhost:8000/ || exit 1 ENTRYPOINT ["/app/astroresearch"]