You've already forked DataMate
- 新增 APT 缓存目录和相关构建脚本 export-cache.sh - 添加 build-base-images.sh 脚本用于构建预装 APT 包的基础镜像 - 增加 build-offline-final.sh 最终版离线构建脚本 - 更新 Makefile.offline.mk 添加新的离线构建目标 - 扩展 README.md 文档详细说明 APT 缓存问题解决方案 - 为多个服务添加使用预装基础镜像的离线 Dockerfile - 修改打包脚本包含 APT 缓存到最终压缩包中
490 lines
16 KiB
Markdown
490 lines
16 KiB
Markdown
# BuildKit 离线构建方案
|
|
|
|
本方案使用 Docker BuildKit 的缓存机制,实现在弱网/无网环境下的镜像构建。
|
|
|
|
## 方案概述
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ 有网环境 (Build Machine) │
|
|
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
|
|
│ │ 基础镜像 │ │ BuildKit │ │ 外部资源 │ │
|
|
│ │ docker pull │ + │ 缓存导出 │ + │ (模型/源码) │ │
|
|
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
|
|
│ │ │ │ │
|
|
│ └──────────────────┼──────────────────┘ │
|
|
│ ▼ │
|
|
│ ┌──────────────────┐ │
|
|
│ │ build-cache.tar.gz│ │
|
|
│ └────────┬─────────┘ │
|
|
└─────────────────────────────┼───────────────────────────────────┘
|
|
│ 传输到无网环境
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ 无网环境 (Offline Machine) │
|
|
│ ┌──────────────────┐ │
|
|
│ │ build-cache.tar.gz│ │
|
|
│ └────────┬─────────┘ │
|
|
│ ▼ │
|
|
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
|
|
│ │ docker load │ │ BuildKit │ │ 本地资源挂载 │ │
|
|
│ │ 基础镜像 │ + │ 缓存导入 │ + │ (模型/源码) │ │
|
|
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
|
|
│ │ │ │ │
|
|
│ └──────────────────┼──────────────────┘ │
|
|
│ ▼ │
|
|
│ 构建成功! │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## 快速开始
|
|
|
|
### 方法一:使用 Makefile 扩展(推荐)
|
|
|
|
#### 1. 合并 Makefile
|
|
|
|
将 `Makefile.offline.mk` 追加到主 Makefile:
|
|
|
|
```bash
|
|
# Linux/Mac
|
|
cat Makefile.offline.mk >> Makefile
|
|
|
|
# Windows (PowerShell)
|
|
Get-Content Makefile.offline.mk | Add-Content Makefile
|
|
```
|
|
|
|
#### 2. 有网环境导出缓存
|
|
|
|
```bash
|
|
# 导出所有缓存(包括基础镜像、BuildKit 缓存、外部资源)
|
|
make offline-export
|
|
|
|
# 或者指定输出目录
|
|
make offline-export CACHE_DIR=/path/to/cache
|
|
```
|
|
|
|
执行完成后,会生成压缩包:`build-cache-YYYYMMDD.tar.gz`
|
|
|
|
#### 3. 传输到无网环境
|
|
|
|
```bash
|
|
# 使用 scp 或其他方式传输
|
|
scp build-cache-20250202.tar.gz user@offline-server:/opt/datamate/
|
|
|
|
# 或者使用 U 盘等物理介质
|
|
```
|
|
|
|
#### 4. 无网环境构建(推荐使用传统方式)
|
|
|
|
```bash
|
|
# 解压缓存
|
|
tar -xzf build-cache-20250202.tar.gz
|
|
|
|
# 诊断环境(检查基础镜像等)
|
|
make offline-diagnose
|
|
|
|
# 方法 A:传统 docker build(推荐,更稳定)
|
|
make offline-setup
|
|
make offline-build-classic
|
|
|
|
# 方法 B:BuildKit 构建(如果方法 A 失败)
|
|
make offline-setup
|
|
make offline-build
|
|
|
|
# 或者指定版本号
|
|
make offline-build-classic OFFLINE_VERSION=v1.0.0
|
|
```
|
|
|
|
**⚠️ 重要提示**:如果遇到镜像拉取问题,请使用 `make offline-build-classic` 而不是 `make offline-build`。
|
|
|
|
### 方法二:使用独立脚本
|
|
|
|
#### 导出缓存
|
|
|
|
```bash
|
|
cd scripts/offline
|
|
./export-cache.sh /path/to/output
|
|
```
|
|
|
|
#### 离线构建
|
|
|
|
```bash
|
|
cd scripts/offline
|
|
./build-offline.sh /path/to/cache [version]
|
|
```
|
|
|
|
## 详细说明
|
|
|
|
### 缓存内容
|
|
|
|
缓存目录结构:
|
|
|
|
```
|
|
build-cache/
|
|
├── buildkit/ # BuildKit 缓存
|
|
│ ├── backend-cache/
|
|
│ ├── backend-python-cache/
|
|
│ ├── database-cache/
|
|
│ ├── frontend-cache/
|
|
│ ├── gateway-cache/
|
|
│ ├── runtime-cache/
|
|
│ ├── deer-flow-backend-cache/
|
|
│ ├── deer-flow-frontend-cache/
|
|
│ └── mineru-cache/
|
|
├── images/
|
|
│ └── base-images.tar # 基础镜像集合
|
|
└── resources/ # 外部资源
|
|
├── models/
|
|
│ ├── ch_ppocr_mobile_v2.0_cls_infer.tar # PaddleOCR 模型
|
|
│ └── zh_core_web_sm-3.8.0-py3-none-any.whl # spaCy 模型
|
|
├── DataX/ # DataX 源码
|
|
└── deer-flow/ # deer-flow 源码
|
|
```
|
|
|
|
### 单个服务构建
|
|
|
|
```bash
|
|
# 仅构建 backend
|
|
make backend-offline-build
|
|
|
|
# 仅构建 runtime
|
|
make runtime-offline-build
|
|
|
|
# 仅构建 deer-flow-backend
|
|
make deer-flow-backend-offline-build
|
|
```
|
|
|
|
### 增量更新
|
|
|
|
如果只有部分服务代码变更,可以只导出该服务的缓存:
|
|
|
|
```bash
|
|
# 重新导出 backend 缓存
|
|
docker buildx build \
|
|
--cache-to type=local,dest=./build-cache/buildkit/backend-cache,mode=max \
|
|
-f scripts/images/backend/Dockerfile \
|
|
-t datamate-backend:cache .
|
|
|
|
# 传输并重新构建
|
|
tar -czf build-cache-partial.tar.gz build-cache/buildkit/backend-cache
|
|
# ... 传输到无网环境 ...
|
|
make backend-offline-build
|
|
```
|
|
|
|
## APT 缓存问题详解
|
|
|
|
### 问题描述
|
|
|
|
即使使用了 `--mount=type=cache,target=/var/cache/apt`,Dockerfile 中的 `apt-get update` 仍会尝试从网络获取包列表(list 数据),导致无网环境下构建失败:
|
|
|
|
```
|
|
Err:1 http://mirrors.aliyun.com/debian bookworm InRelease
|
|
Could not resolve 'mirrors.aliyun.com'
|
|
Reading package lists...
|
|
E: Failed to fetch http://mirrors.aliyun.com/debian/dists/bookworm/InRelease
|
|
```
|
|
|
|
### 根本原因
|
|
|
|
- `--mount=type=cache,target=/var/cache/apt` 只缓存下载的 `.deb` 包
|
|
- `apt-get update` 会尝试从配置的源获取最新的包索引(InRelease/Packages 文件)
|
|
- `/var/lib/apt/lists/` 目录存储包索引,但通常不在缓存范围内
|
|
|
|
### 解决方案
|
|
|
|
#### 方案 1: 使用预装 APT 包的基础镜像(推荐)
|
|
|
|
这是最有效的方法:
|
|
|
|
**步骤 1**: 在有网环境构建预装所有依赖的基础镜像
|
|
|
|
```bash
|
|
# 构建并保存带 APT 预装包的基础镜像
|
|
./scripts/offline/build-base-images.sh
|
|
```
|
|
|
|
这会创建以下预装基础镜像:
|
|
- `datamate-java-base` - 用于 backend、gateway(预装 vim、python3、libreoffice 等)
|
|
- `datamate-python-base` - 用于 backend-python(预装 openjdk、nfs-common 等)
|
|
- `datamate-runtime-base` - 用于 runtime(预装 libgl1、tesseract-ocr 等)
|
|
- `deer-flow-backend-base` - 用于 deer-flow-backend
|
|
- `mineru-base` - 用于 mineru
|
|
|
|
**步骤 2**: 在无网环境使用这些基础镜像构建
|
|
|
|
```bash
|
|
# 加载包含预装基础镜像的 tar 包
|
|
docker load -i build-cache/images/base-images-with-apt.tar
|
|
|
|
# 使用最终版构建脚本
|
|
./scripts/offline/build-offline-final.sh
|
|
```
|
|
|
|
#### 方案 2: 修改 Dockerfile 跳过 apt update
|
|
|
|
如果确定不需要安装新包,可以修改 Dockerfile:
|
|
|
|
```dockerfile
|
|
# 原代码
|
|
RUN apt-get update && apt-get install -y xxx
|
|
|
|
# 修改为(离线环境)
|
|
# RUN apt-get update && \
|
|
RUN apt-get install -y xxx || true
|
|
```
|
|
|
|
#### 方案 3: 挂载 apt lists 缓存
|
|
|
|
在有网环境预先下载并保存 apt lists:
|
|
|
|
```bash
|
|
# 有网环境:保存 apt lists
|
|
docker run --rm \
|
|
-v "$(pwd)/apt-lists:/var/lib/apt/lists" \
|
|
eclipse-temurin:21-jdk \
|
|
apt-get update
|
|
|
|
# 无网环境:挂载保存的 lists
|
|
docker build \
|
|
--mount=type=bind,source=$(pwd)/apt-lists,target=/var/lib/apt/lists,ro \
|
|
-f Dockerfile .
|
|
```
|
|
|
|
**注意**: BuildKit 的 `--mount=type=bind` 在 `docker build` 中不直接支持,需要在 Dockerfile 中使用。
|
|
|
|
---
|
|
|
|
## 故障排查
|
|
|
|
### 问题 1: 构建时仍然尝试拉取镜像(最常见)
|
|
|
|
**现象**:
|
|
```
|
|
ERROR: failed to solve: pulling from host ...
|
|
或
|
|
ERROR: pull access denied, repository does not exist or may require authorization
|
|
```
|
|
|
|
**原因**:
|
|
- 基础镜像未正确加载
|
|
- BuildKit 尝试验证远程镜像
|
|
|
|
**解决方案**:
|
|
|
|
1. **使用传统构建方式(推荐)**:
|
|
```bash
|
|
make offline-build-classic
|
|
```
|
|
|
|
2. **手动加载基础镜像**:
|
|
```bash
|
|
# 加载基础镜像
|
|
docker load -i build-cache/images/base-images.tar
|
|
|
|
# 验证镜像存在
|
|
docker images | grep -E "(maven|eclipse-temurin|mysql|node|nginx)"
|
|
```
|
|
|
|
3. **使用 Docker 守护进程的离线模式**:
|
|
```bash
|
|
# 编辑 /etc/docker/daemon.json
|
|
{
|
|
"registry-mirrors": [],
|
|
"insecure-registries": []
|
|
}
|
|
|
|
# 重启 Docker
|
|
sudo systemctl restart docker
|
|
```
|
|
|
|
### 问题 2: 缓存导入失败
|
|
|
|
```
|
|
ERROR: failed to solve: failed to read cache metadata
|
|
```
|
|
|
|
**解决**: 缓存目录可能损坏,重新在有网环境导出。
|
|
|
|
### 问题 3: 基础镜像不存在
|
|
|
|
```
|
|
ERROR: pull access denied
|
|
```
|
|
|
|
**解决**:
|
|
1. 先执行 `make offline-setup` 加载基础镜像
|
|
2. 运行 `make offline-diagnose` 检查缺失的镜像
|
|
3. 重新导出缓存时确保包含所有基础镜像
|
|
|
|
### 问题 4: 网络连接错误(无网环境)
|
|
|
|
```
|
|
ERROR: failed to do request: dial tcp: lookup ...
|
|
```
|
|
|
|
**解决**: 检查 Dockerfile 中是否还有网络依赖(如 `git clone`、`wget`、`pip install` 等),可能需要修改 Dockerfile 使用本地资源。
|
|
|
|
### 问题 5: 内存不足
|
|
|
|
BuildKit 缓存可能占用大量内存,可以设置资源限制:
|
|
|
|
```bash
|
|
# 创建带资源限制的 buildx 构建器
|
|
docker buildx create --name offline-builder \
|
|
--driver docker-container \
|
|
--driver-opt memory=8g \
|
|
--use
|
|
```
|
|
|
|
### 问题 6: BuildKit 构建器无法使用本地镜像
|
|
|
|
**现象**: 即使镜像已加载,BuildKit 仍提示找不到镜像
|
|
|
|
**解决**: BuildKit 的 `docker-container` 驱动无法直接访问本地镜像。使用以下方法之一:
|
|
|
|
**方法 A**: 使用传统 Docker 构建(推荐)
|
|
```bash
|
|
make offline-build-classic
|
|
```
|
|
|
|
**方法 B**: 将镜像推送到本地 registry
|
|
```bash
|
|
# 启动本地 registry
|
|
docker run -d -p 5000:5000 --name registry registry:2
|
|
|
|
# 标记并推送镜像到本地 registry
|
|
docker tag maven:3-eclipse-temurin-21 localhost:5000/maven:3-eclipse-temurin-21
|
|
docker push localhost:5000/maven:3-eclipse-temurin-21
|
|
|
|
# 修改 Dockerfile 使用本地 registry
|
|
# FROM localhost:5000/maven:3-eclipse-temurin-21
|
|
```
|
|
|
|
**方法 C**: 使用 `docker` 驱动的 buildx 构建器(不需要推送镜像,但有其他限制)
|
|
```bash
|
|
# 创建使用 docker 驱动的构建器
|
|
docker buildx create --name offline-builder --driver docker --use
|
|
|
|
# 但这种方式无法使用 --cache-from type=local
|
|
# 仅适用于简单的离线构建场景
|
|
```
|
|
|
|
## 限制说明
|
|
|
|
1. **镜像版本**: 基础镜像版本必须与缓存导出时一致
|
|
2. **Dockerfile 变更**: 如果 Dockerfile 发生较大变更,可能需要重新导出缓存
|
|
3. **资源文件**: mineru 镜像中的模型下载(`mineru-models-download`)仍需要网络,如果需要在完全无网环境使用,需要预先将模型文件挂载到镜像中
|
|
|
|
## 高级用法
|
|
|
|
### 自定义缓存位置
|
|
|
|
```bash
|
|
make offline-export CACHE_DIR=/mnt/nas/build-cache
|
|
make offline-build CACHE_DIR=/mnt/nas/build-cache
|
|
```
|
|
|
|
### 导出特定平台缓存
|
|
|
|
```bash
|
|
# 导出 ARM64 平台的缓存
|
|
docker buildx build \
|
|
--platform linux/arm64 \
|
|
--cache-to type=local,dest=./build-cache/buildkit/backend-cache,mode=max \
|
|
-f scripts/images/backend/Dockerfile .
|
|
```
|
|
|
|
### 使用远程缓存(有网环境)
|
|
|
|
```bash
|
|
# 导出到 S3/MinIO
|
|
docker buildx build \
|
|
--cache-to type=s3,region=us-east-1,bucket=mybucket,name=backend-cache \
|
|
-f scripts/images/backend/Dockerfile .
|
|
|
|
# 从 S3 导入
|
|
docker buildx build \
|
|
--cache-from type=s3,region=us-east-1,bucket=mybucket,name=backend-cache \
|
|
-f scripts/images/backend/Dockerfile .
|
|
```
|
|
|
|
## 文件清单
|
|
|
|
```
|
|
scripts/offline/
|
|
├── export-cache.sh # 有网环境导出缓存脚本
|
|
├── build-base-images.sh # 构建 APT 预装基础镜像
|
|
├── build-offline.sh # 基础离线构建脚本(BuildKit)
|
|
├── build-offline-v2.sh # 增强版离线构建脚本
|
|
├── build-offline-classic.sh # 传统 docker build 脚本
|
|
├── build-offline-final.sh # 最终版(使用预装基础镜像,推荐)
|
|
├── diagnose.sh # 环境诊断脚本
|
|
├── Dockerfile.base-images # 预装 APT 包的基础镜像定义
|
|
├── Dockerfile.backend.offline # backend 离线 Dockerfile(使用预装基础镜像)
|
|
├── Dockerfile.gateway.offline # gateway 离线 Dockerfile(使用预装基础镜像)
|
|
├── Dockerfile.backend-python.offline # backend-python 离线 Dockerfile
|
|
├── Dockerfile.backend-python.offline-v2 # backend-python 离线 Dockerfile v2(使用预装基础镜像)
|
|
├── Dockerfile.runtime.offline # runtime 离线 Dockerfile
|
|
├── Dockerfile.runtime.offline-v2 # runtime 离线 Dockerfile v2(使用预装基础镜像)
|
|
├── Dockerfile.deer-flow-backend.offline # deer-flow-backend 离线 Dockerfile
|
|
├── Dockerfile.deer-flow-frontend.offline # deer-flow-frontend 离线 Dockerfile
|
|
├── Makefile.offline # 独立离线构建 Makefile
|
|
└── README.md # 本文档
|
|
|
|
Makefile.offline.mk # Makefile 扩展(追加到主 Makefile)
|
|
```
|
|
|
|
## 推荐工作流(解决 APT 问题版)
|
|
|
|
### 工作流 A: 使用预装 APT 包的基础镜像(彻底解决 APT 问题)
|
|
|
|
```bash
|
|
# ========== 有网环境 ==========
|
|
|
|
# 1. 构建并保存带 APT 预装包的基础镜像
|
|
./scripts/offline/build-base-images.sh
|
|
# 输出: build-cache/images/base-images-with-apt.tar
|
|
|
|
# 2. 导出其他缓存(BuildKit 缓存、外部资源)
|
|
./scripts/offline/export-cache.sh
|
|
|
|
# 3. 打包传输
|
|
scp build-cache/images/base-images-with-apt.tar user@offline-server:/opt/datamate/build-cache/images/
|
|
scp build-cache-*.tar.gz user@offline-server:/opt/datamate/
|
|
|
|
# ========== 无网环境 ==========
|
|
|
|
cd /opt/datamate
|
|
|
|
# 4. 解压
|
|
tar -xzf build-cache-*.tar.gz
|
|
|
|
# 5. 加载预装基础镜像(关键!)
|
|
docker load -i build-cache/images/base-images-with-apt.tar
|
|
|
|
# 6. 使用最终版脚本构建
|
|
./scripts/offline/build-offline-final.sh
|
|
```
|
|
|
|
### 工作流 B: 简单场景(使用传统构建)
|
|
|
|
如果 APT 包需求简单,可以直接使用传统构建:
|
|
|
|
```bash
|
|
# 有网环境
|
|
make offline-export
|
|
|
|
# 传输到无网环境
|
|
scp build-cache-*.tar.gz offline-server:/path/
|
|
|
|
# 无网环境
|
|
tar -xzf build-cache-*.tar.gz
|
|
make offline-diagnose # 检查环境
|
|
make offline-build-classic # 使用传统构建
|
|
```
|
|
|
|
## 参考
|
|
|
|
- [Docker BuildKit Documentation](https://docs.docker.com/build/buildkit/)
|
|
- [Cache Storage Backends](https://docs.docker.com/build/cache/backends/)
|