亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 服務器 > Web服務器 > 正文

Dockerfile中multi-stage(多階段構建)詳解

2024-09-01 13:54:07
字體:
來源:轉載
供稿:網友

前言

Docker的口號是Build,Ship,and Run Any App,Anywhere,在我們使用 Docker 的大部分時候,的確能感覺到其優越性,但是往往在我們 Build 一個應用的時候,是將我們的源代碼也構建進去的,這對于類似于 golang 這樣的編譯型語言肯定是不行的,因為實際運行的時候我只需要把最終構建的二進制包給你就行,把源碼也一起打包在鏡像中,需要承擔很多風險,即使是腳本語言,在構建的時候也可能需要使用到一些上線的工具,這樣無疑也增大了我們的鏡像體積。

在應用了容器技術的軟件開發過程中,控制容器鏡像的大小可是一件費時費力的事情。如果我們構建的鏡像既是編譯軟件的環境,又是軟件最終的運行環境,這是很難控制鏡像大小的。所以常見的配置模式為:分別為軟件的編譯環境和運行環境提供不同的容器鏡像。比如為編譯環境提供一個 Dockerfile.build,用它構建的鏡像包含了編譯軟件需要的所有內容,比如代碼、SDK、工具等等。同時為軟件的運行環境提供另外一個單獨的 Dockerfile,它從 Dockerfile.build 中獲得編譯好的軟件,用它構建的鏡像只包含運行軟件所必須的內容。這種情況被稱為構造者模式(builder pattern),本文將介紹如何通過 Dockerfile 中的 multi-stage 來解決構造者模式帶來的問題。

常見的容器鏡像構建過程

比如我們創建了一個 GO 語言編寫了一個檢查頁面中超級鏈接的程序 app.go(請從 sparkdev  (本地下載)獲取本文相關的代碼):

package mainimport ( "encoding/json" "fmt" "log" "net/http" "net/url" "os" "strings" "golang.org/x/net/html")type scrapeDataStore struct { Internal int `json:"internal"` External int `json:"external"`}func isInternal(parsedLink *url.URL, siteUrl *url.URL, link string) bool { return parsedLink.Host == siteUrl.Host || strings.Index(link, "#") == 0 || len(parsedLink.Host) == 0}func main() { urlIn := os.Getenv("url") if len(urlIn) == 0 { urlIn = "https://www.cnblogs.com/" } resp, err := http.Get(urlIn) scrapeData := &scrapeDataStore{} tokenizer := html.NewTokenizer(resp.Body) end := false for { tt := tokenizer.Next() switch { case tt == html.StartTagToken: token := tokenizer.Token() switch token.Data { case "a": for _, attr := range token.Attr {  if attr.Key == "href" {  link := attr.Val  parsedLink, parseLinkErr := url.Parse(link)  if parseLinkErr == nil {  if isInternal(parsedLink, siteUrl, link) {  scrapeData.Internal++  } else {  scrapeData.External++  }  }  if parseLinkErr != nil {  fmt.Println("Can't parse: " + token.Data)  }  } } break } case tt == html.ErrorToken: end = true break } if end { break } } data, _ := json.Marshal(&scrapeData) fmt.Println(string(data))}

下面我們通過容器來構建它,并把它部署到生產型的容器鏡像中。

首先構建編譯應用程序的鏡像:

FROM golang:1.7.3WORKDIR /go/src/github.com/sparkdevo/href-counter/RUN go get -d -v golang.org/x/net/htmlCOPY app.go .RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

把上面的內容保存到 Dockerfile.build 文件中。

接著把構建好的應用程序部署到生產環境用的鏡像中:

FROM alpine:latest RUN apk --no-cache add ca-certificatesWORKDIR /root/COPY app .CMD ["./app"] 

把上面的內容保存到 Dockerfile 文件中。

最后需要使用一個腳本把整個構建過程整合起來:

#!/bin/shecho Building sparkdevo/href-counter:build# 構建編譯應用程序的鏡像docker build --no-cache -t sparkdevo/href-counter:build . -f Dockerfile.build# 創建應用程序docker create --name extract sparkdevo/href-counter:build# 拷貝編譯好的應用程序docker cp extract:/go/src/github.com/sparkdevo/href-counter/app ./appdocker rm -f extractecho Building sparkdevo/href-counter:latest# 構建運行應用程序的鏡像docker build --no-cache -t sparkdevo/href-counter:latest .

把上面的內容保存到 build.sh 文件中。這個腳本會先創建出一個容器來構建應用程序,然后再創建最終運行應用程序的鏡像。

把 app.go、Dockerfile.build、Dockerfile 和 build.sh 放在同一個目錄下,然后進入這個目錄執行 build.sh 腳本進行構建。構建后的容器鏡像大?。?/p>

docker,multi,stage,build

