久久久精品一区ed2k-女人被男人叉到高潮的视频-中文字幕乱码一区久久麻豆樱花-俄罗斯熟妇真实视频

Docker鏡像怎么制作

這篇文章主要講解了“Docker鏡像怎么制作”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Docker鏡像怎么制作”吧!

成都創(chuàng)新互聯(lián)是一家專業(yè)從事成都網(wǎng)站建設(shè)、做網(wǎng)站的網(wǎng)絡(luò)公司。作為專業(yè)網(wǎng)絡(luò)公司,成都創(chuàng)新互聯(lián)依托的技術(shù)實力、以及多年的網(wǎng)站運(yùn)營經(jīng)驗,為您提供專業(yè)的成都網(wǎng)站建設(shè)、成都全網(wǎng)營銷推廣及網(wǎng)站設(shè)計開發(fā)服務(wù)!

1. Go 語言鏡像精簡

Go 語言程序編譯時會將所有必須的依賴編譯到二進(jìn)制文件中,但也不能完全肯定它使用的是靜態(tài)鏈接,因為 Go 的某些包是依賴系統(tǒng)標(biāo)準(zhǔn)庫的,例如使用到 DNS 解析的包。只要代碼中導(dǎo)入了這些包,編譯的二進(jìn)制文件就需要調(diào)用到某些系統(tǒng)庫,為了這個需求,Go 實現(xiàn)了一種機(jī)制叫 cgo,以允許 Go 調(diào)用 C 代碼,這樣編譯好的二進(jìn)制文件就可以調(diào)用系統(tǒng)庫。

也就是說,如果 Go 程序使用了 net 包,就會生成一個動態(tài)的二進(jìn)制文件,如果想讓鏡像能夠正常工作,必須將需要的庫文件復(fù)制到鏡像中,或者直接使用 busybox:glibc 鏡像。

當(dāng)然,你也可以禁止 cgo,這樣 Go 就不會使用系統(tǒng)庫,使用內(nèi)置的實現(xiàn)來替代系統(tǒng)庫(例如使用內(nèi)置的 DNS 解析器),這種情況下生成的二進(jìn)制文件就是靜態(tài)的??梢酝ㄟ^設(shè)置環(huán)境變量 CGO_ENABLED=0 來禁用 cgo,例如:

FROM golang
COPY whatsmyip.go .
ENV CGO_ENABLED=0
RUN go build whatsmyip.go

FROM scratch
COPY --from=0 /go/whatsmyip .
CMD ["./whatsmyip"]

由于編譯生成的是靜態(tài)二進(jìn)制文件,因此可以直接跑在 scratch 鏡像中 ????

當(dāng)然,也可以不用完全禁用 cgo,可以通過 -tags 參數(shù)指定需要使用的內(nèi)建庫,例如 -tags netgo 就表示使用內(nèi)建的 net 包,不依賴系統(tǒng)庫:

$ go build -tags netgo whatsmyip.go

這樣指定之后,如果導(dǎo)入的其他包都沒有用到系統(tǒng)庫,那么編譯得到的就是靜態(tài)二進(jìn)制文件。也就是說,只要還有一個包用到了系統(tǒng)庫,都會開啟 cgo,最后得到的就是動態(tài)二進(jìn)制文件。要想一勞永逸,還是設(shè)置環(huán)境變量 CGO_ENABLED=0 吧。

2. Alpine 鏡像探秘

上篇文章已經(jīng)對 Alpine 鏡像作了簡要的介紹,并保證會在后面的文章中花很大的篇幅來討論 Alpine 鏡像,現(xiàn)在時候到了!

Alpine 是眾多 Linux 發(fā)行版中的一員,和 CentOS、Ubuntu、Archlinux 之類一樣,只是一個發(fā)行版的名字,號稱小巧安全,有自己的包管理工具 apk。

