Skip to content

Commit 5d39fc5

Browse files
committed
ci: 原生双架构并行构建 Docker 镜像并优化层缓存
1 parent daddc91 commit 5d39fc5

4 files changed

Lines changed: 266 additions & 92 deletions

File tree

‎.dockerignore‎

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,53 @@ Dockerfile
33
.dockerignore
44
docker-compose*.yml
55

6-
# 依赖和构建产物
6+
#依赖和构建产物
77
node_modules
88
npm-debug.log
99
.next
10+
.next-prebuilt
1011
dist
12+
dist-scripts
13+
data
14+
certs
1115

12-
# 版本控制
16+
# 安装包构建配置与产物(保留单元测试所需的 packaging/runtime)
17+
packaging/*
18+
!packaging/runtime
19+
20+
# 版本控制与开发配置
1321
.git
1422
.gitignore
23+
.gitattributes
24+
.githooks
25+
.editorconfig
26+
.mailmap
27+
.nvmrc
28+
.vercel
29+
.claude
1530

1631
# 环境配置
1732
.env
1833
.env.*
1934
# 本机配置与登录凭据(含密钥),运行时由挂载的配置目录提供
2035
config/app-config.json
2136
config/minimax-code.json
37+
config/background-tasks.json
2238
config/tts-cache/
2339

2440
# 构建阶段运行单元/集成测试;最终 standalone 镜像不复制测试目录
2541
coverage
2642

27-
# E2E 测试文件 (Playwright)
43+
# E2E 与外部测试、性能脚本
2844
e2e
2945
playwright.config.ts
3046
playwright-report
3147
test-results
3248
blob-report
3349
test_output*.txt
50+
upload_test_output*.txt
51+
tests
52+
perf
3453

3554
# 开发工具
3655
.vscode
@@ -41,6 +60,7 @@ test_output*.txt
4160
__pycache__
4261
*.pyc
4362
*.tsbuildinfo
63+
*.tsbuildinfoconfig
4464

4565
# 本地数据库
4666
*.db
@@ -51,5 +71,12 @@ __pycache__
5171

5272
# 文档
5373
README.md
74+
README.en.md
75+
CHANGELOG.md
76+
AGENTS.md
77+
CONTRIBUTING.md
78+
CODE_OF_CONDUCT.md
79+
SECURITY.md
80+
SUPPORT.md
5481
docs
5582
doc

‎.github/workflows/build-docker.yml‎

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,21 @@ env:
1616
IMAGE_NAME: ${{ github.repository }}
1717

1818
jobs:
19-
build-and-push:
20-
runs-on: ubuntu-latest
19+
build-and-push-arch:
20+
name: Build (${{ matrix.arch }})
2121
# 只在 GitHub 上运行;Gitea 读取 main 时会回退到本目录,需跳过
2222
if: github.server_url == 'https://github.com'
23+
strategy:
24+
fail-fast: false
25+
matrix:
26+
include:
27+
- arch: amd64
28+
platform: linux/amd64
29+
os: ubuntu-24.04
30+
- arch: arm64
31+
platform: linux/arm64
32+
os: ubuntu-24.04-arm
33+
runs-on: ${{ matrix.os }}
2334
permissions:
2435
contents: read
2536
packages: write
@@ -34,11 +45,6 @@ jobs:
3445
id: version
3546
run: echo "version=$(git describe --tags --match 'v[0-9]*' 2>/dev/null || true)" >> "$GITHUB_OUTPUT"
3647

37-
38-
# Set up QEMU for multi-arch builds
39-
- name: Set up QEMU
40-
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
41-
4248
- name: Set up Docker Buildx
4349
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
4450

@@ -49,16 +55,76 @@ jobs:
4955
username: ${{ github.actor }}
5056
password: ${{ secrets.GITHUB_TOKEN }}
5157

52-
- name: Build and push Docker image
58+
- name: Build and push Docker image by digest
59+
id: build
5360
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5.4.0
5461
with:
5562
context: .
56-
push: true
57-
platforms: linux/amd64,linux/arm64
58-
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ inputs.tag }}
63+
platforms: ${{ matrix.platform }}
5964
build-args: |
6065
APP_VERSION=${{ steps.version.outputs.version }}
6166
APP_REVISION=${{ github.sha }}
62-
TEST_TIMEOUT_MS=120000
63-
cache-from: type=gha
64-
cache-to: type=gha,mode=max
67+
outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
68+
cache-from: type=gha,scope=docker-${{ matrix.arch }}
69+
cache-to: type=gha,scope=docker-${{ matrix.arch }},mode=max
70+
71+
- name: Export digest
72+
env:
73+
DIGEST: ${{ steps.build.outputs.digest }}
74+
run: |
75+
mkdir -p /tmp/digests
76+
touch "/tmp/digests/${DIGEST#sha256:}"
77+
78+
- name: Upload digest
79+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
80+
with:
81+
name: docker-digest-${{ matrix.arch }}
82+
path: /tmp/digests/*
83+
if-no-files-found: error
84+
retention-days: 1
85+
86+
build-and-push:
87+
name: Merge & Publish Manifest
88+
runs-on: ubuntu-24.04
89+
needs: build-and-push-arch
90+
if: github.server_url == 'https://github.com'
91+
permissions:
92+
contents: read
93+
packages: write
94+
95+
steps:
96+
- name: Download digests
97+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
98+
with:
99+
path: /tmp/digests
100+
pattern: docker-digest-*
101+
merge-multiple: true
102+
103+
- name: Set up Docker Buildx
104+
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
105+
106+
- name: Log in to the Container registry
107+
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
108+
with:
109+
registry: ${{ env.REGISTRY }}
110+
username: ${{ github.actor }}
111+
password: ${{ secrets.GITHUB_TOKEN }}
112+
113+
- name: Create multi-arch manifest list and push
114+
working-directory: /tmp/digests
115+
env:
116+
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
117+
TAG: ${{ inputs.tag }}
118+
run: |
119+
sources=()
120+
for digest in *; do
121+
sources+=("${IMAGE}@sha256:${digest}")
122+
done
123+
docker buildx imagetools create -t "${IMAGE}:${TAG}" "${sources[@]}"
124+
125+
- name: Inspect image
126+
env:
127+
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
128+
TAG: ${{ inputs.tag }}
129+
run: |
130+
docker buildx imagetools inspect "${IMAGE}:${TAG}"

‎.github/workflows/ci.yml‎

Lines changed: 97 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,24 @@ jobs:
203203
retention-days: 30
204204

205205
# ============================================
206-
# Docker 构建(仅 tag push)
206+
# Docker 构建(仅 tag push,原生双架构并行构建后合并多架构 Manifest)
207207
# ============================================
208-
docker-build:
209-
runs-on: ubuntu-latest
210-
name: Docker Build & Push
208+
docker-build-arch:
209+
name: Docker Build (${{ matrix.arch }})
211210
# 只在 tag 推送时构建镜像,且须先通过公开历史检查
212211
needs: publication-check
213212
if: startsWith(github.ref, 'refs/tags/')
213+
strategy:
214+
fail-fast: false
215+
matrix:
216+
include:
217+
- arch: amd64
218+
platform: linux/amd64
219+
os: ubuntu-24.04
220+
- arch: arm64
221+
platform: linux/arm64
222+
os: ubuntu-24.04-arm
223+
runs-on: ${{ matrix.os }}
214224
permissions:
215225
contents: read
216226
packages: write
@@ -238,23 +248,96 @@ jobs:
238248
type=raw,value=latest,enable=${{ !contains(github.ref, '-') }}
239249
type=sha,prefix=sha-
240250
241-
- name: Set up QEMU (Enable multi-arch)
242-
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
243-
244251
- name: Set up Docker Buildx
245252
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
246253

247-
- name: Build and push Docker image
254+
- name: Build and push Docker image by digest
255+
id: build
248256
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5.4.0
249257
with:
250258
context: .
251-
push: true
252-
platforms: linux/amd64,linux/arm64
253-
tags: ${{ steps.meta.outputs.tags }}
259+
platforms: ${{ matrix.platform }}
254260
labels: ${{ steps.meta.outputs.labels }}
255261
build-args: |
256262
APP_VERSION=${{ steps.meta.outputs.version }}
257263
APP_REVISION=${{ github.sha }}
258-
TEST_TIMEOUT_MS=120000
259-
cache-from: type=gha
260-
cache-to: type=gha,mode=max
264+
outputs: type=image,name=ghcr.io/${{ github.repository }},push-by-digest=true,name-canonical=true,push=true
265+
cache-from: type=gha,scope=docker-${{ matrix.arch }}
266+
cache-to: type=gha,scope=docker-${{ matrix.arch }},mode=max
267+
268+
- name: Export digest
269+
env:
270+
DIGEST: ${{ steps.build.outputs.digest }}
271+
run: |
272+
mkdir -p /tmp/digests
273+
touch "/tmp/digests/${DIGEST#sha256:}"
274+
275+
- name: Upload digest
276+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
277+
with:
278+
name: docker-digest-${{ matrix.arch }}
279+
path: /tmp/digests/*
280+
if-no-files-found: error
281+
retention-days: 1
282+
283+
docker-build:
284+
runs-on: ubuntu-24.04
285+
name: Docker Build & Push
286+
needs: docker-build-arch
287+
if: startsWith(github.ref, 'refs/tags/')
288+
permissions:
289+
contents: read
290+
packages: write
291+
292+
steps:
293+
- name: Download digests
294+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
295+
with:
296+
path: /tmp/digests
297+
pattern: docker-digest-*
298+
merge-multiple: true
299+
300+
- name: Log in to GitHub Container Registry
301+
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
302+
with:
303+
registry: ghcr.io
304+
username: ${{ github.actor }}
305+
password: ${{ secrets.GITHUB_TOKEN }}
306+
307+
- name: Set up Docker Buildx
308+
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
309+
310+
- name: Extract Docker metadata
311+
id: meta
312+
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
313+
with:
314+
images: ghcr.io/${{ github.repository }}
315+
tags: |
316+
type=semver,pattern={{version}}
317+
type=semver,pattern={{major}}.{{minor}}
318+
type=semver,pattern={{major}}
319+
type=raw,value=latest,enable=${{ !contains(github.ref, '-') }}
320+
type=sha,prefix=sha-
321+
322+
- name: Create multi-arch manifest list and push
323+
working-directory: /tmp/digests
324+
env:
325+
IMAGE: ghcr.io/${{ github.repository }}
326+
TAGS: ${{ steps.meta.outputs.tags }}
327+
run: |
328+
tag_args=()
329+
while IFS= read -r tag; do
330+
[[ -n "$tag" ]] && tag_args+=(-t "$tag")
331+
done <<< "$TAGS"
332+
sources=()
333+
for digest in *; do
334+
sources+=("${IMAGE}@sha256:${digest}")
335+
done
336+
docker buildx imagetools create "${tag_args[@]}" "${sources[@]}"
337+
338+
- name: Inspect image
339+
env:
340+
IMAGE: ghcr.io/${{ github.repository }}
341+
VERSION: ${{ steps.meta.outputs.version }}
342+
run: |
343+
docker buildx imagetools inspect "${IMAGE}:${VERSION}"

0 commit comments

Comments
 (0)