当前位置: 首页 > 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 导入并运行。如果你有更复杂的需求(如特定的软件、配置或多架构支持),请提供更多细节,我可以进一步优化!


相关文章:

  • Datawhale 春训营 创新药赛道
  • Linux 进程概念补充 (自用)
  • 代理模式(Proxy Pattern)
  • vue3 excel文件导入
  • 贝叶斯分类器:原理、算法与应用详解
  • 位运算,状态压缩dp(算法竞赛进阶指南学习笔记)
  • 【Java】接口interface学习
  • 残烛与风儿的对话
  • OC底层原理【一】 alloc init new
  • java单元测试不能点击run运行测试方法
  • 【第二天】一月速通Python第二天,函数,数据容器,列表,元组,字典。
  • 论文阅读:2023 arxiv A Survey of Reinforcement Learning from Human Feedback
  • 集成运放的关键技术参数
  • 7.0/Q1,Charls最新文章解读
  • 【Oracle专栏】Oracle中的虚拟列
  • pnpm确认全局下载安装了还是显示cnpm不是内部或外部命令,也不是可运行的程序
  • 算法分析传输加密数据格式密文存储代码混淆逆向保护
  • Mac上Cursor无法安装插件解决方法
  • 【大模型】RAG(Retrieval-Augmented Generation)检索增强生成
  • 使用 NEAT 进化智能体解决 Gymnasium 强化学习环境
  • 上海优化餐企发展环境:装修拓展门店最高奖50万,建立问题协调机制
  • 智飞生物一季度营收下滑79%,连续三个季度亏损,称业绩波动与行业整体趋势一致
  • 大卫·第艾维瑞谈历史学与社会理论②丨马克斯·韦伯与历史学研究
  • 教育部召开全国中小学幼儿园安全工作视频会议:加强校园安防建设
  • 海康威视:去年海外主业和机器人等创新业务占比首次超50%
  • 为护航企业“出海”,“无问西东·中外商会”海上沙龙举行