與 CentOS 和 Ubuntu 不同,Alpine 并沒有像 Red HatCanonical 之類的大公司為其提供維護(hù)支持,軟件包的數(shù)量也比這些發(fā)行版少很多(如果只看開箱即用的默認(rèn)軟件倉庫,Alpine 只有 10000 個軟件包,而 Ubuntu、Debian 和 Fedora 的軟件包數(shù)量均大于 50000。)

容器崛起之前,Alpine 還是個無名之輩,可能是因為大家并不是很關(guān)心操作系統(tǒng)本身的大小,畢竟大家只關(guān)心業(yè)務(wù)數(shù)據(jù)和文檔,程序、庫文件和系統(tǒng)本身的大小通??梢院雎圆挥嫛?/p>

容器技術(shù)席卷整個軟件產(chǎn)業(yè)之后,大家都注意到了一個問題,那就是容器的鏡像太大了,浪費(fèi)磁盤空間,拉取鏡像的時間也很長。于是,人們開始尋求適用于容器的更小的鏡像。對于那些耳熟能詳?shù)陌l(fā)行版(例如 Ubuntu、Debian、Fedora)來說,只能通過刪除某些工具(例如 ifconfignetstat)將鏡像體積控制在 100M 以下。而對于 Alpine 而言,什么都不用刪除,鏡像大小也就只有 5M 而已。

Alpine 鏡像的另一個優(yōu)勢是包管理工具的執(zhí)行速度非??欤惭b軟件體驗非常順滑。誠然,在傳統(tǒng)的虛擬機(jī)上不需要太關(guān)心軟件包的安裝速度,同一個包只需要裝一次即可,無需不停重復(fù)安裝。容器就不一樣了,你可能會定期構(gòu)建新鏡像,也可能會在運(yùn)行的容器中臨時安裝某些調(diào)試工具,如果軟件包的安裝速度很慢,會很快消磨掉我們的耐心。

為了更直觀,我們來做個簡單的對比測試,看看不同的發(fā)行版安裝 tcpdump 需要多長時間,測試命令如下:

???? → time docker run <image> <packagemanager> install tcpdump

測試結(jié)果如下:

Base image           Size      Time to install tcpdump
---------------------------------------------------------
alpine:3.11          5.6 MB      1-2s
archlinux:20200106   409 MB      7-9s
centos:8             237 MB      5-6s
debian:10            114 MB      5-7s
fedora:31            194 MB    35-60s
ubuntu:18.04          64 MB      6-8s

如果你想了解更多關(guān)于 Alpine 的內(nèi)幕,可以看看 Natanel Copa 的演講。

好吧,既然 Alpine 這么棒,為什么不用它作為所有鏡像的基礎(chǔ)鏡像呢?別急,先一步一步來,為了趟平所有的坑,需要分兩種情況來考慮:

  1. 使用 Alpine 作為第二構(gòu)建階段(run 階段)的基礎(chǔ)鏡像

  2. 使用 ALpine 作為所有構(gòu)建階段(run 階段和 build 階段)的基礎(chǔ)鏡像

run 階段使用 Alpine

帶著激動的心情,將 Alpine 鏡像加入了 Dockerfile:

FROM gcc AS mybuildstage
COPY hello.c .
RUN gcc -o hello hello.c

FROM alpine
COPY --from=mybuildstage hello .
CMD ["./hello"]

第一個坑來了,啟動容器出現(xiàn)了錯誤:

standard_init_linux.go:211: exec user process caused "no such file or directory"

這個報錯在上篇文章已經(jīng)見識過了,上篇文章的場景是使用 scratch 鏡像作為 C 語言程序的基礎(chǔ)鏡像,錯誤的原因是 scratch 鏡像中缺少動態(tài)庫文件??墒菫槭裁词褂?Alpine 鏡像也有報錯,難道它也缺少動態(tài)庫文件?

