当前位置: 首页 > news >正文

从零创建 Docker 镜像(基于 OCI 格式)

更现代的 OCI 镜像格式,采用了 OCI Image Format Specification,其中文件引用使用 blobs/sha256/<hash> 的形式,层和配置存储在 blobs/sha256/ 目录下,并且包含 LayerSources 字段。这种格式在较新的 Docker 版本和 OCI 兼容的镜像存储中更常见。

从零开始手动创建一个可以被 docker load 加载的 Docker 镜像的步骤。我们将构造一个简单的镜像,包含一个 shell 脚本,输出 “Hello from my custom image!”,并确保生成的 tar 文件符合你提供的 manifest.json 结构。


从零创建 Docker 镜像(基于 OCI 格式)

我们将创建一个包含单个文件系统层的镜像,运行一个 shell 脚本。最终生成一个 tar 文件,包含 blobs/sha256/ 目录结构和相应的 manifest.json

步骤 1:准备文件系统层

创建一个简单的文件系统,包含一个可执行的 shell 脚本。

  1. 创建工作目录和文件系统结构:
mkdir -p my-image/rootfs/bin
cd my-image
  1. 创建一个 shell 脚本:
echo -e '#!/bin/sh\necho "Hello from my custom image!"' > rootfs/bin/hello.sh
chmod +x rootfs/bin/hello.sh
  1. 打包文件系统层为 tar 文件:
tar -cvf layer.tar -C rootfs .
  1. 计算层的 SHA256 校验值:
sha256sum layer.tar

假设输出为:

e4d7f1b4c3b2a1...  layer.tar

将层文件移动到 blobs/sha256/ 目录:

mkdir -p blobs/sha256
mv layer.tar blobs/sha256/e4d7f1b4c3b2a1...

步骤 2:创建镜像配置文件

创建一个 config.json 文件,描述镜像的运行时配置。需要注意的是,config.json 本身也会被存储为一个 blob,并以 SHA256 校验值命名。

my-image 目录下创建 config.json

{"architecture": "amd64","os": "linux","config": {"Entrypoint": ["/bin/hello.sh"],"Env": ["PATH=/bin"],"WorkingDir": "/"},"rootfs": {"type": "layers","diff_ids": ["sha256:e4d7f1b4c3b2a1..."]},"history": [{"created": "2025-04-19T00:00:00Z","created_by": "Manual creation"}]
}
  1. 计算 config.json 的 SHA256 校验值:
sha256sum config.json

假设输出为:

d41617c0b2d95b2...  config.json

config.json 移动到 blobs/sha256/ 目录:

mv config.json blobs/sha256/d41617c0b2d95b2...

步骤 3:创建 Manifest 文件

manifest.json 描述镜像的层和配置信息,引用 blobs/sha256/<hash> 路径。

my-image 目录下创建 manifest.json

[{"Config": "blobs/sha256/d41617c0b2d95b2...","RepoTags": ["my-custom-image:latest"],"Layers": ["blobs/sha256/e4d7f1b4c3b2a1..."],"LayerSources": {"sha256:e4d7f1b4c3b2a1...": {"mediaType": "application/vnd.oci.image.layer.v1.tar","size": 1024,"digest": "sha256:e4d7f1b4c3b2a1..."}}}
]

填写 LayerSourcessize 字段

LayerSources 中的 size 是层文件的大小(字节)。运行以下命令获取 layer.tar 的大小:

ls -l blobs/sha256/e4d7f1b4c3b2a1... | awk '{print $5}'

假设大小为 1024 字节,更新 manifest.json 中的 size 字段。

步骤 4:创建 OCI 布局文件

OCI 镜像需要一个 oci-layout 文件,表明目录符合 OCI 镜像规范。

my-image 目录下创建 oci-layout

{"imageLayoutVersion": "1.0.0"
}

步骤 5:打包镜像

将所有文件打包成一个 tar 文件,符合 Docker/OCI 镜像格式。

my-image 目录下运行:

tar -cvf my-image.tar oci-layout blobs/sha256/e4d7f1b4c3b2a1... blobs/sha256/d41617c0b2d95b2... manifest.json

这会生成 my-image.tar,即最终的 Docker 镜像文件。

步骤 6:验证和加载镜像

my-image.tar 传输到有 Docker 的环境中,运行:

docker load -i my-image.tar

加载后,检查镜像:

docker images

应该能看到 my-custom-image:latest

运行镜像:

docker run my-custom-image:latest

预期输出:

Hello from my custom image!