從上圖中我們可以觀察到,用于編譯應用程序的容器鏡像大小接近 700M,而用于生產環境的容器鏡像只有 10.3 M,這樣的大小在網絡間傳輸的效率是很高的。

運行下面的命令可以檢查我們構建的容器是否可以正常的工作:

$ docker run -e url=https://www.cnblogs.com/ sparkdevo/href-counter:latest$ docker run -e url=http://www.cnblogs.com/sparkdev/ sparkdevo/href-counter:latest

docker,multi,stage,build

OK,我們寫的程序正確的統計了博客園首頁和筆者的首頁中超級鏈接的情況。

采用上面的構建過程,我們需要維護兩個 Dockerfile 文件和一個腳本文件 build.sh。能不能簡化一些呢? 下面我們看看 docker 針對這種情況提供的解決方案:multi-stage。

在 Dockerfile 中使用 multi-stage

multi-stage 允許我們在 Dockerfile 中完成類似前面 build.sh 腳本中的功能,每個 stage 可以理解為構建一個容器鏡像,后面的 stage 可以引用前面 stage 中創建的鏡像。所以我們可以使用下面單個的 Dockerfile 文件實現前面的需求:

FROM golang:1.7.3WORKDIR /go/src/github.com/sparkdevo/href-counter/RUN go get -d -v golang.org/x/net/htmlCOPY app.go .RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .FROM alpine:latestRUN apk --no-cache add ca-certificatesWORKDIR /root/COPY --from=0 /go/src/github.com/sparkdevo/href-counter/app .CMD ["./app"]

把上面的內容保存到文件 Dockerfile.multi 中。這個 Dockerfile 文件的特點是同時存在多個 FROM 指令,每個 FROM 指令代表一個 stage 的開始部分。我們可以把一個 stage 的產物拷貝到另一個 stage 中。本例中的第一個 stage 完成了應用程序的構建,內容和前面的 Dockerfile.build 是一樣的。第二個 stage 中的 COPY 指令通過 --from=0 引用了第一個 stage ,并把應用程序拷貝到了當前 stage 中。接下來讓我們編譯新的鏡像:

$ docker build --no-cache -t sparkdevo/href-counter:multi . -f Dockerfile.multi

這次使用 href-counter:multi 鏡像運行應用:

$ docker run -e url=https://www.cnblogs.com/ sparkdevo/href-counter:multi$ docker run -e url=http://www.cnblogs.com/sparkdev/ sparkdevo/href-counter:multi

docker,multi,stage,build

結果和之前是一樣的。那么新生成的鏡像有沒有特別之處呢:

docker,multi,stage,build

好吧,從上圖我們可以看到,除了 sparkdevo/href-counter:multi 鏡像,還生成了一個匿名的鏡像。因此,所謂的 multi-stage 不過時多個 Dockerfile 的語法糖罷了。但是這個語法糖還好很誘人的,現在我們維護一個結構簡潔的 Dockerfile 文件就可以了!

使用命名的 stage

在上面的例子中我們通過 --from=0 引用了 Dockerfile 中第一個 stage,這樣的做法會讓 Dockerfile 變得不容易閱讀。其實我們是可以為 stage 命名的,然后就可以通過名稱來引用 stage 了。下面是改造后的 Dockerfile.mult 文件:

FROM golang:1.7.3 as builderWORKDIR /go/src/github.com/sparkdevo/href-counter/RUN go get -d -v golang.org/x/net/htmlCOPY app.go .RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .FROM alpine:latestRUN apk --no-cache add ca-certificatesWORKDIR /root/COPY --from=builder /go/src/github.com/sparkdevo/href-counter/app .CMD ["./app"]

我們把第一個 stage 使用 as 語法命名為 builder,然后在后面的 stage 中通過名稱 builder 進行引用 --from=builder。通過使用命名的 stage, Dockerfile 更容易閱讀了。

總結

Dockerfile 中的 multi-stage 雖然只是些語法糖,但它確實為我們帶來了很多便利。尤其是減輕了 Dockerfile 維護者的負擔(要知道實際生產中的 Dockerfile 可不像 demo 中的這么簡單)。需要注意的是舊版本的 docker 是不支持 multi-stage 的,只有 17.05 以及之后的版本才開始支持。好了,是不是該去升級你的 docker 版本了?

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。

參考:

  • Use multi-stage builds
  • Builder pattern vs. Multi-stage builds in Docker