也不完全是,Alpine 使用的也是動態(tài)庫,畢竟它的設(shè)計目標(biāo)之一就是占用更少的空間。但 Alpine 使用的標(biāo)準(zhǔn)庫與大多數(shù)發(fā)行版不同,它使用的是 musl libc,這個庫相比于 glibc 更小、更簡單、更安全,但是與大家常用的標(biāo)準(zhǔn)庫 glibc 并不兼容。

你可能又要問了:『既然 musl libc 更小、更簡單,還特么更安全,為啥其他發(fā)行版還在用 glibc?』

mmm。。。因為 glibc 有很多額外的擴(kuò)展,并且很多程序都用到了這些擴(kuò)展,而 musl libc 是不包含這些擴(kuò)展的。詳情可以參考 musl 的文檔。

也就是說,如果想讓程序跑在 Alpine 鏡像中,必須在編譯時使用 musl libc 作為動態(tài)庫。

所有階段使用 Alpine

為了生成一個與 musl libc 鏈接的二進(jìn)制文件,有兩條路:

  • 某些官方鏡像提供了 Alpine 版本,可以直接拿來用。

  • 還有些官方鏡像沒有提供 Alpine 版本,我們需要自己構(gòu)建。

golang 鏡像就屬于第一種情況,golang:alpine 提供了基于 Alpine 構(gòu)建的 Go 工具鏈。

構(gòu)建 Go 程序可以使用下面的 Dockerfile

FROM golang:alpine
COPY hello.go .
RUN go build hello.go

FROM alpine
COPY --from=0 /go/hello .
CMD ["./hello"]

生成的鏡像大小為 7.5M,對于一個只打印 『hello world』的程序來說確實有點大了,但我們可以換個角度:

  • 即使程序很復(fù)雜,生成的鏡像也不會很大。

  • 包含了很多有用的調(diào)試工具。

  • 即使運(yùn)行時缺少某些特殊的調(diào)試工具,也可以迅速安裝。

Go 語言搞定了,C 語言呢?并沒有 gcc:alpine 這樣的鏡像啊。只能以 Alpine 鏡像作為基礎(chǔ)鏡像,自己安裝 C 編譯器了,Dockerfile 如下:

FROM alpine
RUN apk add build-base
COPY hello.c .
RUN gcc -o hello hello.c

FROM alpine
COPY --from=0 hello .
CMD ["./hello"]

必須安裝 build-base,如果安裝 gcc,就只有編譯器,沒有標(biāo)準(zhǔn)庫。build-base 相當(dāng)于 Ubuntu 的 build-essentials,引入了編譯器、標(biāo)準(zhǔn)庫和 make 之類的工具。

最后來對比一下不同構(gòu)建方法得到的 『hello world』鏡像大小:

  • 使用基礎(chǔ)鏡像 golang 構(gòu)建:805MB

  • 多階段構(gòu)建,build 階段使用基礎(chǔ)鏡像 golang,run 階段使用基礎(chǔ)鏡像 ubuntu:66.2MB

  • 多階段構(gòu)建,build 階段使用基礎(chǔ)鏡像 golang:alpine,run 階段使用基礎(chǔ)鏡像 alpine:7.6MB

  • 多階段構(gòu)建,build 階段使用基礎(chǔ)鏡像 golang,run 階段使用基礎(chǔ)鏡像 scratch:2MB

最終鏡像體積減少了 99.75%,相當(dāng)驚人了。再來看一個更實際的例子,上一節(jié)提到的使用 net 的程序,最終的鏡像大小對比:

  • 使用基礎(chǔ)鏡像 golang 構(gòu)建:810MB

  • 多階段構(gòu)建,build 階段使用基礎(chǔ)鏡像 golang,run 階段使用基礎(chǔ)鏡像 ubuntu:71.2MB

  • 多階段構(gòu)建,build 階段使用基礎(chǔ)鏡像 golang:alpine,run 階段使用基礎(chǔ)鏡像 alpine:12.6MB

  • 多階段構(gòu)建,build 階段使用基礎(chǔ)鏡像 golang,run 階段使用基礎(chǔ)鏡像 busybox:glibc:12.2MB

  • 多階段構(gòu)建,build 階段使用基礎(chǔ)鏡像 golang 并使用參數(shù) CGO_ENABLED=0,run 階段使用基礎(chǔ)鏡像 ubuntu:7MB

