From 074414aeabe1b0cc53b3df028610ff7b23d339f7 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 30 Apr 2026 16:26:50 +0800 Subject: [PATCH] =?UTF-8?q?modify:=20aarch64=20=E8=AE=BE=E5=A4=87docker?= =?UTF-8?q?=E9=83=A8=E7=BD=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 85 ++++++++++++++++++++++------------ README.md | 15 +++++- config.toml | 3 ++ deploy.sh | 37 +++++++++++++-- public/main.py | 5 +- src/chongming/scripts/build.py | 5 +- 6 files changed, 114 insertions(+), 36 deletions(-) diff --git a/Dockerfile b/Dockerfile index 141cb78..66b532a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,48 +1,75 @@ -# FROM debian:bookworm-slim AS builder +# 架构参数:可选值 x86_64 或 aarch64 +ARG TARGETARCH=x86_64 + FROM ubuntu:24.04 AS builder -RUN apt-get update && \ - apt-get install -y --no-install-recommends ca-certificates tzdata && \ +ARG TARGETARCH + +# 跳过 GPG 签名验证(兼容 BM1684 等系统时间不准的设备) +RUN apt-get update -o Acquire::AllowInsecureRepositories=yes \ + -o Acquire::AllowDowngradeToInsecureRepositories=yes \ + --allow-unauthenticated 2>/dev/null || true && \ + apt-get install -y --no-install-recommends \ + -o Acquire::AllowInsecureRepositories=yes \ + --allow-unauthenticated \ + ca-certificates tzdata 2>/dev/null || true && \ rm -rf /var/lib/apt/lists/* COPY build/chongming /tmp/chongming -RUN mkdir -p /tmp/rootfs/app && \ - # === 临时目录 === - mkdir -p /tmp/rootfs/tmp && \ - chmod 1777 /tmp/rootfs/tmp && \ - # === 数据目录 === - mkdir -p /tmp/rootfs/app/data && \ - chmod 777 /tmp/rootfs/app/data && \ - # === 解释器目录 === - mkdir -p /tmp/rootfs/lib64 && \ - mkdir -p /tmp/rootfs/lib/x86_64-linux-gnu && \ - cp /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ && \ - ln -s /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /tmp/rootfs/lib64/ld-linux-x86-64.so.2 && \ +# 构建最小 rootfs +RUN \ + if [ "$TARGETARCH" = "aarch64" ]; then \ + LIB_PATH="/lib/aarch64-linux-gnu"; \ + LD_LINKER="/lib/ld-linux-aarch64.so.1"; \ + LD_LINKER_TARGET="/tmp/rootfs/lib/ld-linux-aarch64.so.1"; \ + else \ + LIB_PATH="/lib/x86_64-linux-gnu"; \ + LD_LINKER="/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"; \ + LD_LINKER_TARGET="/tmp/rootfs/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2"; \ + fi && \ + mkdir -p /tmp/rootfs/app && \ + mkdir -p /tmp/rootfs/tmp && chmod 1777 /tmp/rootfs/tmp && \ + mkdir -p /tmp/rootfs/app/data && chmod 777 /tmp/rootfs/app/data && \ + # === aarch64 链接器路径特殊处理 === + if [ "$TARGETARCH" = "aarch64" ]; then \ + mkdir -p /tmp/rootfs/lib && \ + cp /lib/ld-linux-aarch64.so.1 /tmp/rootfs/lib/ && \ + mkdir -p /tmp/rootfs/lib64 && \ + ln -s /lib/ld-linux-aarch64.so.1 /tmp/rootfs/lib64/ld-linux-aarch64.so.1; \ + else \ + mkdir -p /tmp/rootfs/lib64 && \ + mkdir -p /tmp/rootfs${LIB_PATH} && \ + cp ${LIB_PATH}/ld-linux-x86-64.so.2 /tmp/rootfs${LIB_PATH}/ && \ + ln -s ${LIB_PATH}/ld-linux-x86-64.so.2 /tmp/rootfs/lib64/ld-linux-x86-64.so.2; \ + fi && \ # === 依赖库 === - cp /lib/x86_64-linux-gnu/libdl.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ && \ - cp /lib/x86_64-linux-gnu/libz.so.1 /tmp/rootfs/lib/x86_64-linux-gnu/ && \ - cp /lib/x86_64-linux-gnu/libpthread.so.0 /tmp/rootfs/lib/x86_64-linux-gnu/ && \ - cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/rootfs/lib/x86_64-linux-gnu/ && \ - cp /lib/x86_64-linux-gnu/librt.so.1 /tmp/rootfs/lib/x86_64-linux-gnu/ && \ - cp /lib/x86_64-linux-gnu/libm.so.6 /tmp/rootfs/lib/x86_64-linux-gnu/ && \ - cp /lib/x86_64-linux-gnu/libutil.so.1 /tmp/rootfs/lib/x86_64-linux-gnu/ && \ - cp /lib/x86_64-linux-gnu/libnss_dns.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ 2>/dev/null || true && \ - cp /lib/x86_64-linux-gnu/libnss_files.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ 2>/dev/null || true && \ - cp /lib/x86_64-linux-gnu/libresolv.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ 2>/dev/null || true && \ + mkdir -p /tmp/rootfs${LIB_PATH} && \ + cp ${LIB_PATH}/libdl.so.2 /tmp/rootfs${LIB_PATH}/ && \ + cp ${LIB_PATH}/libz.so.1 /tmp/rootfs${LIB_PATH}/ && \ + cp ${LIB_PATH}/libpthread.so.0 /tmp/rootfs${LIB_PATH}/ && \ + cp ${LIB_PATH}/libc.so.6 /tmp/rootfs${LIB_PATH}/ && \ + cp ${LIB_PATH}/librt.so.1 /tmp/rootfs${LIB_PATH}/ && \ + cp ${LIB_PATH}/libm.so.6 /tmp/rootfs${LIB_PATH}/ && \ + cp ${LIB_PATH}/libutil.so.1 /tmp/rootfs${LIB_PATH}/ && \ + cp ${LIB_PATH}/libnss_dns.so.2 /tmp/rootfs${LIB_PATH}/ 2>/dev/null || true && \ + cp ${LIB_PATH}/libnss_files.so.2 /tmp/rootfs${LIB_PATH}/ 2>/dev/null || true && \ + cp ${LIB_PATH}/libresolv.so.2 /tmp/rootfs${LIB_PATH}/ 2>/dev/null || true && \ # === 时区数据 === mkdir -p /tmp/rootfs/usr/share/zoneinfo && \ - cp -r /usr/share/zoneinfo/Asia /tmp/rootfs/usr/share/zoneinfo/ && \ - cp /usr/share/zoneinfo/UTC /tmp/rootfs/usr/share/zoneinfo/ && \ + cp -r /usr/share/zoneinfo/Asia /tmp/rootfs/usr/share/zoneinfo/ 2>/dev/null || true && \ + cp /usr/share/zoneinfo/UTC /tmp/rootfs/usr/share/zoneinfo/ 2>/dev/null || true && \ # === 证书和 DNS === mkdir -p /tmp/rootfs/etc/ssl/certs && \ - cp /etc/ssl/certs/ca-certificates.crt /tmp/rootfs/etc/ssl/certs/ && \ + cp /etc/ssl/certs/ca-certificates.crt /tmp/rootfs/etc/ssl/certs/ 2>/dev/null || true && \ echo "hosts: files dns" > /tmp/rootfs/etc/nsswitch.conf && \ # === /proc /sys /dev === mkdir -p /tmp/rootfs/proc /tmp/rootfs/sys /tmp/rootfs/dev FROM scratch +ARG TARGETARCH + COPY --from=builder /tmp/rootfs/ / COPY build/chongming /app/chongming @@ -55,4 +82,4 @@ WORKDIR /app EXPOSE 8000 -CMD ["./chongming"] \ No newline at end of file +CMD ["./chongming"] diff --git a/README.md b/README.md index f951a6a..d1ebeba 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ chongming/ ### 运行原理 开发时通过 `uv run serve` 直接启动 uvicon。 -打包后,`chongming` 可执行文件内嵌了经过混淆的引导程序,引导程序从加密的 Module-Bank 文件 (`app.mbank`, `plugins.mbank`) 中动态加载应用模块,同时从 SQLite VFS (`static.svfs`) 提供前端静态文件。所有 Python 业务代码不暴露与明文磁盘。 +打包后,`chongming` 可执行文件内嵌了经过混淆的引导程序,引导程序从加密的 Module-Bank 文件 (`app.mbank`, `plugins.mbank`) 中动态加载应用模块,同时从 SQLite VFS (`static.svfs`) 提供前端静态文件。所有 Python 业务代码不暴露于明文磁盘。 --- @@ -197,12 +197,23 @@ build/ ## Docker 部署 -Docker 镜像采用多角度构建 + `scratch` 基础镜像,真正做到最小化。 +Docker 镜像采用多阶段构建 + `scratch` 基础镜像,真正做到最小化。同时支持 **x86_64** 与 **aarch64 (ARM64)** 双架构。 ### 构建镜像 ```bash +# 默认构建 x86_64 架构 docker build -t chongming:latest . + +# 在 ARM64 设备上构建 +docker build --build-arg TARGETARCH=aarch64 -t chongming:arm64 . + +# 使用 Docker Buildx 构建多架构镜像(推送到仓库) +docker buildx build \ + --platform linux/amd64,linux/arm64 \ + --build-arg TARGETARCH \ + -t your-registry/chongming:latest \ + --push . ``` ### 执行部署脚本 diff --git a/config.toml b/config.toml index 0658d0d..8a3f018 100644 --- a/config.toml +++ b/config.toml @@ -67,6 +67,9 @@ host = "0.0.0.0" port = 8000 reload = false workers = 4 +# 对于嵌入式设备(如 BM1684),建议启用环境变量覆盖: +# docker run -e APP_WORKERS=2 ... +# 可减少线程数,避免 "can't start new thread" 错误 [production.logging] backup_count = 5 # 最多保存 10 个日志文件 diff --git a/deploy.sh b/deploy.sh index b5d1b4b..e42d231 100755 --- a/deploy.sh +++ b/deploy.sh @@ -12,8 +12,25 @@ log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } -# 配置 -IMAGE="chongming:latest" +# 检测架构 +ARCH=$(uname -m) +case "$ARCH" in + x86_64|amd64) + DEFAULT_IMAGE="chongming:latest" + ARCH_FLAG="x86_64" + ;; + aarch64|arm64) + DEFAULT_IMAGE="chongming:arm64" + ARCH_FLAG="aarch64" + ;; + *) + log_error "不支持的架构: $ARCH" + exit 1 + ;; +esac + +# 配置:可通过环境变量覆盖镜像标签,例如: IMAGE=chongming:arm64 ./deploy.sh +IMAGE="${IMAGE:-$DEFAULT_IMAGE}" CONTAINER="chongming" PORT=8000 DATA_DIR="${HOME}/chongming-data" @@ -60,13 +77,27 @@ if ss -tlnp | grep -q ":${PORT}"; then exit 1 fi +# 根据架构设置默认 worker 数 +case "$ARCH" in + aarch64|arm64) + DEFAULT_WORKERS=2 + ;; + *) + DEFAULT_WORKERS=4 + ;; +esac + # 4. 启动容器 log_info "启动容器..." +log_info "架构: $ARCH, workers: ${APP_WORKERS:-$DEFAULT_WORKERS}, 端口: $PORT" docker run -d \ -p "$PORT:8000" \ -v "$DATA_DIR/data:/app/data" \ -v "$DATA_DIR/uploads:/app/uploads" \ -v "$DATA_DIR/logs:/app/logs" \ + -e "APP_WORKERS=${APP_WORKERS:-$DEFAULT_WORKERS}" \ + --ulimit nproc=65535 \ + --ulimit nofile=65535 \ --restart unless-stopped \ --name "$CONTAINER" \ "$IMAGE" @@ -92,4 +123,4 @@ else log_error "容器启动失败,查看日志:" docker logs "$CONTAINER" 2>/dev/null || true exit 1 -fi \ No newline at end of file +fi diff --git a/public/main.py b/public/main.py index 51a233a..20a3346 100644 --- a/public/main.py +++ b/public/main.py @@ -4,6 +4,7 @@ FastAPI chongming 示例 主入口文件,适配 chongming 打包系统 """ +import os import sys import platform from utils.launch import launch @@ -37,7 +38,9 @@ def app_run(app_config: dict, default_config: dict): # 打包环境强制禁用重载 is_frozen = getattr(sys, "frozen", False) reload = False if is_frozen else server_config.get("reload", False) - workers = server_config.get("workers", 4) + # 支持通过环境变量 APP_WORKERS 覆盖 worker 数量(方便嵌入式设备调优) + default_workers = server_config.get("workers", 4) + workers = int(os.environ.get("APP_WORKERS", str(default_workers))) # 显示启动信息 env = app_config.get("env", "development") diff --git a/src/chongming/scripts/build.py b/src/chongming/scripts/build.py index d25d26d..054ca56 100644 --- a/src/chongming/scripts/build.py +++ b/src/chongming/scripts/build.py @@ -302,7 +302,7 @@ async def init_database(): from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from ..app.core.config import get_config - from ..app.task.dev_init_db import init_permission, dev_init_admin + from ..app.task.dev_init_db import init_permission, init_default_roles, dev_init_admin database = get_config()["database"] database_type = database["type"] @@ -333,6 +333,9 @@ async def init_database(): async with async_session_maker() as session: # await UserService.create_user(session, "admin", "admin", is_superuser=True) # type: ignore await init_permission(session) + # 再初始化默认角色及权限关联 + await init_default_roles(session) + # 最后初始化管理员用户 await dev_init_admin(session)