激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

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

服務器之家 - 服務器技術 - 服務器知識 - Dockerfile中multi-stage(多階段構建)詳解

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

2021-02-21 16:19sparkdev 服務器知識

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

前言

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 )獲取本文相關的代碼):

?
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))
}

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

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

?
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 .

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

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
echo 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 ./app
docker rm -f extract
 
echo 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 腳本進行構建。構建后的容器鏡像大小:

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

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

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

?
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(多階段構建)詳解

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

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

在 dockerfile 中使用 multi-stage

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

?
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"]

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

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

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

?
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(多階段構建)詳解

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

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

好吧,從上圖我們可以看到,除了 sparkdevo/href-counter:multi 鏡像,還生成了一個匿名的鏡像。因此,所謂的 multi-stage 不過時多個 dockerfile 的語法糖罷了。但是這個語法糖還好很誘人的,現在我們維護一個結構簡潔的 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 更容易閱讀了。

總結

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

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

參考:

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 性 毛片| 欧美激情猛片xxxⅹ大3 | 午夜国内精品a一区二区桃色 | 国产一级淫片在线观看 | 日本在线播放一区二区 | 成人在线观看一区二区三区 | 18pao国产成人免费视频 | 久久精品中文字幕一区二区 | 视频一区二区在线播放 | 日本成人一区二区 | 91久久久久久久一区二区 | 911色_911色sss主站色播 | 免费永久看羞羞片网站入口 | 国产免费传媒av片在线 | av免费在线网| 国产在线区| 欧美三级欧美成人高清www | 亚洲成人第一页 | 91久久久久久久久久久久久久 | 欧美wwwsss9999 | 成人毛片视频免费看 | 暴力肉体进入hdxxxx古装 | 精品成人av一区二区三区 | 日本中文视频 | h视频在线播放 | 特级毛片a级毛片100免费 | 久久在线精品视频 | 国产一区精品在线观看 | xxxxxx免费| 美女黄页网站免费进入 | 免费男女视频 | 久久影院免费观看 | 在线a毛片免费视频观看 | 欧美精品黄色 | 懂色av懂色aⅴ精彩av | 99精品热视频 | 性 毛片 | 视频一区二区中文字幕 | 日本成人午夜 | 成人精品久久 | 午夜小视频免费观看 |