久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Docker中Dockerfile多From指令存在的意義是什么

150次閱讀
沒有評論

共計 3156 個字符,預計需要花費 8 分鐘才能閱讀完成。

這篇文章主要介紹 Docker 中 Dockerfile 多 From 指令存在的意義是什么,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

老版本 Docker 中為什么不支持多個 FROM 指令

在 17.05 版本之前的 Docker,只允許 Dockerfile 中出現一個 FROM 指令,這得從鏡像的本質說起。

在《Docker 概念簡介》中我們提到,你可以簡單理解 Docker 的鏡像是一個壓縮文件,其中包含了你需要的程序和一個文件系統。其實這樣說是不嚴謹的,Docker 鏡像并非只是一個文件,而是由一堆文件組成,最主要的文件是 層。

Dockerfile 中,大多數指令會生成一個層,比如下方的兩個例子:

#  示例一,foo  鏡像的 Dockerfile
#  基礎鏡像中已經存在若干個層了
FROM ubuntu:16.04
# RUN 指令會增加一層,在這一層中,安裝了  git  軟件
RUN apt-get update \
   apt-get install -y --no-install-recommends git \
   apt-get clean \
   rm -rf /var/lib/apt/lists/*
#  示例二,bar  鏡像的 Dockerfile
FROM foo
# RUN 指令會增加一層,在這一層中,安裝了  nginx
RUN apt-get update \
   apt-get install -y --no-install-recommends nginx \
   apt-get clean \
   rm -rf /var/lib/apt/lists/*

假設基礎鏡像 ubuntu:16.04 已經存在 5 層,使用第一個 Dockerfile 打包成鏡像 foo,則 foo 有 6 層,又使用第二個 Dockerfile 打包成鏡像 bar,則 bar 中有 7 層。

如果 ubuntu:16.04 等其他鏡像不算,如果系統中只存在 foo 和 bar 兩個鏡像,那么系統中一共保存了多少層呢?

是 7 層,并非 13 層,這是因為,foo 和 bar 共享了 6 層。層的共享機制可以節約大量的磁盤空間和傳輸帶寬,比如你本地已經有了 foo 鏡像,又從鏡像倉庫中拉取 bar 鏡像時,只拉取本地所沒有的最后一層就可以了,不需要把整個 bar 鏡像連根拉一遍。但是層共享是怎樣實現的呢?

原來,Docker 鏡像的每一層只記錄文件變更,在容器啟動時,Docker 會將鏡像的各個層進行計算,最后生成一個文件系統,這個被稱為 聯合掛載。對此感興趣的話可以進入了解一下 AUFS。

Docker 的各個層是有相關性的,在聯合掛載的過程中,系統需要知道在什么樣的基礎上再增加新的文件。那么這就要求一個 Docker 鏡像只能有一個起始層,只能有一個根。所以,Dockerfile 中,就只允許一個 FROM 指令。因為多個 FROM 指令會造成多根,則是無法實現的。但為什么 Docker 17.05 版本以后允許 Dockerfile 支持多個 FROM 指令了呢,莫非已經支持了多根?

多個 FROM 指令的意義

多個 FROM 指令并不是為了生成多根的層關系,最后生成的鏡像,仍以最后一條 FROM 為準,之前的 FROM 會被拋棄,那么之前的 FROM 又有什么意義呢?

每一條 FROM 指令都是一個構建階段,多條 FROM 就是多階段構建,雖然最后生成的鏡像只能是最后一個階段的結果,但是,能夠將前置階段中的文件拷貝到后邊的階段中,這就是多階段構建的最大意義。

最大的使用場景是將編譯環境和運行環境分離,比如,之前我們需要構建一個 Go 語言程序,那么就需要用到 go 命令等編譯環境,我們的 Dockerfile 可能是這樣的:

# Go 語言環境基礎鏡像
FROM golang:1.10.3
#  將源碼拷貝到鏡像中
COPY server.go /build/
#  指定工作目錄
WORKDIR /build
#  編譯鏡像時,運行  go build  編譯生成  server  程序
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOARM=6 go build -ldflags  -w -s  -o server
#  指定容器運行時入口程序  server
ENTRYPOINT [/build/server]

基礎鏡像 golang:1.10.3 是非常龐大的,因為其中包含了所有的 Go 語言編譯工具和庫,而運行時候我們僅僅需要編譯后的 server 程序就行了,不需要編譯時的編譯工具,最后生成的大體積鏡像就是一種浪費。

使用脈沖云的解決辦法是將程序編譯和鏡像打包分開,使用脈沖云的編譯構建服務,選擇增加構 Go 語言構建工具,然后在構建步驟中編譯。

Docker 中 Dockerfile 多 From 指令存在的意義是什么

最后將編譯接口拷貝到鏡像中就行了,那么 Dockerfile 的基礎鏡像并不需要包含 Go 編譯環境:

#  不需要 Go 語言編譯環境
FROM scratch
#  將編譯結果拷貝到容器中
COPY server /server
#  指定容器運行時入口程序  server
ENTRYPOINT [/server]

提示:scratch 是內置關鍵詞,并不是一個真實存在的鏡像。FROM scratch 會使用一個完全干凈的文件系統,不包含任何文件。因為 Go 語言編譯后不需要運行時,也就不需要安裝任何的運行庫。FROM scratch 可以使得最后生成的鏡像最小化,其中只包含了 server 程序。

在 Docker 17.05 版本以后,就有了新的解決方案,直接一個 Dockerfile 就可以解決:

#  編譯階段
FROM golang:1.10.3
COPY server.go /build/
WORKDIR /build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOARM=6 go build -ldflags  -w -s  -o server
#  運行階段
FROM scratch
#  從編譯階段的中拷貝編譯結果到當前鏡像中
COPY --from=0 /build/server /
ENTRYPOINT [/server]

這個 Dockerfile 的玄妙之處就在于 COPY 指令的 –from=0 參數,從前邊的階段中拷貝文件到當前階段中,多個 FROM 語句時,0 代表第一個階段。除了使用數字,我們還可以給階段命名,比如:

#  編譯階段   命名為  builder
FROM golang:1.10.3 as builder
# ...  省略
#  運行階段
FROM scratch
#  從編譯階段的中拷貝編譯結果到當前鏡像中
COPY --from=builder /build/server /

更為強大的是,COPY –from 不但可以從前置階段中拷貝,還可以直接從一個已經存在的鏡像中拷貝。比如,

FROM ubuntu:16.04
COPY --from=quay.io/coreos/etcd:v3.3.9 /usr/local/bin/etcd /usr/local/bin/

我們直接將 etcd 鏡像中的程序拷貝到了我們的鏡像中,這樣,在生成我們的程序鏡像時,就不需要源碼編譯 etcd 了,直接將官方編譯好的程序文件拿過來就行了。

有些程序要么沒有 apt 源,要么 apt 源中的版本太老,要么干脆只提供源碼需要自己編譯,使用這些程序時,我們可以方便地使用已經存在的 Docker 鏡像作為我們的基礎鏡像。但是我們的軟件有時候可能需要依賴多個這種文件,我們并不能同時將 nginx 和 etcd 的鏡像同時作為我們的基礎鏡像(不支持多根),這種情況下,使用 COPY –from 就非常方便實用了。

以上是“Docker 中 Dockerfile 多 From 指令存在的意義是什么”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注丸趣 TV 行業資訊頻道!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-25發表,共計3156字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 兴仁县| 荥阳市| 延吉市| 林甸县| 中山市| 海原县| 桃源县| 漳平市| 杭锦旗| 佳木斯市| 会东县| 永兴县| 海原县| 高陵县| 东宁县| 虎林市| 莫力| 衡阳县| 景洪市| 莱芜市| 南乐县| 香港 | 池州市| 临洮县| 独山县| 尚义县| 巢湖市| 威海市| 嘉峪关市| 长岭县| 象山县| 措勤县| 达孜县| 扬州市| 宜章县| 邹城市| 黄山市| 武乡县| 江津市| 宁陵县| 丰台区|