注意事项

  1. SHA256 校验值:确保 layer.tarconfig.json 的 SHA256 值正确,文件名和 manifest.json 中的引用必须一致。
  2. 文件权限:确保 hello.sh 有可执行权限(chmod +x)。
  3. LayerSourcesLayerSources 字段是可选的,但在某些 Docker 版本中需要。如果不需要,可以从 manifest.json 中移除。
  4. mediaType:层使用 application/vnd.oci.image.layer.v1.tar,配置使用 application/vnd.oci.image.config.v1+json(Docker 通常会推断)。
  5. 依赖问题:此例中,hello.sh 依赖 /bin/sh。如果目标环境没有 /bin/sh,需要将 sh 二进制文件包含在 rootfs 中。
  6. 目录结构:确保 blobs/sha256/ 目录和文件路径与 manifest.json 中的引用一致。

扩展:支持多层

如果需要多个层,重复以下步骤:

  1. 创建新的文件系统目录,添加或修改文件。
  2. 打包成新的 layerN.tar,计算 SHA256 值,移动到 blobs/sha256/<hash>
  3. 更新 config.jsonrootfs.diff_ids,添加新的 sha256:<hash>
  4. 更新 manifest.jsonLayersLayerSources,添加新的层引用。

例如,添加第二个层:

mkdir rootfs2
echo "Another file" > rootfs2/another.txt
tar -cvf layer2.tar -C rootfs2 .
sha256sum layer2.tar  # 假设得到 sha256:abcdef...
mv layer2.tar blobs/sha256/abcdef...
ls -l blobs/sha256/abcdef... | awk '{print $5}'  # 获取大小,假设为 2048

更新 config.json

"rootfs": {"type": "layers","diff_ids": ["sha256:e4d7f1b4c3b2a1...", "sha256:abcdef..."]
}

更新 manifest.json

"Layers": ["blobs/sha256/e4d7f1b4c3b2a1...", "blobs/sha256/abcdef..."],
"LayerSources": {"sha256:e4d7f1b4c3b2a1...": {"mediaType": "application/vnd.oci.image.layer.v1.tar","size": 1024,"digest": "sha256:e4d7f1b4c3b2a1..."},"sha256:abcdef...": {"mediaType": "application/vnd.oci.image.layer.v1.tar","size": 2048,"digest": "sha256:abcdef..."}
}

重新打包:

tar -cvf my-image.tar oci-layout blobs/sha256/e4d7f1b4c3b2a1... blobs/sha256/d41617c0b2d95b2... blobs/sha256/abcdef... manifest.json

总结

通过以上步骤,你可以完全不依赖 Docker 工具,从零创建一个符合 OCI 规范的 Docker 镜像,匹配你提供的 manifest.json 格式。最终的 my-image.tar 可以通过 docker load 导入并运行。如果你有更复杂的需求(如特定的软件、配置或多架构支持),请提供更多细节,我可以进一步优化!


http://www.xdnf.cn/news/51661.html

相关文章:

  • 【kubernetes】pod资源配额
  • 016-C语言内存函数
  • 每日一题算法——链表相交
  • git学习日志
  • Java EE(20)——线程安全——ThreadLocal
  • 第36讲:作物生长预测中的时间序列建模(LSTM等)
  • buildroot构建根文件系统报错(已解决大部分问题)
  • Linux学习——Linux进程间通信(IPC)聊天程序实践
  • Android开发中广播(Broadcast)技术详解
  • 线程基础题
  • FOC控制中的正弦PWM和空间矢量PWM对比与理解
  • 【计量地理学】实验五 试验变异函数计算
  • 软件设计师/系统架构师---计算机网络
  • Python爬虫实战:获取fenbi网最新备考资讯
  • 机器学习专栏(4):从数据饥荒到模型失控,破解AI训练的七大生死劫
  • SpringBoot Actuator健康检查:自定义HealthIndicator
  • Java 8 date/time type `java.time.LocalDateTime`
  • FreeRTOS中断管理
  • LangChain4j对话内存管理:ChatMemory原理与实战应用
  • 【深度学习与大模型基础】第12章-损失函数与梯度下降
  • 高等数学同步测试卷 同济7版 试卷部分 上 做题记录 上册期中同步测试卷 B卷
  • 相对路径和绝对路径解析
  • windows下配置Ninja
  • 算法笔记—动态规划
  • Multisim使用教程详尽版--(2025最新版)
  • B树的异常恢复
  • pivot_root:原理、用途及最简单 Demo
  • 项目预期管理:超越甘特图,实现客户价值交付
  • 协程?协程与线程的区别?Java是否支持协程?
  • The_Planets_Earth靶场笔记(VulnHub)