预构建Gitea CI工具链镜像
固定Node、Rust、Chrome与系统依赖并生成内容寻址镜像 四个CI任务改用genarrative-ci并保留独立npm ci 补充镜像构建装载导出和运行时沙箱校验脚本 同步开发运维文档与项目共享记忆
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Genarrative 容器化压测与隔离部署方案
|
||||
# Genarrative 容器化压测、隔离部署与 CI Job 镜像
|
||||
|
||||
本目录只服务本机或预发的容器化模拟压测,不替换当前生产 `systemd + Nginx + Jenkins` 发布路径。生产服务器仍以 `deploy/systemd/`、`deploy/nginx/`、`scripts/jenkins-*.sh` 和 `scripts/deploy/production-api-deploy.sh` 为准。
|
||||
本目录同时保存两类互不替代的容器资产:本机或预发的容器化模拟压测,以及 Gitea Actions 使用的预构建 CI job 镜像。它们都不替换当前生产 `systemd + Nginx + Jenkins` 发布路径;生产服务器仍以 `deploy/systemd/`、`deploy/nginx/`、`scripts/jenkins-*.sh` 和 `scripts/deploy/production-api-deploy.sh` 为准。
|
||||
|
||||
## 拓扑
|
||||
|
||||
@@ -58,6 +58,33 @@ Linux Docker Engine 若要从宿主机 CLI 连到容器内服务,直接用 `ht
|
||||
|
||||
`api-server` 容器镜像只构建 Linux release API 二进制,不构建 `spacetime-module`。当前 `api-server -> spacetime-client -> spacetimedb-sdk 2.6.1` 依赖链要求 Rust 1.93,因此 `deploy/container/api-server.Dockerfile` 的 Rust builder 固定为 `rust:1.93-bookworm`。镜像构建阶段会同时复制 `public/`,用于满足 API 二进制里 `include_bytes!` 引用的内置素材;不要把 `public/generated-*` 放入镜像上下文。如果本机 Docker Hub 拉取失败,可以先在本机准备同名本地 builder 镜像,但不要把临时 bootstrap 容器或私有 registry 凭据写入仓库。
|
||||
|
||||
### Gitea CI 预构建 Job 镜像
|
||||
|
||||
`.gitea/workflows/project-ci.yml` 的四个 job 统一使用 `deploy/container/gitea-ci-job.Dockerfile` 构建的 `genarrative-ci` 环境。镜像固定 Ubuntu job base digest `sha256:58ea92624c7c09582e05594d95488331045053d3a3f34cf09649f2a32313a614` 和 Rust stage digest `sha256:19817ead3289c8c631c73df281e18b59b172f6a31f4f563290f69cddd06c30e9`;Node `22.23.1` 发行包在解压前执行 SHA-256 校验,Google Linux 主签名指纹固定为 `EB4C1BFD4F042F6DDDCCEC917721F63BD38B4796`,Chrome 固定为 `150.0.7871.181-1`。镜像预装 Rust `1.96.0`、`rustfmt`、Chrome、`bwrap`、`rg`、`ffmpeg`、`clang/lld` 和 Tauri / 后端系统依赖,并设置 `RUSTUP_AUTO_INSTALL=0`;仓库工具链变更时必须先重建镜像,不允许 job 现场下载补齐。
|
||||
|
||||
构建、校验和装入 runner 内层 Docker:
|
||||
|
||||
```bash
|
||||
bash scripts/gitea-ci-job-image.sh build
|
||||
bash scripts/gitea-ci-job-image.sh verify
|
||||
bash scripts/gitea-ci-job-image.sh export /仓库外受控路径/genarrative-gitea-project-ci-20260722.1.tar.zst
|
||||
bash scripts/gitea-ci-job-image.sh load-runner
|
||||
```
|
||||
|
||||
默认构建 tag 为 `genarrative/gitea-project-ci:20260722.1`。脚本将 build context 固定为 `deploy/container`,不会把整个工作区发送给 Docker daemon;`build` 完成后会自动运行环境校验,`load-runner` 还会比对宿主和 runner 内层的完整 Image ID,并在内层执行 bwrap 与 Chrome headless canary。当前验证镜像约 `1.416 GB`,完整 Image ID 为 `sha256:62304a788905cec805bf0ae3638c2811bf530b2f5709523277d816edb4772942`。执行这些命令不要求必须使用 root,但执行账号必须有权访问宿主 Docker API 并管理 runner 容器;没有该权限时交给 runner 运维人员执行。
|
||||
|
||||
runner 配置保留原 `ubuntu-latest` 映射,另外增加 `genarrative-ci:docker://sha256:62304a788905cec805bf0ae3638c2811bf530b2f5709523277d816edb4772942`。内层 Docker 数据必须持久化,`force_pull` 保持 `false`;该精确 Image ID 在内层不存在时 job 应直接失败,不回退到浮动 tag 或现场拉取。四个 job 开头均以 `GENARRATIVE_GITEA_CI_CHECK_RUNTIME=1` 执行 `scripts/check-gitea-ci-job-image.sh`,同时验工具链、bwrap 和 Chrome headless;它们仍各自运行 `npm ci` 以校验当前 lockfile 并隔离 PR 依赖,不把 `node_modules` 烘进镜像,本阶段也不启用 Actions cache。
|
||||
|
||||
更新顺序固定为:
|
||||
|
||||
1. 执行 `build` / `verify`,记录输出的完整 Image ID;用 `export` 将镜像和便携 SHA-256 sidecar 保存到仓库外受控位置。
|
||||
2. 执行 `load-runner`,确认该 ID 已进入 runner 内层 Docker。
|
||||
3. 确认没有活跃 job,将当前 runner config 备份到仓库外的受控位置;备份不得进入 Git,也不得在文档或日志中回显注册信息。
|
||||
4. 增加或替换 `genarrative-ci` 的精确 `docker://<Image ID>` 映射,然后执行 `docker restart --timeout 660 gitea-runner`。
|
||||
5. 重跑真实 PR 的四个 CI job;全部通过且隔离边界复核完成后,才能清理旧镜像。
|
||||
|
||||
回滚时先把 workflow 的 `runs-on` 改回 `ubuntu-latest`,再恢复备份的 runner config 并用同一超时重启 runner。不要在真实 CI 验证前删除旧映射或旧镜像。
|
||||
|
||||
## 启动与验证
|
||||
|
||||
```bash
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
ARG RUST_IMAGE=rust:1.96-bookworm@sha256:19817ead3289c8c631c73df281e18b59b172f6a31f4f563290f69cddd06c30e9
|
||||
ARG RUNNER_IMAGE=docker.gitea.com/runner-images:ubuntu-latest@sha256:58ea92624c7c09582e05594d95488331045053d3a3f34cf09649f2a32313a614
|
||||
|
||||
FROM ${RUST_IMAGE} AS rust-toolchain
|
||||
|
||||
RUN rustup component add rustfmt \
|
||||
&& rustc --version \
|
||||
&& cargo --version \
|
||||
&& rustfmt --version
|
||||
|
||||
FROM ${RUNNER_IMAGE}
|
||||
|
||||
ARG NODE_VERSION=22.23.1
|
||||
ARG NODE_LINUX_X64_SHA256=9749e988f437343b7fa832c69ded82a312e41a03116d766797ac14f6f9eee578
|
||||
ARG GOOGLE_CHROME_VERSION=150.0.7871.181-1
|
||||
ARG GOOGLE_LINUX_SIGNING_KEY_FINGERPRINT=EB4C1BFD4F042F6DDDCCEC917721F63BD38B4796
|
||||
|
||||
LABEL org.opencontainers.image.title="Genarrative Gitea CI job image" \
|
||||
org.opencontainers.image.description="Ubuntu 24.04 CI image with Node 22, Rust 1.96, Chrome, and native build dependencies" \
|
||||
org.opencontainers.image.version="2026.07.22.1"
|
||||
|
||||
RUN test "$(dpkg --print-architecture)" = "amd64" \
|
||||
&& find /etc/apt/sources.list.d -maxdepth 1 -type f \
|
||||
! -name ubuntu.sources -delete \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
bubblewrap \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
clang \
|
||||
cmake \
|
||||
curl \
|
||||
ffmpeg \
|
||||
file \
|
||||
libayatana-appindicator3-dev \
|
||||
libclang-dev \
|
||||
libcurl4-openssl-dev \
|
||||
librsvg2-dev \
|
||||
libssl-dev \
|
||||
libwebkit2gtk-4.1-dev \
|
||||
libxdo-dev \
|
||||
lld \
|
||||
patchelf \
|
||||
pkg-config \
|
||||
ripgrep \
|
||||
wget \
|
||||
xz-utils \
|
||||
&& google_key="$(mktemp)" \
|
||||
&& curl --retry 3 --retry-all-errors --retry-delay 2 \
|
||||
--proto '=https' --tlsv1.2 -fsSL \
|
||||
https://dl.google.com/linux/linux_signing_key.pub \
|
||||
-o "${google_key}" \
|
||||
&& test "$(gpg --batch --show-keys --with-colons "${google_key}" \
|
||||
| awk -F: '$1 == "fpr" { print $10; exit }')" \
|
||||
= "${GOOGLE_LINUX_SIGNING_KEY_FINGERPRINT}" \
|
||||
&& install -d -m 0755 /etc/apt/keyrings \
|
||||
&& install -m 0644 "${google_key}" /etc/apt/keyrings/google-chrome.asc \
|
||||
&& printf '%s\n' \
|
||||
'deb [arch=amd64 signed-by=/etc/apt/keyrings/google-chrome.asc] https://dl.google.com/linux/chrome/deb/ stable main' \
|
||||
> /etc/apt/sources.list.d/google-chrome.list \
|
||||
&& rm -f "${google_key}" \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
"google-chrome-stable=${GOOGLE_CHROME_VERSION}" \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN node_archive="node-v${NODE_VERSION}-linux-x64.tar.xz" \
|
||||
&& curl --retry 3 --retry-all-errors --retry-delay 2 \
|
||||
--proto '=https' --tlsv1.2 -fsSLO \
|
||||
"https://nodejs.org/dist/v${NODE_VERSION}/${node_archive}" \
|
||||
&& printf '%s %s\n' "${NODE_LINUX_X64_SHA256}" "${node_archive}" \
|
||||
| sha256sum --check --strict \
|
||||
&& install -d -m 0755 /usr/local/lib/genarrative-node \
|
||||
&& tar -xJf "${node_archive}" \
|
||||
--strip-components=1 \
|
||||
--directory /usr/local/lib/genarrative-node \
|
||||
&& rm -f "${node_archive}" \
|
||||
&& ln -sfn /usr/local/lib/genarrative-node/bin/node /usr/local/bin/node \
|
||||
&& ln -sfn /usr/local/lib/genarrative-node/bin/npm /usr/local/bin/npm \
|
||||
&& ln -sfn /usr/local/lib/genarrative-node/bin/npx /usr/local/bin/npx \
|
||||
&& ln -sfn /usr/local/lib/genarrative-node/bin/corepack /usr/local/bin/corepack
|
||||
|
||||
COPY --from=rust-toolchain /usr/local/cargo /usr/local/cargo
|
||||
COPY --from=rust-toolchain /usr/local/rustup /usr/local/rustup
|
||||
|
||||
RUN install -m 0755 /usr/local/cargo/bin/rustup /usr/local/bin/rustup \
|
||||
&& for command_name in cargo cargo-fmt rustc rustdoc rustfmt; do \
|
||||
ln -sfn rustup "/usr/local/bin/${command_name}"; \
|
||||
done
|
||||
|
||||
ENV CARGO_HOME=/usr/local/cargo \
|
||||
RUSTUP_AUTO_INSTALL=0 \
|
||||
RUSTUP_HOME=/usr/local/rustup \
|
||||
PATH=/usr/local/lib/genarrative-node/bin:/usr/local/bin:/usr/local/cargo/bin:/opt/acttoolcache/node/24.18.0/x64/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
|
||||
|
||||
ARG IMAGE_REVISION=uncommitted
|
||||
LABEL org.opencontainers.image.vendor="GenarrativeAI" \
|
||||
org.opencontainers.image.source="https://git.genarrative.world/GenarrativeAI/Genarrative" \
|
||||
org.opencontainers.image.revision="${IMAGE_REVISION}" \
|
||||
org.opencontainers.image.base.name="docker.gitea.com/runner-images:ubuntu-latest@sha256:58ea92624c7c09582e05594d95488331045053d3a3f34cf09649f2a32313a614" \
|
||||
com.genarrative.ci.dockerfile="deploy/container/gitea-ci-job.Dockerfile" \
|
||||
com.genarrative.ci.definition-sha256="${IMAGE_REVISION}"
|
||||
|
||||
RUN node --version \
|
||||
&& npm --version \
|
||||
&& rustup show active-toolchain \
|
||||
&& rustc --version \
|
||||
&& cargo --version \
|
||||
&& rustfmt --version \
|
||||
&& google-chrome --version \
|
||||
&& bwrap --version \
|
||||
&& rg --version \
|
||||
&& ffmpeg -version | head -n 1
|
||||
Reference in New Issue
Block a user