当前位置: 代码网 > 服务器>服务器>云虚拟主机 > 一次dockerfile的循环依赖错误实战记录

一次dockerfile的循环依赖错误实战记录

2025年02月13日 云虚拟主机 我要评论
1. 写在最前面笔者在使用 dockerfile 多阶段构建的功能时,写出了一个「circular dependency detected on stage: xx」的错误。解决方式:解耦互相依赖的构

1. 写在最前面

笔者在使用 dockerfile 多阶段构建的功能时,写出了一个「circular dependency detected on stage: xx」的错误。

解决方式:解耦互相依赖的构建阶段即可,构建 a <=> 构建 b 两个阶段是互相依赖的,改为构建 a => 构建 b

注:「多阶段构建」是 docker 提供的一种功能,运行用户在一个 dockerfile 中定义多个构建阶段,从而优化构镜像的大小和构建过程的效率。通过这种方式,开发者可以在不同的阶段使用不同的基础镜像和工具,最终只将所需要的文件和依赖项复制到最终的镜像中。

但是,作为一个有求知精神的软件开发工程师,笔者去翻看了一下源码的位置。(ps: 其实就是自己感兴趣 buildkit 的源码想要学习一下,而带着问题学习的速度更快)

1.1 具体循环依赖的例子

from busybox as stage0
copy --from=stage0 f1 /sub/ 
  • from busybox as stage0: 这行代码定义了一个名为 stage0 的构建阶段,并使用 busybox 作为基础镜像。

  • copy --from=stage0 f1 /sub/: 这行代码尝试从名为 stage0 的构建阶段复制文件 f1 到 /sub/ 目录。

在这个情况下,在同一个构建阶段中同时定义了一个新的阶段并尝试从该阶段复制文件。这会导致 docker 无法解析这个依赖关系,因为 stage0 还没有完成构建就被引用了。

2. 报错的位置

源码仓库:github - moby/buildkit: concurrent, cache-efficient, and dockerfile-agnostic builder toolkit

具体位置:buildkit/frontend/dockerfile/dockerfile2llb/convert.go at master · moby/buildkit · github

2.1 代码快速分析

得益于 github 支持了 codespaces 让笔者可以无需代码下载到本地,可以直接基于 codespaces 对 「convert_test.go」的具体 case 直接做在线 debug ,逐行分析。

注:github codespaces 是一个基于云的开发环境,允许开发者在浏览器中创建和使用完整的开发环境。它旨在简化开发流程,特别是对于团队协作和快速启动项目。以下是 github codespaces 的一些关键特性和功能:

代码 debug 效果:

注:感慨一下 codespaces 真的香!

2.2 代码总结

核心的循环依赖检测逻辑代码如下:

func validatecirculardependency(states []*dispatchstate) error {
	var visit func(*dispatchstate, []instructions.command) []instructions.command
	if states == nil {
		return nil
	}
	visited := make(map[*dispatchstate]struct{})
	path := make(map[*dispatchstate]struct{})

	visit = func(state *dispatchstate, current []instructions.command) []instructions.command {
		_, ok := visited[state]
		if ok {
			return nil
		}
		visited[state] = struct{}{}
		path[state] = struct{}{}
		for dep, c := range state.deps {
			next := append(current, c)
			if _, ok := path[dep]; ok {
				return next
			}
			if c := visit(dep, next); c != nil {
				return c
			}
		}
		delete(path, state)
		return nil
	}
	for _, state := range states {
		if cmds := visit(state, nil); cmds != nil {
			err := errors.errorf("circular dependency detected on stage: %s", state.stagename)
			for _, c := range cmds {
				err = parser.withlocation(err, c.location())
			}
			return err
		}
	}
	return nil
}

核心分析:它使用深度优先搜索(dfs)的方式来检测循环依赖,并在发现循环时返回一个错误。

注:看来不是算法没有用,是业务逻辑的代码中使用 dfs 这种算法的场景比较少,还是得多看源码

2.3 关于 parser 的记录

对于 dockerfile 的 parser 也有点兴趣,后面要继续抽个时间深入分析一下。笔者当前负责的模块重构成一个通用的 parser 的话,代码的复用率会更高一点。希望后面有时间可以优化改进一波

总结

到此这篇关于一次dockerfile的循环依赖错误的文章就介绍到这了,更多相关dockerfile循环依赖错误内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com