Skip to content

Commit 5169185

Browse files
committed
[UPDATE]: add docker manifest
1 parent 9c79d3f commit 5169185

File tree

5 files changed

+394
-0
lines changed

5 files changed

+394
-0
lines changed

source/_posts/docker-manifest.md

Lines changed: 394 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,394 @@
1+
---
2+
title: Harbor 多架构镜像管理完整指南
3+
date: 2025-08-13 10:40:00
4+
tags:
5+
- Docker
6+
- Harbor
7+
- Manifest
8+
- Multi-Architecture
9+
# comments: true
10+
category: Docker
11+
---
12+
13+
      在现代容器化环境中,多架构支持变得越来越重要。随着 ARM64 架构在服务器和边缘设备中的普及,我们需要构建和管理支持多种 CPU 架构的容器镜像。本文将详细介绍如何在 Harbor 私有镜像仓库中管理多架构镜像,包括配置、推送和创建 manifest 列表的完整流程。
14+
15+
<!-- more -->
16+
17+
## 环境说明
18+
19+
- **Harbor 版本**: 自建 Harbor 私有仓库
20+
- **部署方式**: HTTPS 模式,使用自签名证书,443 端口
21+
- **Docker 版本**: 支持 manifest 功能的版本
22+
- **目标架构**: AMD64 和 ARM64
23+
24+
## 问题背景
25+
26+
在实际项目中,我们遇到了以下挑战:
27+
28+
1. 需要将单架构镜像转换为多架构镜像
29+
2. Harbor 使用自签名 HTTPS 证书,需要正确配置 Docker 客户端
30+
3. Docker manifest 功能需要特定的配置和操作流程
31+
4. 需要批量处理多个版本的镜像
32+
33+
## 解决方案
34+
35+
### 1. Harbor 证书配置
36+
37+
#### 问题现象
38+
```bash
39+
Get "http://110.1.20.3/v2/": dial tcp 110.1.20.3:80: connect: connection refused
40+
```
41+
42+
这个错误表明 Docker 客户端尝试使用 HTTP 协议连接 Harbor,但 Harbor 实际运行在 HTTPS 模式。
43+
44+
#### 解决步骤
45+
46+
**Step 1: 配置客户端证书**
47+
```bash
48+
# 创建证书目录
49+
mkdir -p /etc/docker/certs.d/110.1.20.3/
50+
51+
# 复制 Harbor CA 证书和服务器证书
52+
\cp -rvf /data/opt/installharbor/certs/{ca.crt,harbor.crt} /etc/docker/certs.d/110.1.20.3/
53+
54+
# 设置正确的文件权限
55+
cd /etc/docker/certs.d/110.1.20.3/
56+
chmod 644 ca.crt harbor.crt
57+
```
58+
59+
**Step 2: 配置 Docker daemon**
60+
61+
编辑 `/etc/docker/daemon.json`
62+
```json
63+
{
64+
"registry-mirrors": [
65+
"https://docker.m.daocloud.io",
66+
"http://docker.1panel.live",
67+
"https://docker.agsv.top",
68+
"https://docker.agsvpt.work",
69+
"https://dockerpull.com",
70+
"https://dockerproxy.cn"
71+
],
72+
"debug": false,
73+
"insecure-registries": [
74+
"110.1.20.3"
75+
],
76+
"ip-forward": true,
77+
"ipv6": false,
78+
"live-restore": true,
79+
"log-driver": "json-file",
80+
"log-level": "warn",
81+
"log-opts": {
82+
"max-size": "100m",
83+
"max-file": "2"
84+
},
85+
"selinux-enabled": false,
86+
"experimental": true,
87+
"storage-driver": "overlay2",
88+
"data-root": "/data/docker_dir",
89+
"default-ulimits": {
90+
"nofile": {
91+
"Name": "nofile",
92+
"Hard": 65536,
93+
"Soft": 65536
94+
}
95+
},
96+
"exec-opts": ["native.cgroupdriver=systemd"]
97+
}
98+
```
99+
100+
**关键配置说明:**
101+
- `"experimental": true` - 启用 manifest 功能
102+
- `"insecure-registries": ["110.1.20.3"]` - 信任自签名证书
103+
104+
**Step 3: 重启服务**
105+
```bash
106+
# 重启 Docker
107+
systemctl daemon-reload
108+
systemctl restart docker
109+
110+
# 重启 Harbor(同台机器部署需要)
111+
cd /data/opt/installharbor/
112+
bash install.sh
113+
```
114+
115+
### 2. 常见证书问题解决
116+
117+
#### 问题1:证书文件扩展名错误
118+
```
119+
missing key ca.key for client certificate ca.cert. CA certificates must use the extension .crt
120+
```
121+
122+
**解决方法:**
123+
- Docker 要求 CA 证书必须使用 `.crt` 扩展名
124+
- 客户端证书目录不应包含私钥文件(`.key` 文件)
125+
126+
**正确的证书目录结构:**
127+
```
128+
/etc/docker/certs.d/110.1.20.3/
129+
├── ca.crt # CA 证书(必需)
130+
└── harbor.crt # Harbor 服务器证书(可选)
131+
```
132+
133+
#### 问题2:Docker daemon 配置错误
134+
```
135+
json: cannot unmarshal string into Go struct field Config.experimental of type bool
136+
```
137+
138+
**解决方法:**
139+
```json
140+
// 错误写法
141+
"experimental": "enabled"
142+
143+
// 正确写法
144+
"experimental": true
145+
```
146+
147+
### 3. 多架构镜像管理脚本
148+
149+
创建自动化脚本 `pushImages.sh` 来批量处理镜像:
150+
151+
```bash
152+
#!/bin/bash
153+
# ===================================
154+
# 批量处理:打 tag + 推送 + 创建多架构 manifest
155+
# 支持 HTTPS Harbor 自签名证书
156+
# ===================================
157+
set -e
158+
159+
# Harbor 配置
160+
HARBOR_HOST="110.1.20.3"
161+
REPO_PREFIX="${HARBOR_HOST}/library"
162+
VERSIONS=("3.11.3" "3.10.1" "3.9.2" "3.8.5")
163+
ARCHES=("amd64" "arm64")
164+
165+
# 是否删除旧标签(可选)
166+
DELETE_OLD_TAGS=false
167+
168+
echo "🚀 开始处理镜像标签与多架构清单..."
169+
echo "📡 Harbor 地址: https://${HARBOR_HOST}"
170+
171+
# 检查登录状态
172+
if ! docker login https://${HARBOR_HOST} 2>/dev/null; then
173+
echo "⚠️ Docker 未登录到 Harbor,请先登录:"
174+
echo " docker login https://${HARBOR_HOST}"
175+
exit 1
176+
fi
177+
178+
# 1. 先为所有镜像打新标签并推送
179+
for version in "${VERSIONS[@]}"; do
180+
for arch in "${ARCHES[@]}"; do
181+
OLD_TAG="${REPO_PREFIX}/java-gdal-local-${arch}:${version}"
182+
NEW_TAG="${REPO_PREFIX}/java-gdal-local:${version}-${arch}"
183+
184+
if docker inspect "$OLD_TAG" &> /dev/null; then
185+
echo "🏷️ 打标签: $OLD_TAG -> $NEW_TAG"
186+
docker tag "$OLD_TAG" "$NEW_TAG"
187+
188+
echo "📤 推送: $NEW_TAG"
189+
docker push "$NEW_TAG"
190+
191+
if [ "$DELETE_OLD_TAGS" = true ]; then
192+
echo "🗑️ 删除旧标签: $OLD_TAG"
193+
docker rmi "$OLD_TAG" || true
194+
fi
195+
else
196+
echo "⚠️ 镜像不存在,跳过: $OLD_TAG"
197+
fi
198+
done
199+
done
200+
201+
# 2. 为每个版本创建多架构 manifest
202+
echo ""
203+
echo "🔧 开始创建多架构 manifest..."
204+
205+
for version in "${VERSIONS[@]}"; do
206+
MANIFEST_TAG="${REPO_PREFIX}/java-gdal-local:${version}"
207+
TAG_AMD64="${REPO_PREFIX}/java-gdal-local:${version}-amd64"
208+
TAG_ARM64="${REPO_PREFIX}/java-gdal-local:${version}-arm64"
209+
210+
echo "📦 创建多架构镜像清单: $MANIFEST_TAG"
211+
212+
# 删除可能存在的旧 manifest
213+
docker manifest rm "$MANIFEST_TAG" 2>/dev/null || true
214+
215+
# 创建 manifest
216+
docker manifest create "$MANIFEST_TAG" \
217+
--amend "$TAG_AMD64" \
218+
--amend "$TAG_ARM64"
219+
220+
# 添加平台信息(关键步骤)
221+
docker manifest annotate "$MANIFEST_TAG" "$TAG_AMD64" --os linux --arch amd64
222+
docker manifest annotate "$MANIFEST_TAG" "$TAG_ARM64" --os linux --arch arm64
223+
224+
# 推送 manifest
225+
echo "📤 推送多架构镜像: $MANIFEST_TAG"
226+
docker manifest push "$MANIFEST_TAG"
227+
228+
echo "✅ 完成: $MANIFEST_TAG"
229+
done
230+
231+
echo ""
232+
echo "🎉 所有操作完成!"
233+
echo ""
234+
echo "你现在可以通过以下方式拉取:"
235+
for version in "${VERSIONS[@]}"; do
236+
echo " docker pull ${HARBOR_HOST}/library/java-gdal-local:${version}"
237+
done
238+
```
239+
240+
### 4. 手动操作流程
241+
242+
如果需要手动创建多架构镜像,可以按以下步骤:
243+
244+
**Step 1: 登录 Harbor**
245+
```bash
246+
docker login 110.1.20.3
247+
# 或者
248+
docker login -u admin -p [email protected] 110.1.20.3
249+
```
250+
251+
**Step 2: 推送单架构镜像**
252+
```bash
253+
# 为现有镜像打新标签
254+
docker tag 110.1.20.3/library/java-gdal-local-amd64:3.8.5 \
255+
110.1.20.3/library/java-gdal-local:3.8.5-amd64
256+
257+
docker tag 110.1.20.3/library/java-gdal-local-arm64:3.8.5 \
258+
110.1.20.3/library/java-gdal-local:3.8.5-arm64
259+
260+
# 推送镜像
261+
docker push 110.1.20.3/library/java-gdal-local:3.8.5-amd64
262+
docker push 110.1.20.3/library/java-gdal-local:3.8.5-arm64
263+
```
264+
265+
**Step 3: 创建多架构 manifest**
266+
```bash
267+
# 创建 manifest
268+
docker manifest create 110.1.20.3/library/java-gdal-local:3.8.5 \
269+
--amend 110.1.20.3/library/java-gdal-local:3.8.5-amd64 \
270+
--amend 110.1.20.3/library/java-gdal-local:3.8.5-arm64
271+
272+
# 添加平台信息(重要!)
273+
docker manifest annotate 110.1.20.3/library/java-gdal-local:3.8.5 \
274+
110.1.20.3/library/java-gdal-local:3.8.5-amd64 --os linux --arch amd64
275+
276+
docker manifest annotate 110.1.20.3/library/java-gdal-local:3.8.5 \
277+
110.1.20.3/library/java-gdal-local:3.8.5-arm64 --os linux --arch arm64
278+
279+
# 推送 manifest(注意:使用 manifest push,不是普通 push)
280+
docker manifest push 110.1.20.3/library/java-gdal-local:3.8.5
281+
```
282+
283+
**Step 4: 验证结果**
284+
```bash
285+
# 查看 manifest 信息
286+
docker manifest inspect 110.1.20.3/library/java-gdal-local:3.8.5
287+
288+
# 测试拉取(会根据当前平台自动选择架构)
289+
docker pull 110.1.20.3/library/java-gdal-local:3.8.5
290+
```
291+
292+
### 5. 故障排除
293+
294+
#### 常见错误及解决方法
295+
296+
**1. 证书相关错误**
297+
```
298+
x509: certificate signed by unknown authority
299+
```
300+
**解决:** 确保正确配置了 CA 证书或使用 `insecure-registries`
301+
302+
**2. Manifest 推送错误**
303+
```
304+
tag does not exist: 110.1.20.3/library/java-gdal-local:3.8.5
305+
```
306+
**解决:** 使用 `docker manifest push` 而不是 `docker push`
307+
308+
**3. 实验性功能未启用**
309+
```
310+
docker manifest is only supported when experimental cli features are enabled
311+
```
312+
**解决:**`daemon.json` 中设置 `"experimental": true`
313+
314+
#### 检查清单
315+
316+
- [ ] Docker daemon 配置了 `"experimental": true`
317+
- [ ] 证书文件使用正确的扩展名(`.crt`
318+
- [ ] 证书目录不包含私钥文件
319+
- [ ] 已正确登录 Harbor
320+
- [ ] 单架构镜像已成功推送
321+
- [ ] 使用 `docker manifest push` 推送 manifest
322+
323+
## 完整配置脚本
324+
325+
将所有配置步骤整合成一个脚本:
326+
327+
```bash
328+
#!/bin/bash
329+
# Harbor 多架构镜像配置脚本
330+
331+
echo "🔧 配置 Harbor 多架构镜像支持..."
332+
333+
# 1. 配置客户端证书
334+
echo "📜 配置客户端证书..."
335+
mkdir -p /etc/docker/certs.d/110.1.20.3/
336+
\cp -rvf /data/opt/installharbor/certs/{ca.crt,harbor.crt} /etc/docker/certs.d/110.1.20.3/
337+
cd /etc/docker/certs.d/110.1.20.3/
338+
chmod 644 ca.crt harbor.crt
339+
340+
# 2. 重启 Docker
341+
echo "🔄 重启 Docker 服务..."
342+
systemctl daemon-reload
343+
systemctl restart docker
344+
345+
# 3. 重启 Harbor(同台机器上需要)
346+
echo "🔄 重启 Harbor..."
347+
cd /data/opt/installharbor/
348+
bash install.sh
349+
350+
# 4. 等待服务启动
351+
echo "⏳ 等待服务启动..."
352+
sleep 30
353+
354+
# 5. 测试配置
355+
echo "🧪 测试配置..."
356+
docker login 110.1.20.3
357+
358+
# 6. 创建测试 manifest
359+
echo "📦 创建测试 manifest..."
360+
docker manifest create 110.1.20.3/library/java-gdal-local:3.8.5 \
361+
110.1.20.3/library/java-gdal-local:3.8.5-amd64 \
362+
110.1.20.3/library/java-gdal-local:3.8.5-arm64
363+
364+
docker manifest annotate 110.1.20.3/library/java-gdal-local:3.8.5 \
365+
110.1.20.3/library/java-gdal-local:3.8.5-amd64 --os linux --arch amd64
366+
367+
docker manifest annotate 110.1.20.3/library/java-gdal-local:3.8.5 \
368+
110.1.20.3/library/java-gdal-local:3.8.5-arm64 --os linux --arch arm64
369+
370+
docker manifest push 110.1.20.3/library/java-gdal-local:3.8.5
371+
372+
# 7. 验证结果
373+
echo "✅ 验证结果..."
374+
docker manifest inspect 110.1.20.3/library/java-gdal-local:3.8.5
375+
376+
echo "🎉 配置完成!"
377+
```
378+
379+
## 总结
380+
381+
通过本文的配置和脚本,我们成功解决了在自建 Harbor 中管理多架构镜像的问题。关键要点包括:
382+
383+
1. **正确配置 HTTPS 证书**:使用正确的文件名和权限
384+
2. **启用实验性功能**:Docker manifest 需要实验性功能支持
385+
3. **理解 manifest 操作**:区分 `docker push``docker manifest push`
386+
4. **自动化流程**:使用脚本批量处理多个版本和架构
387+
388+
这套方案可以帮助团队高效地管理多架构容器镜像,支持在不同 CPU 架构的环境中无缝部署应用。
389+
390+
## 参考资源
391+
392+
- [Docker Multi-platform images](https://docs.docker.com/build/building/multi-platform/)
393+
- [Docker manifest command](https://docs.docker.com/engine/reference/commandline/manifest/)
394+
- [Harbor Documentation](https://goharbor.io/docs/)
-24.3 KB
Binary file not shown.
-142 KB
Binary file not shown.
-810 Bytes
Binary file not shown.
-1.93 KB
Binary file not shown.

0 commit comments

Comments
 (0)