- 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:
@@ -0,0 +1,11 @@
|
||||
# 大目录/与镜像无关的内容不进 build context
|
||||
# 注意: dist/ 和 ota-package/ 不能忽略 —— CI 预构建产物要通过 context 进入镜像
|
||||
.git
|
||||
.gitea
|
||||
.local
|
||||
.pnpm-store
|
||||
node_modules
|
||||
src-tauri
|
||||
docs
|
||||
*.log
|
||||
readme
|
||||
@@ -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
|
||||
|
||||
@@ -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 注入, 不进镜像层
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user