国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

云服務(wù)器|WEB服務(wù)器|FTP服務(wù)器|郵件服務(wù)器|虛擬主機|服務(wù)器安全|DNS服務(wù)器|服務(wù)器知識|Nginx|IIS|Tomcat|

服務(wù)器之家 - 服務(wù)器技術(shù) - 服務(wù)器知識 - Dockerfile中multi-stage(多階段構(gòu)建)詳解

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

2021-02-21 16:19sparkdev 服務(wù)器知識

在2017年5月3日即將發(fā)行的 Docker 17.05.0-ce 中,Docker 官方提供了簡便的多階段構(gòu)建 (multi-stage build) 方案,下面這篇文章主要給大家介紹了關(guān)于Dockerfile中multi-stage(多階段構(gòu)建)的相關(guān)資料,需要的朋友可以參考借鑒,下面隨著小編來一起

前言

docker的口號是build,ship,and run any app,anywhere,在我們使用 docker 的大部分時候,的確能感覺到其優(yōu)越性,但是往往在我們 build 一個應(yīng)用的時候,是將我們的源代碼也構(gòu)建進去的,這對于類似于 golang 這樣的編譯型語言肯定是不行的,因為實際運行的時候我只需要把最終構(gòu)建的二進制包給你就行,把源碼也一起打包在鏡像中,需要承擔(dān)很多風(fēng)險,即使是腳本語言,在構(gòu)建的時候也可能需要使用到一些上線的工具,這樣無疑也增大了我們的鏡像體積。

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

常見的容器鏡像構(gòu)建過程

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package main
import (
 "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))
}

下面我們通過容器來構(gòu)建它,并把它部署到生產(chǎn)型的容器鏡像中。

首先構(gòu)建編譯應(yīng)用程序的鏡像:

?
1
2
3
4
5
from golang:1.7.3
workdir /go/src/github.com/sparkdevo/href-counter/
run go get -d -v golang.org/x/net/html
copy app.go .
run cgo_enabled=0 goos=linux go build -a -installsuffix cgo -o app .

把上面的內(nèi)容保存到 dockerfile.build 文件中。

接著把構(gòu)建好的應(yīng)用程序部署到生產(chǎn)環(huán)境用的鏡像中:

?
1
2
3
4
5
from alpine:latest
run apk --no-cache add ca-certificates
workdir /root/
copy app .
cmd ["./app"]

把上面的內(nèi)容保存到 dockerfile 文件中。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
echo building sparkdevo/href-counter:build
# 構(gòu)建編譯應(yīng)用程序的鏡像
docker build --no-cache -t sparkdevo/href-counter:build . -f dockerfile.build
# 創(chuàng)建應(yīng)用程序
docker create --name extract sparkdevo/href-counter:build
# 拷貝編譯好的應(yīng)用程序
docker cp extract:/go/src/github.com/sparkdevo/href-counter/app ./app
docker rm -f extract
 
echo building sparkdevo/href-counter:latest
# 構(gòu)建運行應(yīng)用程序的鏡像
docker build --no-cache -t sparkdevo/href-counter:latest .

把上面的內(nèi)容保存到 build.sh 文件中。這個腳本會先創(chuàng)建出一個容器來構(gòu)建應(yīng)用程序,然后再創(chuàng)建最終運行應(yīng)用程序的鏡像。

把 app.go、dockerfile.build、dockerfile 和 build.sh 放在同一個目錄下,然后進入這個目錄執(zhí)行 build.sh 腳本進行構(gòu)建。構(gòu)建后的容器鏡像大小:

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

從上圖中我們可以觀察到,用于編譯應(yīng)用程序的容器鏡像大小接近 700m,而用于生產(chǎn)環(huán)境的容器鏡像只有 10.3 m,這樣的大小在網(wǎng)絡(luò)間傳輸?shù)男适呛芨叩摹?/p>

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

?
1
2
$ 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

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

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

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

在 dockerfile 中使用 multi-stage

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

?
1
2
3
4
5
6
7
8
9
10
11
from golang:1.7.3
workdir /go/src/github.com/sparkdevo/href-counter/
run go get -d -v golang.org/x/net/html
copy app.go .
run cgo_enabled=0 goos=linux go build -a -installsuffix cgo -o app .
 
from alpine:latest
run apk --no-cache add ca-certificates
workdir /root/
copy --from=0 /go/src/github.com/sparkdevo/href-counter/app .
cmd ["./app"]

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

?
1
$ docker build --no-cache -t sparkdevo/href-counter:multi . -f dockerfile.multi

這次使用 href-counter:multi 鏡像運行應(yīng)用:

?
1
2
$ 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

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

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

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

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

使用命名的 stage

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

?
1
2
3
4
5
6
7
8
9
10
11
from golang:1.7.3 as builder
workdir /go/src/github.com/sparkdevo/href-counter/
run go get -d -v golang.org/x/net/html
copy app.go .
run cgo_enabled=0 goos=linux go build -a -installsuffix cgo -o app .
 
from alpine:latest
run apk --no-cache add ca-certificates
workdir /root/
copy --from=builder /go/src/github.com/sparkdevo/href-counter/app .
cmd ["./app"]

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

總結(jié)

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

好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。

參考:

原文鏈接:http://www.cnblogs.com/sparkdev/p/8508435.html

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 成人影院在线观看 | 日韩精品在线一区 | 日本久久精品 | 日韩电影一区 | 中文字幕观看 | 欧美日韩免费在线 | 亚洲国产精品99久久久久久久久 | 欧美精品黄色 | 黄色一级网站 | 日韩一区在线播放 | 日韩成人在线观看 | 亚洲色图50p| 国产精品毛片一区二区三区 | 欧美精品久久久 | 黄在线看v | 亚洲福利 | 精品久久久久久亚洲综合网 | 久久国产精品一区二区 | 久久国内精品 | 婷婷国产| 一区二区三区高清 | 中国黄色视屏 | 国产美女自拍视频 | 国产一区二区精品在线观看 | 久草久| 五月激情综合网 | 精品久久av| 国产成人精品一区二 | 视频一区二区在线观看 | 午夜男人天堂 | 亚洲一区中文字幕在线观看 | 日韩成人精品在线 | 日韩理伦片在线观看视频播放 | 亚洲成人影音 | 欧美影院日韩 | 亚洲精品一 | 国产精品久久久久久久 | 国产美女福利在线 | 日韩中文一区二区三区 | 亚洲精品乱码久久久久久花季 | 国产精品久久久久久吹潮 |