一次dockerfile的循環(huán)依賴(lài)錯(cuò)誤實(shí)戰(zhàn)記錄
1. 寫(xiě)在最前面
筆者在使用 dockerfile 多階段構(gòu)建的功能時(shí),寫(xiě)出了一個(gè)「circular dependency detected on stage: xx」的錯(cuò)誤。
解決方式:解耦互相依賴(lài)的構(gòu)建階段即可,構(gòu)建 A <=> 構(gòu)建 B 兩個(gè)階段是互相依賴(lài)的,改為構(gòu)建 A => 構(gòu)建 B
注:「多階段構(gòu)建」是 Docker 提供的一種功能,運(yùn)行用戶(hù)在一個(gè) Dockerfile 中定義多個(gè)構(gòu)建階段,從而優(yōu)化構(gòu)鏡像的大小和構(gòu)建過(guò)程的效率。通過(guò)這種方式,開(kāi)發(fā)者可以在不同的階段使用不同的基礎(chǔ)鏡像和工具,最終只將所需要的文件和依賴(lài)項(xiàng)復(fù)制到最終的鏡像中。
但是,作為一個(gè)有求知精神的軟件開(kāi)發(fā)工程師,筆者去翻看了一下源碼的位置。(ps: 其實(shí)就是自己感興趣 BuildKit 的源碼想要學(xué)習(xí)一下,而帶著問(wèn)題學(xué)習(xí)的速度更快)
1.1 具體循環(huán)依賴(lài)的例子
FROM busybox AS stage0 COPY --from=stage0 f1 /sub/
FROM busybox AS stage0: 這行代碼定義了一個(gè)名為stage0的構(gòu)建階段,并使用busybox作為基礎(chǔ)鏡像。COPY --from=stage0 f1 /sub/: 這行代碼嘗試從名為stage0的構(gòu)建階段復(fù)制文件f1到/sub/目錄。
在這個(gè)情況下,在同一個(gè)構(gòu)建階段中同時(shí)定義了一個(gè)新的階段并嘗試從該階段復(fù)制文件。這會(huì)導(dǎo)致 Docker 無(wú)法解析這個(gè)依賴(lài)關(guān)系,因?yàn)?nbsp;stage0 還沒(méi)有完成構(gòu)建就被引用了。
2. 報(bào)錯(cuò)的位置
源碼倉(cāng)庫(kù):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 讓筆者可以無(wú)需代碼下載到本地,可以直接基于 Codespaces 對(duì) 「convert_test.go」的具體 case 直接做在線(xiàn) debug ,逐行分析。
注:GitHub Codespaces 是一個(gè)基于云的開(kāi)發(fā)環(huán)境,允許開(kāi)發(fā)者在瀏覽器中創(chuàng)建和使用完整的開(kāi)發(fā)環(huán)境。它旨在簡(jiǎn)化開(kāi)發(fā)流程,特別是對(duì)于團(tuán)隊(duì)協(xié)作和快速啟動(dòng)項(xiàng)目。以下是 GitHub Codespaces 的一些關(guān)鍵特性和功能:
代碼 debug 效果:

注:感慨一下 Codespaces 真的香!
2.2 代碼總結(jié)
核心的循環(huán)依賴(lài)檢測(cè)邏輯代碼如下:
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
}
核心分析:它使用深度優(yōu)先搜索(DFS)的方式來(lái)檢測(cè)循環(huán)依賴(lài),并在發(fā)現(xiàn)循環(huán)時(shí)返回一個(gè)錯(cuò)誤。
注:看來(lái)不是算法沒(méi)有用,是業(yè)務(wù)邏輯的代碼中使用 DFS 這種算法的場(chǎng)景比較少,還是得多看源碼
2.3 關(guān)于 parser 的記錄
對(duì)于 dockerfile 的 parser 也有點(diǎn)興趣,后面要繼續(xù)抽個(gè)時(shí)間深入分析一下。筆者當(dāng)前負(fù)責(zé)的模塊重構(gòu)成一個(gè)通用的 parser 的話(huà),代碼的復(fù)用率會(huì)更高一點(diǎn)。希望后面有時(shí)間可以?xún)?yōu)化改進(jìn)一波
總結(jié)
到此這篇關(guān)于一次dockerfile的循環(huán)依賴(lài)錯(cuò)誤的文章就介紹到這了,更多相關(guān)dockerfile循環(huán)依賴(lài)錯(cuò)誤內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Docker容器網(wǎng)絡(luò)地址的創(chuàng)建修改
Docker提供了一個(gè)方便的方式來(lái)配置容器的網(wǎng)絡(luò)地址,在本文中,我們將介紹如何修改Docker容器的網(wǎng)絡(luò)地址,本文主要介紹了Docker容器網(wǎng)絡(luò)地址的創(chuàng)建修改,感興趣的可以了解一下2024-01-01
Docker如何使用nginx搭建tomcat集群(圖文詳解)
這篇文章主要介紹了Docker使用nginx搭建tomcat集群的教程,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12
在CentOS啟動(dòng)時(shí)自動(dòng)加載內(nèi)核模塊overlayfs操作
這篇文章主要介紹了在CentOS啟動(dòng)時(shí)自動(dòng)加載內(nèi)核模塊overlayfs操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
使用Docker部署MySQL 5.7&8.0主從集群的方法步驟
這篇文章主要介紹了使用Docker部署MySQL 5.7&8.0主從集群的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
Docker搭建prometheus(普羅米修斯)的方法步驟
phometheus:當(dāng)前一套非常流行的開(kāi)源監(jiān)控和報(bào)警系統(tǒng),本文主要介紹了Docker搭建prometheus(普羅米修斯)的方法步驟,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02
Docker overlay 網(wǎng)絡(luò)搭建的方法
Overlay網(wǎng)絡(luò)是指通過(guò)在現(xiàn)有網(wǎng)絡(luò)上疊加一個(gè)軟件定義的邏輯網(wǎng)絡(luò),這篇文章主要介紹了Docker overlay 網(wǎng)絡(luò)搭建的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
如何使用docker極簡(jiǎn)打包java.jar鏡像并啟動(dòng)
這篇文章主要介紹了如何使用docker極簡(jiǎn)打包java.jar鏡像并啟動(dòng),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08

