ci: 优化构建速度与资源消耗
Docker Build and Push / build-image (push) Failing after 39s

- docker-build: 停用 docker system prune --volumes (保住 build 层缓存), 改为 image prune -f
- 新增 .dockerignore, node_modules/.git/src-tauri 等不再进 build context
- 前端只构建一次: CI 构建 dist 供 OTA 与镜像复用 (PREBUILT_DIST 构建参数)
- Dockerfile: npm install → npm ci + BuildKit cache mount
- setup-node 开启 npm 缓存; master/android-* 加 concurrency 取消旧 run
- android: 只构建 aarch64; tauri target 缓存 key 按 Cargo.lock hash
- minisign 改为静态二进制下载, 去掉 apt-get
This commit is contained in:
jif2.zhang
2026-10-25 00:48:50 +08:00
parent 20a5105c23
commit 51256335ba
5 changed files with 500 additions and 443 deletions
+11
View File
@@ -0,0 +1,11 @@
# 大目录/与镜像无关的内容不进 build context
# 注意: dist/ 和 ota-package/ 不能忽略 —— CI 预构建产物要通过 context 进入镜像
.git
.gitea
.local
.pnpm-store
node_modules
src-tauri
docs
*.log
readme
+12 -4
View File
@@ -7,6 +7,11 @@ on:
branches:
- 'android-*'
# 同分支连续 push 时取消旧的构建, 省资源也避免上传过时 APK
concurrency:
group: android-${{ github.ref_name }}
cancel-in-progress: true
jobs:
build-android:
runs-on: ubuntu-latest
@@ -55,7 +60,7 @@ jobs:
with:
path: |
~/.cargo
~/.rustup
~/.rustup/toolchains
# 工具链升级时 bump 版本号使缓存失效重装 (含 cargo-ndk)
key: rust-android-v1-${{ runner.os }}
@@ -63,7 +68,9 @@ jobs:
uses: https://gitea.com/actions/cache@v4
with:
path: src-tauri/target
key: tauri-target-android-${{ runner.os }}
# 依赖变化 → 新 key; 命不中时回退最近一次的 target 目录做增量编译
key: tauri-target-android-${{ hashFiles('src-tauri/Cargo.lock') }}
restore-keys: tauri-target-android-
# ---------- 安装工具链 (仅缓存未命中时) ----------
- name: Install Rust + Android targets
@@ -72,7 +79,8 @@ jobs:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
. "$HOME/.cargo/env"
rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android
# 只构建 aarch64 (现代 Android 手机); 需要模拟器/x86 设备时再加回其他 target
rustup target add aarch64-linux-android
cargo install cargo-ndk --locked
- name: Install Android SDK & NDK
@@ -130,7 +138,7 @@ jobs:
export CARGO_HOME="$HOME/.cargo"
. "$HOME/.cargo/env"
cd src-tauri
npx tauri android build --apk
npx tauri android build --apk --target aarch64
# 断言签名配置仍在且 release 块实际引用了它 (防止 tauri 重新生成 gen/android 或正则未命中)
if ! grep -q 'create("release")' gen/android/app/build.gradle.kts || ! grep -q 'signingConfig = signingConfigs.getByName("release")' gen/android/app/build.gradle.kts; then
echo "ERROR: 构建后签名配置丢失/未生效, APK 未签名" >&2
+25 -5
View File
@@ -18,6 +18,11 @@ on:
branches:
- master
# 连续 push master 时取消还在跑的旧部署, 避免排队执行过时版本的完整部署
concurrency:
group: deploy-master
cancel-in-progress: true
jobs:
build-image:
runs-on: ubuntu-latest
@@ -38,6 +43,7 @@ jobs:
uses: https://gitea.com/actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- name: Check version consistency & branch
# 1) package.json / tauri.conf.json / Cargo.toml / Cargo.lock 四处版本必须完全相等且不带 -ota
@@ -53,11 +59,18 @@ jobs:
run: npm ci --no-audit --no-fund
- name: Build frontend
# dist/ 供 OTA 打包用 (Dockerfile 内也会构建一份)
# 全流程唯一一次前端构建: dist/ 既供 OTA 打包, 也通过 build context 进入镜像
# (docker build 传 PREBUILT_DIST=true 跳过镜像内的重复构建)
run: npm run build
- name: Install minisign
run: sudo apt-get update && sudo apt-get install -y minisign
# 静态二进制直接下载, 免去每次 apt-get update + install
run: |
set -euo pipefail
mkdir -p /tmp/ms
curl -sL https://github.com/jedisct1/minisign/releases/download/0.12/minisign-0.12-linux.tar.gz | tar xz -C /tmp/ms
sudo install -m755 "$(find /tmp/ms -type f -name minisign | head -1)" /usr/local/bin/minisign
minisign -v
- name: Build & sign OTA package
# 每次主分支提交生成 OTA 升级包, sequence 默认时间戳 (单调递增)
@@ -75,7 +88,11 @@ jobs:
- name: Build Docker image
# DATABASE_URL 仅在 prisma generate 阶段需要, 可用任何合法占位串
run: docker build -t iboard:latest --build-arg DATABASE_URL=mysql://build:build@127.0.0.1:3306/build .
# PREBUILT_DIST=true: 复用上一步构建好的 dist/, 镜像内跳过前端构建
# DOCKER_BUILDKIT=1: Dockerfile 用了 cache mount 语法
run: docker build -t iboard:latest --build-arg DATABASE_URL=mysql://build:build@127.0.0.1:3306/build --build-arg PREBUILT_DIST=true .
env:
DOCKER_BUILDKIT: '1'
- name: List images
run: docker images
@@ -95,8 +112,11 @@ jobs:
- name: Remove old container
run: docker rm -vf iboard || true
- name: Recycle container
run: docker system prune --volumes -f
- name: Prune dangling images
# 只清理本项目的悬空镜像 (旧 iboard:latest 被同名新镜像顶掉后变 dangling),
# 不再用 `docker system prune --volumes` —— 那会清光宿主机 build cache,
# 导致每次部署都全量重装 npm 依赖、重跑构建
run: docker image prune -f
- name: Run container
# DATABASE_URL 通过 gitea Actions secret 注入, 不进镜像层
+7 -1
View File
@@ -46,7 +46,13 @@ jobs:
run: npm run build
- name: Install minisign
run: sudo apt-get update && sudo apt-get install -y minisign
# 静态二进制直接下载, 免去每次 apt-get update + install
run: |
set -euo pipefail
mkdir -p /tmp/ms
curl -sL https://github.com/jedisct1/minisign/releases/download/0.12/minisign-0.12-linux.tar.gz | tar xz -C /tmp/ms
sudo install -m755 "$(find /tmp/ms -type f -name minisign | head -1)" /usr/local/bin/minisign
minisign -v
- name: Build & sign OTA package
env:
+18 -6
View File
@@ -1,8 +1,11 @@
# syntax=docker/dockerfile:1
# ===============================================================
# iBoard 一体化镜像: 静态前端 (dist/) + Express API (server/) 同进程
# 构建: docker build --build-arg DATABASE_URL=... -t iboard:latest .
# 可选 --build-arg VITE_API_BASE=https://api.example.com 让前端走绝对地址
# CI 传入 --build-arg PREBUILT_DIST=true 复用 CI 已构建的 dist/ (跳过镜像内前端构建)
# 运行: docker run -d --name iboard -p 3001:3001 -e DATABASE_URL=... iboard:latest
# 需要 BuildKit (cache mount 语法; Docker 23+ 默认开启)
# ===============================================================
FROM node:22-alpine AS builder
@@ -17,18 +20,27 @@ COPY prisma ./prisma/
COPY prisma.config.ts ./
COPY generated ./generated/
# 装全量依赖 (dev 也装, 后面 build 要用)
RUN npm install
# 装全量依赖 (dev 也装, 后面 prisma generate / 本地构建前端要用)
# cache mount 复用 npm 下载缓存, 不进镜像层
RUN --mount=type=cache,target=/root/.npm npm ci
# 拷贝源码
COPY . .
# 构建前端 (输出到 dist/) 与 Prisma 客户端
RUN npx prisma generate
# 构建 Prisma 客户端
RUN --mount=type=cache,target=/root/.npm npx prisma generate
# 构建前端 (输出到 dist/)
# PREBUILT_DIST=true: CI 已在镜像外构建过 dist/ (供 OTA 打包), 直接复用, 跳过镜像内构建
ARG PREBUILT_DIST=false
# build 时把 VITE_API_BASE 写进 bundle, 默认空 = 走相对路径 /api (同源 Express)
ARG VITE_API_BASE=
ENV VITE_API_BASE=$VITE_API_BASE
RUN npm run build
RUN if [ "$PREBUILT_DIST" = "true" ]; then \
test -f dist/index.html || { echo "PREBUILT_DIST=true 但 dist/ 缺失"; exit 1; }; \
else \
npm run build; \
fi
# 运行时阶段
FROM node:22-alpine
@@ -40,7 +52,7 @@ RUN npm config set registry https://registry.npmmirror.com
# 只装运行时依赖
COPY package*.json ./
RUN npm install --omit=dev
RUN --mount=type=cache,target=/root/.npm npm ci --omit=dev
# 拷贝构建产物
COPY --from=builder /app/dist ./dist