鏡像體積仍然減少了 99%。

3. Java 語言鏡像精簡

Java 屬于編譯型語言,但運(yùn)行時還是要跑在 JVM 中。那么對于 Java 語言來說,該如何使用多階段構(gòu)建呢?

靜態(tài)還是動態(tài)?

從概念上來看,Java 使用的是動態(tài)鏈接,因為 Java 代碼需要調(diào)用 JVM 提供的 Java API,這些 API 的代碼都在可執(zhí)行文件之外,通常是 JAR 文件或 WAR 文件。

然而這些 Java 庫并不是完全獨立于系統(tǒng)庫的,某些 Java 函數(shù)最終還是會調(diào)用系統(tǒng)庫,例如打開文件時需要調(diào)用 open(), fopen() 或它們的變體,因此 JVM 本身可能會與系統(tǒng)庫動態(tài)鏈接。

這就意味著理論上可以使用任意的 JVM 來運(yùn)行 Java 程序,系統(tǒng)標(biāo)準(zhǔn)庫是 musl libc 還是 glibc 都無所謂。因此,也就可以使用任意帶有 JVM 的基礎(chǔ)鏡像來構(gòu)建 Java 程序,也可以使用任意帶有 JVM 的鏡像作為運(yùn)行 Java 程序的基礎(chǔ)鏡像。

類文件格式

Java 類文件(Java 編譯器生成的字節(jié)碼)的格式會隨著版本而變化,且大部分變化都是 Java API 的變化。還有一部分更改與 Java 語言本身有關(guān),例如 Java 5 中添加了泛型,這種變化就可能會導(dǎo)致類文件格式的變化,從而破壞與舊版本的兼容性。

所以默認(rèn)情況下,使用給定版本的 Java 編譯器編譯的類不能與更早版本的 JVM 兼容,但可以指定編譯器的 -target (Java 8 及其以下版本)參數(shù)或者 --release (Java 9 及其以上版本)參數(shù)來使用較舊的類文件格式。--release 參數(shù)還可以指定類文件的路徑,以確保程序運(yùn)行在指定的 JVM 版本中(例如 Java 11),不會意外調(diào)用 Java 12 的 API。

JDK vs JRE

如果你對大多數(shù)平臺上的 Java 打包方式很熟悉,那你應(yīng)該知道 JDKJRE。

JRE 即 Java 運(yùn)行時環(huán)境(Java Runtime Environment),包含了運(yùn)行 Java 程序所需要的環(huán)境,即 JVM。

JDK 即 Java 開發(fā)工具包(Java Development Kit),既包含了 JRE,也包含了開發(fā) Java 程序所需的工具,即 Java 編譯器。

大多數(shù) Java 鏡像都提供了 JDK 和 JRE 兩種標(biāo)簽,因此可以在多階段構(gòu)建的 build 階段使用 JDK 作為基礎(chǔ)鏡像,run 階段使用 JRE 作為基礎(chǔ)鏡像。

Java vs OpenJDK

推薦使用 openjdk,因為開源啊,更新勤快啊~~

也可以使用 amazoncorretto,這是 Amazon fork OpenJDK 后打了補(bǔ)丁的版本,號稱企業(yè)級。

開始構(gòu)建

說了那么多,到底該用哪個鏡像呢?這里給出幾個參考:

  • openjdk:8-jre-alpine(85MB)

  • openjdk:11-jre(267MB)或者 openjdk:11-jre-slim(204MB)

  • openjdk:14-alpine(338MB)

如果你想要更直觀的數(shù)據(jù),可以看我的例子,還是搬出屢試不爽的 『hello world』,只不過這次是 Java 版本:

class hello {
  public static void main(String [] args) {
    System.out.println("Hello, world!");
  }
}

不同構(gòu)建方法得到的鏡像大?。?/p>

  • 使用基礎(chǔ)鏡像 java 構(gòu)建:643MB

  • 使用基礎(chǔ)鏡像 openjdk 構(gòu)建:490MB

  • 多階段構(gòu)建,build 階段使用基礎(chǔ)鏡像 openjdk,run 階段使用基礎(chǔ)鏡像 openjdk:jre:479MB

  • 使用基礎(chǔ)鏡像 amazoncorretto 構(gòu)建:390MB

  • 多階段構(gòu)建,build 階段使用基礎(chǔ)鏡像 openjdk:11,run 階段使用基礎(chǔ)鏡像 openjdk:11-jre:267MB

  • 多階段構(gòu)建,build 階段使用基礎(chǔ)鏡像 openjdk:8,run 階段使用基礎(chǔ)鏡像 openjdk:8-jre-alpine:85MB

所有的 Dockerfile 都可以在這個倉庫找到。

4. 解釋型語言鏡像精簡

對于諸如 Node、Python、Rust 之類的解釋型語言來說,情況就比較復(fù)雜一點了。先來看看 Alpine 鏡像。

Alpine 鏡像

對于解釋型語言來說,如果程序僅用到了標(biāo)準(zhǔn)庫或者依賴項和程序本身使用的是同一種語言,且無需調(diào)用 C 庫和外部依賴,那么使用 Alpine 作為基礎(chǔ)鏡像一般是沒有啥問題的。一旦你的程序需要調(diào)用外部依賴,情況就復(fù)雜了,想繼續(xù)使用 Alpine 鏡像,就得安裝這些依賴。根據(jù)難度可以劃分為三個等級:

  • 簡單:依賴庫有針對 Alpine 的安裝說明,一般會說明需要安裝哪些軟件包以及如何建立依賴關(guān)系。但這種情況非常罕見,原因前面也提到了,Alpine 的軟件包數(shù)量比大多數(shù)流行的發(fā)行版要少得多。

  • 中等:依賴庫沒有針對 Alpine 的安裝說明,但有針對別的發(fā)行版的安裝說明。我們可以通過對比找到與別的發(fā)行版的軟件包相匹配的 Alpine 軟件包(假如有的話)。

  • 困難:依賴庫沒有針對 Alpine 的安裝說明,但有針對別的發(fā)行版的安裝說明,但是 Alpine 也沒有與之對應(yīng)的軟件包。這種情況就必須從源碼開始構(gòu)建!

最后一種情況最不推薦使用 Alpine 作為基礎(chǔ)鏡像,不但不能減小體積,可能還會適得其反,因為你需要安裝編譯器、依賴庫、頭文件等等。。。更重要的是,構(gòu)建時間會很長,效率低下。如果非要考慮多階段構(gòu)建,就更復(fù)雜了,你得搞清楚如何將所有的依賴編譯成二進(jìn)制文件,想想就頭大。因此一般不推薦在解釋型語言中使用多階段構(gòu)建。

有一種特殊情況會同時遇到 Alpine 的絕大多數(shù)問題:將 Python 用于數(shù)據(jù)科學(xué)。numpypandas 之類的包都被預(yù)編譯成了 wheel,wheel 是 Python 新的打包格式,被編譯成了二進(jìn)制,用于替代 Python 傳統(tǒng)的 egg 文件,可以通過 pip 直接安裝。但這些 wheel 都綁定了特定的 C 庫,這就意味著在大多數(shù)使用 glibc 的鏡像中都可以正常安裝,但 Alpine 鏡像就不行,原因你懂得,前面已經(jīng)說過了。如果非要在 Alpine 中安裝,你需要安裝很多依賴,重頭構(gòu)建,耗時又費(fèi)力,有一篇文章專門解釋了這個問題:使用 Alpine 構(gòu)建 Pyhton 鏡像會將構(gòu)建速度拖慢 50 倍!。

