Files
WeChat-AI/Dockerfile
T

76 lines
2.8 KiB
Docker

# syntax=docker/dockerfile:1
# WeChat-AI (iLink + Redis + LINUX DO OAuth)
#
# Prefer host wrappers (bump + OTA pack + docker):
# pnpm docker:build -- -- docker build -t your-dockerhub-user/wechat-ai:latest .
# pnpm docker:up
# Publish channel: /admin → 上传通道包 (dist/release/<ver>/files.json)
# Plain `docker build` does NOT bump or pack.
#
# 必填环境变量见 .env.example / docs/docker.md
FROM node:22-bookworm-slim
LABEL org.opencontainers.image.title="wechat-ai" \
org.opencontainers.image.description="WeChat roleplay bots via iLink, Redis, LINUX DO OAuth"
# Keep corepack/pnpm under /pnpm so the non-root runtime user can use them
# without writing to /home/appuser/.cache (which caused EACCES).
ENV PNPM_HOME=/pnpm \
COREPACK_HOME=/pnpm/corepack \
PATH=/pnpm:$PATH \
NODE_ENV=production \
WECHAT_AI_HOST=0.0.0.0 \
WECHAT_AI_PORT=8787 \
COREPACK_ENABLE_DOWNLOAD_PROMPT=0
RUN corepack enable \
&& corepack prepare [email protected] --activate \
&& apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Install deps first (better layer cache)
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml tsconfig.base.json ./
COPY apps/api/package.json ./apps/api/
COPY packages/core/package.json ./packages/core/
COPY packages/db/package.json ./packages/db/
COPY packages/ilink/package.json ./packages/ilink/
COPY packages/llm/package.json ./packages/llm/
# tsx is a runtime dependency of @wechat-ai/api; install all workspace packages
RUN pnpm install --frozen-lockfile
# Application source (TypeScript run via tsx)
COPY apps/api ./apps/api
COPY packages ./packages
COPY scripts ./scripts
# Non-root user + writable home for tools
RUN mkdir -p /home/appuser \
&& groupadd --system --gid 1001 nodejs \
&& useradd --system --uid 1001 --gid nodejs --home-dir /home/appuser --no-create-home appuser \
&& chown -R appuser:nodejs /app /pnpm /home/appuser
USER appuser
EXPOSE 8787
# scrypt (login + provider-secret KDF) runs on the libuv pool; the default 4
# threads let a login burst queue behind itself.
ENV UV_THREADPOOL_SIZE=16
HEALTHCHECK --interval=30s --timeout=8s --start-period=50s --retries=3 \
CMD node -e "fetch('http://127.0.0.1:'+(process.env.WECHAT_AI_PORT||8787)+'/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
# Run node as PID 1 so SIGTERM reaches the process and the graceful shutdown
# in index.ts actually runs (releasing bot leases). `sh -c` swallowed it, so
# every deploy left up to LEASE_TTL_SEC of bots that no node was polling.
# The separate seed step is gone — index.ts already calls seedPersonas().
# WORKDIR is apps/api because tsx is linked under apps/api/node_modules;
# resolveRepoRoot() still walks up to /app for .env and OTA paths.
WORKDIR /app/apps/api
CMD ["node", "--import", "tsx", "src/index.ts"]