注:相關教程知識閱讀請移步到服務器教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲www在线观看| 欧美日韩国产91| 亚洲欧美国产制服动漫| 国产在线久久久| 亚洲精品国精品久久99热一| 国产精品久久久999| 爽爽爽爽爽爽爽成人免费观看| 亚洲美女福利视频网站| 亚洲伊人一本大道中文字幕| 欧美性xxxxhd| 日韩美女av在线免费观看| 成人久久久久久| 亚洲自拍偷拍一区| 日韩欧美国产成人| 理论片在线不卡免费观看| 久久久久www| 久久免费视频在线观看| 国产v综合v亚洲欧美久久| 菠萝蜜影院一区二区免费| 自拍偷拍亚洲欧美| 欧美大尺度电影在线观看| 77777少妇光屁股久久一区| 亚洲女人被黑人巨大进入| 亚洲视频精品在线| 日韩精品一区二区三区第95| 国产精品免费一区豆花| 欧美精品videos另类日本| 日韩av毛片网| 亚洲黄在线观看| 日本免费久久高清视频| 欧美激情视频免费观看| 日韩人在线观看| 亚洲理论在线a中文字幕| 日韩精品中文字幕久久臀| 国产97在线亚洲| 成人免费视频97| 久久久久国产精品一区| 欧亚精品在线观看| 91中文在线视频| 91免费观看网站| 欧美又大又硬又粗bbbbb| 国产精品精品久久久| 欧美日韩国产精品一区二区三区四区| 综合国产在线视频| 亚洲级视频在线观看免费1级| 午夜精品久久久久久久99黑人| 欧美超级乱淫片喷水| 国产精品免费小视频| 成人有码视频在线播放| 韩国19禁主播vip福利视频| 亚洲色图在线观看| 91精品国产综合久久香蕉922| 最新国产精品拍自在线播放| 精品激情国产视频| 亚洲精品永久免费精品| 欧美午夜精品伦理| 欧美黑人视频一区| 日本三级韩国三级久久| 欧美一区三区三区高中清蜜桃| 国产精品网站大全| 欧美孕妇与黑人孕交| 久久精品夜夜夜夜夜久久| 亚洲欧美日韩综合| 国产精品第二页| 欧美一级免费视频| 日韩av影院在线观看| 日韩欧美一区二区在线| 国产成人亚洲综合91精品| 欧美激情性做爰免费视频| 国产午夜精品理论片a级探花| 久久精品2019中文字幕| 久久影视电视剧免费网站| 亚洲人成网站777色婷婷| 成人国产精品一区二区| 欧美一级片在线播放| 亚洲在线第一页| 国产免费一区二区三区在线观看| 久久理论片午夜琪琪电影网| 日韩av观看网址| 久久久亚洲精选| 国产精品成人av在线| 国产精品三级网站| 日韩欧中文字幕| 日韩在线视频线视频免费网站| 国产精品露脸av在线| 91在线播放国产| 欧美噜噜久久久xxx| 日韩欧美国产网站| 国产日产亚洲精品| 日韩成人性视频| 欧美激情视频一区二区三区不卡| 欧美日韩aaaa| 欧美xxxx做受欧美| 日韩精品视频在线免费观看| 欧美激情网站在线观看| 国产不卡在线观看| 久久手机免费视频| 欧美性猛交xxxx免费看漫画| 欧美xxxx14xxxxx性爽| 欧美精品一二区| 欧美与黑人午夜性猛交久久久| 国产精品pans私拍| 日韩欧亚中文在线| 91精品国产自产在线老师啪| 欧美亚洲视频一区二区| 亚洲国产精品yw在线观看| 久久久女女女女999久久| 亚洲a成v人在线观看| 国产一区二区香蕉| 欧美一级在线播放| 日韩精品在线私人| 日韩在线观看精品| 欧美久久精品一级黑人c片| 久久久91精品| 97精品一区二区视频在线观看| 日韩av在线网址| 国产玖玖精品视频| 欧美一级免费视频| 国产成人福利视频| 欧洲精品毛片网站| 国内外成人免费激情在线视频网站| 国产一区二区三区在线播放免费观看| 97视频在线观看网址| 国产a级全部精品| 亚洲字幕一区二区| 精品国产区一区二区三区在线观看| 亚洲午夜女主播在线直播| 亚洲成人免费在线视频| 日韩一区二区欧美| 日韩大胆人体377p| 久久青草精品视频免费观看| 久久久久久18| 成人写真福利网| 久久影院免费观看| 51色欧美片视频在线观看| 欧美高清视频在线观看| 亚洲色图美腿丝袜| 久久久精品2019中文字幕神马| 久久影视电视剧凤归四时歌| 亚洲小视频在线| 欧美有码在线观看| 亚洲精品久久在线| 亚洲成av人影院在线观看| 日韩免费看的电影电视剧大全| 亚洲精品乱码久久久久久按摩观| 亚洲综合日韩中文字幕v在线| 岛国av午夜精品| 国产精品私拍pans大尺度在线| 国产情人节一区| 日韩av手机在线观看| 日韩美女av在线| 国产欧美日韩91| 成人国产精品一区二区| 在线观看视频亚洲| 欧美综合一区第一页| 亚洲国产日韩欧美在线99| 欧美精品制服第一页| 日韩av电影中文字幕| 日韩的一区二区| 在线观看日韩视频| 亚洲午夜精品视频| 91精品国产自产91精品| 久久久久久18| 日本高清+成人网在线观看|