1. 简介
通常,我们是从 Dockerfile 构建出镜像(image),但有没有可能反过来操作,从镜像还原出 Dockerfile 呢?
虽然 Docker 官方并没有提供标准工具来从镜像生成 Dockerfile,但我们可以借助一些技巧实现近似的效果。本文将介绍几种从镜像中反向生成 Dockerfile 的方法,包括使用 docker history
和第三方工具如 dfimage
、dedockify
等。
2. 使用 docker history
docker history
是一个查看镜像各层构建历史的命令,它可以帮助我们还原出镜像中使用的构建指令。通过这些指令,我们就可以手动还原出一个近似原始的 Dockerfile。
整个过程大致分为以下几个步骤:
- 创建一个原始 Dockerfile 并构建镜像
- 使用
docker history
查看镜像的构建历史 - 根据输出信息还原 Dockerfile
- 对还原出的 Dockerfile 进行调整以保证可用性
2.1. 创建 Dockerfile
以下是一个简单的 Python Web 应用的 Dockerfile 示例:
$ cat ParentDockerfile
FROM python:3.10-bullseye
EXPOSE 80
COPY static static
COPY app.py app.py
COPY index.html index.html
RUN pip install flask
ENTRYPOINT [ "/bin/bash", "-c", "flask run --debug -p 80 -h 0.0.0.0" ]
这个 Dockerfile 使用了 Python 官方镜像作为基础镜像,复制了几个文件,并安装了 Flask 框架,最后设置了容器启动命令。
2.2. 构建镜像
使用以下命令构建镜像:
$ docker build . -f ParentDockerfile -t baeldung-image
确认镜像是否成功生成:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
baeldung-image latest a4a6f7d78efc 15 seconds ago 923MB
这个镜像体积较大,但不影响我们做测试。
2.3. 使用 docker history
查看镜像构建历史
运行以下命令查看镜像构建历史:
$ docker history baeldung-image
输出结果中的 CREATED BY
列包含了构建该层所使用的指令。但默认输出可能会被截断,我们可以加上 --no-trunc
参数避免截断:
$ docker history --no-trunc baeldung-image
为了更清晰地查看 CREATED BY
列,可以使用 --format
参数只显示该列内容:
$ docker history --no-trunc --format {{.CreatedBy}} baeldung-image
⚠️ 注意:输出是倒序的,即 Dockerfile 中的最后一条指令会出现在输出的第一行。我们可以用 tac
命令反转输出顺序:
$ docker history --no-trunc --format {{.CreatedBy}} baeldung-image | tac
这样输出就和原始 Dockerfile 的顺序一致了。
2.4. 还原 Dockerfile
通过上述命令输出的内容,我们可以手动还原出一个 Dockerfile:
$ docker history --no-trunc --format {{.CreatedBy}} baeldung-image | tac
输出内容如下(截取关键部分):
EXPOSE map[80/tcp:{}]
COPY static static # buildkit
COPY app.py app.py # buildkit
COPY index.html index.html # buildkit
RUN /bin/sh -c pip install flask # buildkit
ENTRYPOINT ["/bin/bash" "-c" "flask run --debug -p 80 -h 0.0.0.0"]
根据这些信息,我们可以写出如下 Dockerfile:
FROM python:3.11-bookworm
EXPOSE 80
COPY static static
COPY app.py app.py
COPY index.html index.html
RUN pip install flask
ENTRYPOINT ["/bin/bash", "-c", "flask run --debug -p 80 -h 0.0.0.0"]
2.5. 调整 Dockerfile
在还原过程中,需要注意以下几点:
✅ EXPOSE 指令格式:原始输出是 EXPOSE map[80/tcp:{}]
,应简化为 EXPOSE 80
✅ 删除注释:# buildkit
这类注释应删除
✅ ENTRYPOINT 格式:确保 JSON 数组中的命令用逗号分隔,如:
ENTRYPOINT ["/bin/bash", "-c", "flask run --debug -p 80 -h 0.0.0.0"]
最终,构建新的镜像验证是否可用:
$ docker build . -t new-image
如果构建成功,说明还原的 Dockerfile 是可用的。
3. 使用第三方工具
除了 docker history
,还有一些第三方工具也能帮助我们从镜像生成 Dockerfile,比如:
dfimage
dedockify
这些工具通常能提供更结构化的输出,但依然需要人工调整。
3.1. 使用 dfimage
可以使用如下命令创建别名:
$ alias dfimage="docker run -v /var/run/docker.sock:/var/run/docker.sock --rm alpine/dfimage"
然后运行:
$ dfimage baeldung-image
输出内容包括:
- 环境变量
- 暴露的端口
- 用户信息
- 可能的敏感信息
- Dockerfile 指令
示例输出:
Dockerfile:
CMD ["bash"]
...truncated...
ENTRYPOINT ["/bin/bash" "-c" "flask run --debug -p 80 -h 0.0.0.0"]
⚠️ 注意:虽然输出顺序通常已经是正序,但建议仍需检查是否与实际构建顺序一致。
4. 小结
方法 | 是否官方支持 | 输出是否有序 | 是否需要人工调整 |
---|---|---|---|
docker history |
❌ 否 | ❌ 否(需 tac ) |
✅ 是 |
dfimage |
❌ 否 | ✅ 是 | ✅ 是 |
dedockify |
❌ 否 | ✅ 是 | ✅ 是 |
虽然没有官方工具能直接从镜像生成 Dockerfile,但借助 docker history
或第三方工具,我们仍然可以还原出一个近似的 Dockerfile。不过,生成的结果通常需要手动调整后才能使用。
建议:
- ✅ 优先使用
docker history
+tac
的方式还原 Dockerfile - ✅ 第三方工具如
dfimage
可作为辅助,提高效率 - ✅ 不要盲目信任生成的 Dockerfile,务必验证其正确性
💡 本文参考自 Baeldung 的相关文章,并经过原创改写,内容更贴合中文技术圈习惯。