既然 Alpine 鏡像這么坑,那么是不是只要是 Python 寫的程序就不推薦使用 Alpine 鏡像來構(gòu)建呢?也不能完全這么肯定,至少 Python 用于數(shù)據(jù)科學(xué)時不推薦使用 Alpine,其他情況還是要具體情況具體分析,如果有可能,還是可以試一試 Alpine 的。

:slim 鏡像

如果實在不想折騰,可以選擇一個折衷的鏡像 xxx:slim。slim 鏡像一般都基于 Debianglibc,刪除了許多非必需的軟件包,優(yōu)化了體積。如果構(gòu)建過程中需要編譯器,那么 slim 鏡像不適合,除此之外大多數(shù)情況下還是可以使用 slim 作為基礎(chǔ)鏡像的。

下面是主流的解釋型語言的 Alpine 鏡像和 slim 鏡像大小對比:

Image            Size
---------------------------
node             939 MB
node:alpine      113 MB
node:slim        163 MB
python           932 MB
python:alpine    110 MB
python:slim      193 MB
ruby             842 MB
ruby:alpine       54 MB
ruby:slim        149 MB

再來舉個特殊情況的例子,同時安裝 matplotlib,numpypandas,不同的基礎(chǔ)鏡像構(gòu)建的鏡像大小如下:

Image and technique         Size
--------------------------------------
python                      1.26 GB
python:slim                  407 MB
python:alpine                523 MB
python:alpine multi-stage    517 MB

可以看到這種情況下使用 Alpine 并沒有任何幫助,即使使用多階段構(gòu)建也無濟(jì)于事。

但也不能全盤否定 Alpine,比如下面這種情況:包含大量依賴的 Django 應(yīng)用。

Image and technique         Size
--------------------------------------
python                      1.23 GB
python:alpine                636 MB
python:alpine multi-stage    391 MB

最后來總結(jié)一下:到底使用哪個基礎(chǔ)鏡像并不能蓋棺定論,有時使用 Alpine 效果更好,有時反而使用 slim 效果更好,如果你對鏡像體積有著極致的追求,可以這兩種鏡像都嘗試一下。相信隨著時間的推移,我們就會積累足夠的經(jīng)驗,知道哪種情況該用 Alpine,哪種情況該用 slim,不用再一個一個嘗試。

5. Rust 語言鏡像精簡

Rust 是最初由 Mozilla 設(shè)計的現(xiàn)代編程語言,并且在 Web 和基礎(chǔ)架構(gòu)領(lǐng)域中越來越受歡迎。Rust 編譯的二進(jìn)制文件動態(tài)鏈接到 C 庫,可以正常運(yùn)行于 UbuntuDebianFedora 之類的鏡像中,但不能運(yùn)行于 busybox:glibc 中。因為 Rust 二進(jìn)制需要調(diào)用 libdl 庫,busybox:glibc 中不包含該庫。

還有一個 rust:alpine 鏡像,Rust 編譯的二進(jìn)制也可以正常運(yùn)行其中。

如果考慮編譯成靜態(tài)鏈接,可以參考 Rust 官方文檔。在 Linux 上需要構(gòu)建一個特殊版本的 Rust 編譯器,構(gòu)建的依賴庫就是 musl libc,你沒有看錯,就是 Alpine 中的那個 musl libc。如果你想獲得更小的鏡像,請按照文檔中的說明進(jìn)行操作,最后將生成的二進(jìn)制文件扔進(jìn) scratch 鏡像中就好了。

感謝各位的閱讀,以上就是“Docker鏡像怎么制作”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Docker鏡像怎么制作這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

當(dāng)前文章:Docker鏡像怎么制作
文章轉(zhuǎn)載:http://sd-ha.com/article14/jossge.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、小程序開發(fā)商城網(wǎng)站、網(wǎng)站排名、軟件開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)