原文地址:Docker Images : Part II - Details Specific To Different Languages
介紹
在第一部分中惜论,我們介紹了多階段構建纸镊,靜態(tài)和動態(tài)鏈接,并簡要提到了Alpine。在第二部分中咳胃,我們將深入研究Go特有的一些細節(jié)。然后,我們將更多地討論Alpine,因為它值得我們討論兔港。最后,我們將看到其他語言(例如Java仔拟,Node衫樊,Python,Ruby和Rust)如何發(fā)揮作用理逊。
那么橡伞,Go呢?
你可能已經(jīng)聽說了Go做了件很聰明的事情:構建二進制文件時晋被,它包括該二進制文件中的所有必需依賴項,以方便其部署刚盈。
你可能會想羡洛,“等等,那是靜態(tài)二進制文件藕漱!” 沒錯欲侮。(如果想知道靜態(tài)二進制是什么,可以查看本系列的第一部分肋联。)
一些Go軟件包依賴于系統(tǒng)庫威蕉。舉例來說韧涨,DNS解析宪哩,因為它可以以各種方式進行配置(/etc/hosts锁孟,/etc/resolv.conf和其他一些文件)品抽。一旦我們的代碼導入了這些軟件包之一,Go就需要生成一個調用系統(tǒng)庫的二進制文件南蓬。為此,它啟用了一種名為cgo的機制(簡單來說就是允許Go調用C的代碼)炕淮,并生成一個動態(tài)可執(zhí)行文件,引用了需要調用的系統(tǒng)庫币叹。
這意味著使用例如net包的Go程序將生成動態(tài)二進制文件踩衩,并且約束條件與C程序相同褐鸥。Go程序會要求我們復制所需的庫,或使用類似busybox:glibc的鏡像蠢莺。
但是,我們可以完全禁用cgo会宪。在這種情況下巍沙,Go不會使用系統(tǒng)庫,而是會使用它們對這些庫的內(nèi)置重新實現(xiàn)拨齐。例如,它將使用其自己的解析器挺尿,而不是使用系統(tǒng)的DNS解析器奏黑。生成的二進制文件將是靜態(tài)的。如果要禁用cgo编矾,我們要做的就是設置環(huán)境變量CGO_ENABLED = 0。
例如:
FROM golang
COPY whatsmyip.go .
ENV CGO_ENABLED=0
RUN go build whatsmyip.go
FROM scratch
COPY --from=0 /go/whatsmyip .
CMD ["./whatsmyip"]
由于禁用了cgo馁害,因此Go不會鏈接任何系統(tǒng)庫窄俏,所以會生成靜態(tài)二進制文件。由于它生成的是靜態(tài)二進制文件碘菜,因此該二進制文件可以在scratch鏡像中工作凹蜈。
Tags 和 netgo
我們也可以根據(jù)每個包選擇不同的實現(xiàn)。這是通過使用Go“標簽(tags)”完成的忍啸。標簽是Go構建過程中仰坦,指示應構建或忽略哪些文件的說明。通過啟用標簽“ netgo”计雌,我們告訴Go使用原生net軟件包悄晃,而不是依賴于系統(tǒng)庫的軟件包:
go build -tags netgo whatsmyip.go
如果沒有其他使用系統(tǒng)庫的軟件包,則結果將是靜態(tài)二進制文件凿滤。但是妈橄,如果我們使用另一個導致啟用cgo的程序包,我們將得到動態(tài)文件翁脆。
(這就是為什么設置CGO_ENABLED=0的環(huán)境變量是確保我們獲得靜態(tài)可執(zhí)行文件的最簡單方法的原因眷蚓。)
標簽還用于選擇要在不同體系結構或不同操作系統(tǒng)上構建的代碼。如果我們在Linux和Windows或Intel和ARM CPU上有一些不同的代碼反番,我們也使用標簽來指示編譯器“僅在Linux上構建時才使用”沙热。
Alpine
我們在第一部分中簡要提到了Alpine叉钥,然后說:“我們稍后再討論「菝常” 現(xiàn)在是時候了投队!
Alpine是Linux發(fā)行版,直到幾年前歉秫,大多數(shù)人都將其稱為“ exotic”蛾洛。它的設計既小巧又安全,并使用自己的包管理器apk雁芙。
與CentOS或Ubuntu不同轧膘,它沒有像Red Hat或Canonical這樣的大型公司提供的支持。它的軟件包少于這些發(fā)行版兔甘。(在開箱即用的默認存儲庫中谎碍,Alpine擁有大約10,000個軟件包; Debian洞焙,F(xiàn)edora和Ubuntu各自擁有超過50,000個軟件包蟆淀。)
在容器興起之前,Alpine并不是很流行澡匪,也許是因為很少有人真正在乎Linux系統(tǒng)中安裝包的大小熔任。畢竟,與我們處理的文檔和數(shù)據(jù)(如用戶的圖片和電影唁情;或服務器上的數(shù)據(jù)庫)的大小相比疑苔,其他系統(tǒng)文件的大小通常可以忽略不計甸鸟。
當人們意識到Alpine可以很好地分配容器時惦费,Alpine就引起了人們的關注。我們說它很小抢韭。究竟有多行狡丁?當容器流行時刻恭,每個人都注意到容器的鏡像很大瞧省。它們占用磁盤空間;拉取他們很慢吠各。(正在閱讀本文的你臀突,很可能也正在擔心這個問題,對吧贾漏?)最初的基礎鏡像使用的是“云鏡像”候学,該云鏡像在云服務器上非常流行,大小在幾百MB到幾GB之間纵散。對于云實例(通常通過非呈崧耄快的本地網(wǎng)絡將鏡像從鏡像存儲系統(tǒng)傳輸?shù)教摂M機的情況下)隐圾,該大小是合適的,但是通過電纜或DSL互聯(lián)網(wǎng)將其拉出就要慢得多掰茶。因此暇藏,發(fā)行版維護人員開始研究專門用于容器的較小鏡像。但是濒蒋,盡管流行的發(fā)行版(例如Debian盐碱,Ubuntu,F(xiàn)edora)有時會通過刪除可能有用的工具(例如ifconfig或netstat)而努力將其大小控制在100 MB以下沪伙,但Alpine卻在沒有犧牲這些工具的前提下瓮顽,僅僅只有5MB。
Alpine Linux的另一個優(yōu)點(以我的觀點)是其軟件包管理器非澄穑快暖混。軟件包管理器的速度通常不是主要問題,因為在正常系統(tǒng)上翁授,我們只需要安裝一次即可拣播。我們并不是反復在安裝它們。但是收擦,使用容器時贮配,我們會定期構建鏡像,并且經(jīng)常使用基本鏡像啟動一個容器塞赂,并安裝一些軟件包來測試某些東西牧嫉,有時我們需要鏡像中沒有的額外工具。
只是因為感興趣减途,我決定下載一些流行的基本鏡像,并檢查在其中安裝tcpdump需要多長時間曹洽△⒅茫看一下結果:
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
使用docker images命令報告大小,并通過運行幾次以下命令來測量時間送淆。時間標準為eu-north-1下的t3.medium
time docker run <image> <packagemanager> install tcpdump
當我在歐洲時税产,我使用在斯德哥爾摩的服務器,因為瑞典的電力比其他任何地方都清潔偷崩,我是個環(huán)保主義者辟拷。不要相信關于eu-central-1“綠色” 的鬼話,法蘭克福的數(shù)據(jù)中心主要依靠煤炭運行阐斜。
屏幕截圖來自electricalmap.org衫冻,顯示此時此刻,德國40%的電力來自燃煤發(fā)電廠
好吧谒出,所以Alpine很小隅俘。我們?nèi)绾卧谧约旱膽贸绦蛑惺褂盟诘欤恐辽儆袃煞N策略值得考慮:
- 使用
alpine
作為我們的“運行”階段, - 使用
alpine
作為我們的“構建”和“運行”階段为居。
讓我們嘗試一下碌宴。
使用Alpine作為我們的“run”階段
讓我們構建以下Dockerfile,并運行結果鏡像:
FROM gcc AS mybuildstage
COPY hello.c .
RUN gcc -o hello hello.c
FROM alpine
COPY --from=mybuildstage hello .
CMD ["./hello"]
我們將收到以下錯誤消息:
standard_init_linux.go:211: exec user process caused "no such file or directory"
當我們嘗試在scratch
圖像中運行C程序時蒙畴,我們已經(jīng)看到了該錯誤消息贰镣。我們看到問題出在臨時鏡像中缺少動態(tài)庫∩拍看起來這些庫也從Alpine鏡像中丟失了嗎碑隆?
不完全是。Alpine使用動態(tài)庫鸠项。畢竟干跛,其設計目標之一是實現(xiàn)較小的空間占用。靜態(tài)二進制文件無濟于事祟绊。
Alpine使用不同的標準C庫楼入。它使用musl代替GNU C庫。(我個人將其發(fā)音為emm-you-ess-ell牧抽,但官方發(fā)音為“ mussel”或“ muscle”嘉熊。)該庫比GNU C庫更小,更簡單扬舒,更安全阐肤。動態(tài)鏈接到GNU C庫的程序不能與musl一起使用,反之亦然讲坎。
你可能會想孕惜,“如果musl更小,更簡單晨炕,更安全衫画,我們?yōu)槭裁床欢几挠盟兀俊?/p>
…因為GNU C庫具有許多擴展瓮栗,并且某些程序確實使用這些擴展削罩;有時甚至沒有意識到他們正在使用非標準擴展。musl文檔列出了與GNU C庫的功能差異费奸。
此外弥激,musl不是二進制兼容的。為GNU C庫編譯的二進制文件無法與musl一起使用(在某些非常簡單的情況下除外)愿阐,這意味著必須重新編譯代碼(有時會進行一些微調)才能與musl一起使用微服。
TL,DR:僅當程序是為musl(這是Alpine使用的C庫)構建的時换况,才將Alpine用作“運行”階段职辨。
話雖這么說盗蟆,構建Musl程序相對容易。我們要做的就是用Alpine本身構建它舒裤!
將Alpine用作“構建”和“運行”階段
我們決定生成一個與musl關聯(lián)的二進制文件喳资,以便它可以在Alpine基礎鏡像中運行。我們有兩種方式實現(xiàn)這點腾供。
- 一些官方鏡像提供的alpine標簽應盡可能接近普通鏡像仆邓,而不是改用Alpine(和musl)。
- 某些官方鏡像沒有alpine標簽伴鳖;對于這些节值,我們需要自己建立一個等效的鏡像,通常以Alpine為基礎榜聂。
golang鏡像屬于第一類:有一個golang:alpine鏡像提供了在Alpine上構建的Go工具鏈搞疗。
我們可以使用Dockerfile來構建我們的Go程序,如下所示:
FROM golang:alpine
COPY hello.go .
RUN go build hello.go
FROM alpine
COPY --from=0 /go/hello .
CMD ["./hello"]
生成的鏡像為7.5 MB须肆。對于只能打印“ Hello匿乃,world!”的程序來說的確很大豌汇,但是:
- 一個更復雜的程序不會更大
- 該鏡像包含許多有用的工具幢炸,
- 由于它基于Alpine,因此可以根據(jù)需要輕松快捷地在鏡像中添加更多工具拒贱。
現(xiàn)在宛徊,我們的C程序呢?當我寫這些時逻澳,沒有gcc:alpine鏡像闸天。因此,我們必須從Alpine開始斜做,然后安裝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),因為gcc在Alpine上的軟件包將安裝編譯器陨享,而不是我們需要的所有庫。相反钝腺,我們使用build-base抛姑,它等效于Debian或Ubuntu里的build-essentials,引入了編譯器艳狐,類庫以及諸如make之類的工具定硝。
關鍵總結:使用多階段構建時,我們可以使用alpine鏡像作為運行代碼的基礎毫目。如果我們的代碼是使用動態(tài)庫的編譯程序(這是我們可能在容器中使用的幾乎每種編譯語言都會遇到的情況)蔬啡,那么我們將需要生成一個與Alpine musl C庫鏈接的二進制文件诲侮。最簡單的方法是將我們的構建的鏡像基于另一個Alpine鏡像。為此箱蟆,許多官方鏡像都提供了標記:alpine沟绪。
對于我們的“ hello world”程序,這是最終結果空猜,將我們到目前為止展示的所有技術進行了比較绽慈。
使用golang映像的單階段構建:805 MB
使用golang和ubuntu的多階段構建:66.2 MB
使用Golang和Alpine進行多階段構建:7.6 MB
使用golang和scratch進行多階段構建:2 MB
大小減少了400倍,即99.75%辈毯。如果我們嘗試使用稍微更實際的程序坝疼,比如使用了net包,讓我們來看一下結果谆沃。使用golang映像的單階段構建:810 MB
使用golang和ubuntu的多階段構建:71.2 MB
使用golang:alpine和alpine的多階段構建:12.6 MB
使用golang和busybox的多階段構建:glibc:12.2 MB
使用golang钝凶,CGO_ENABLED = 0和scratch的多階段構建:7 MB
大小仍然縮小了100倍,也就是99%唁影。真香耕陷!
Java呢?
Java是一種編譯語言夭咬,但是它在Java虛擬機(或JVM)上運行啃炸。讓我們看看這對于多階段構建意味著什么。
靜態(tài)或動態(tài)鏈接卓舵?
從概念上講南用,Java使用動態(tài)鏈接,因為Java代碼將調用JVM提供的Java API掏湾。因此裹虫,這些API的代碼在Java“可執(zhí)行文件”(通常是JAR或WAR文件)之外。
但是融击,這些Java庫并不完全獨立于系統(tǒng)庫筑公。某些Java函數(shù)最終可能會調用系統(tǒng)庫。例如尊浪,當我們打開一個文件匣屡,在某些時候JVM會調用open()
,fopen()
或者它們的某種變體拇涤。您可以再次閱讀:JVM將調用這些函數(shù)捣作;因此JVM本身可能與系統(tǒng)庫動態(tài)鏈接。
這意味著從理論上講鹅士,我們可以使用任何JVM來運行Java程序券躁。使用musl還是GNU C庫都沒有關系。因此,我們可以使用具有Java編譯器的任何鏡像來構建Java代碼也拜,然后使用任何具有JVM的鏡像來運行它以舒。
Java類文件格式
但是,實際上慢哈,Java類文件的格式(由Java編譯器生成的字節(jié)碼)已經(jīng)隨著時間而發(fā)展蔓钟。從一個Java版本到下一個Java版本的大部分更改都位于Java API中。某些更改涉及語言本身岸军,例如Java 5中的泛型添加奋刽。這些更改可能導致Java .class
文件格式的更改,從而破壞了與舊版本的兼容性艰赞。
這意味著默認情況下佣谐,使用給定版本的Java編譯器編譯的類不適用于較早版本的JVM。但是我們可以要求編譯器使用帶有-target
標志(最多Java 8)或帶有--release
標志(來自Java 9)的較舊文件格式方妖。后者還將選擇正確的類路徑狭魂,以確保如果我們構建例如在Java 11上運行的代碼,我們不會意外使用Java 12的庫和API(這會阻止我們的代碼在Java 11上運行) 党觅。
(如果您想了解更多有關Java類文件版本的信息雌澄,可以閱讀此博客文章。)
JDK與JRE
如果你熟悉大多數(shù)平臺上Java打包的方式杯瞻,那么你可能已經(jīng)了解JDK和JRE镐牺。
JRE是Java運行時環(huán)境。它包含我們運行Java應用程序所需的內(nèi)容魁莉;即JVM睬涧。
JDK是Java開發(fā)工具包。它包含與JRE相同的東西旗唁,但是它還具有開發(fā)(和構建)Java應用程序所需的內(nèi)容畦浓。即Java編譯器。
在Docker生態(tài)系統(tǒng)中检疫,大多數(shù)Java鏡像都提供JDK讶请,因此它們適合構建和運行Java代碼。我們還將看到一些帶有:jre
標簽(或包含jre
某處的標簽)的鏡像屎媳。這些是僅包含JRE而沒有完整的JDK夺溢。它們較小。
對于多階段構建烛谊,這意味著什么企垦?
我們可以在構建階段使用常規(guī)鏡像,然后在運行階段使用較小的JRE鏡像晒来。
Java與OpenJDK
如果你在Docker中使用Java,你可能已經(jīng)知道了郑现。但你不應該使用Java官方鏡像湃崩,因為它們不再接收更新荧降。而應該使用openjdk
鏡像。
你也可以嘗試amazoncorretto
(Corretto是Amazon OpenJDK的分支攒读,帶有額外的補丁程序)朵诫。
關鍵總結
好了,那我們應該怎么用呢薄扁?如果你正在市場上購買小型Java鏡像剪返,那么這里有一些不錯的選擇:
-
openjdk:8-jre-alpine
(只有85 MB!) -
openjdk:11-jre
(267 MB)或openjdk:11-jre-slim(204 MB)(如果你需要更新的Java版本) -
openjdk:14-alpine
(338 MB)如果你需要更新的版本
不幸的是邓梅,并非所有組合都可用脱盲。比如openjdk:14-jre-alpine
不存在(這很可悲,因為它可能比-jre
和-alpine
變體腥沼А)钱反,但是可能有其他充分的理由。(如果你知道原因匣距,請告訴我面哥,我很想知道!)
請記住毅待,你應該構建代碼以匹配JRE版本尚卫。如果你需要詳細信息,這篇博客文章將說明如何在各種環(huán)境(IDE尸红,Maven等)中執(zhí)行此操作吱涉。
你想要一些數(shù)字嗎?我準備了一些給你驶乾!我用Java構建了一個簡單的“ hello world”程序:
class hello {
public static void main(String [] args) {
System.out.println("Hello, world!");
}
}
你可以在minimage GitHub repo中找到所有Dockerfile 邑飒,這是各種構建的大小。
- 使用
java
鏡像的單階段構建:643 MB - 使用
openjdk
鏡像的單階段構建:490 MB - 多級構建使用
openjdk
和openjdk:jre:
479 MB - 使用
amazoncorretto
鏡像的單階段構建:390 MB - 使用
openjdk:11
和openjdk:11-jre
的多階段構建:267 MB - 使用
openjdk:8
和openjdk:8-jre-alpine
的多階段構建:85 MB
那解釋型語言呢级乐?
如果你主要使用諸如Node疙咸,Python或Ruby之類的解釋語言編寫代碼,你可能會想知道是否應該擔心所有這些問題风科,以及是否有任何方法可以優(yōu)化圖像大小撒轮。事實證明,這兩個問題的答案都是肯定的贼穆!
Alpine與解釋性語言
我們可以使用alpine
或其他基于Alpine的鏡像來運行我們喜歡的腳本代碼题山。這僅適用于僅使用標準庫或“純”依賴項(即用相同語言編寫,而無需調用C代碼和外部庫的代碼)故痊。
現(xiàn)在顶瞳,如果我們的代碼依賴于外部庫,則事情會變得更加復雜。我們將不得不在Alpine上安裝這些庫慨菱。根據(jù)情況焰络,可能是:
- 簡單,當庫包含用于Alpine的安裝說明時符喝。它將告訴我們要安裝哪些Alpine軟件包以及如何建立依賴關系闪彼。但是,這相當罕見协饲,因為Alpine不如例如Debian或Fedora受歡迎畏腕。
- 一般,當庫沒有針對Alpine的安裝說明茉稠,但具有針對其他發(fā)行版的說明時描馅,你可以輕松地找出哪些Alpine軟件包與其他發(fā)行版的軟件包相對應。
- 很難战惊,當我們的依賴項使用沒有Alpine等效項的軟件包時流昏。然后我們可能必須從源頭構建,這將是一個完全不同的事情了吞获!
這最后一種情況正是Alpine可能沒有幫助况凉,甚至可能適得其反。如果我們需要從源代碼構建各拷,則意味著安裝編譯器刁绒,庫,頭……這將在最終映像上占用額外的空間烤黍。(是的知市,我們可以使用多階段構建;但是在特定的上下文中速蕊,取決于語言嫂丙,這可能很復雜,因為我們需要弄清楚如何為依賴項生成二進制包规哲。)從源代碼進行構建也將需要更長時間跟啤。
在某些情況下,使用Alpine會遇到所有這些問題:Python中的數(shù)據(jù)處理相關唉锌。諸如numpy或pandas之類的流行軟件包隅肥,稱為wheel,但這些wheel綁定到特定的C庫袄简。(“哦腥放,不!”你可能會想绿语,“又是那些庫秃症!”候址。)這意味著它們可以在“正常” Python鏡像上正常安裝种柑,而不能在Alpine變體上安裝宗雇。在Alpine上,他們將需要安裝系統(tǒng)軟件包莹规,在某些情況下,將需要很長時間的重建泌神。有一篇很好的文章專門針對這個問題良漱,解釋了使用Alpine如何使Python Docker的構建速度降低50倍。
如果你閱讀該文章欢际,你可能會想母市,“那,我應該為了python遠離Alpine嗎损趋?” 我不確定患久。對于數(shù)據(jù)相關,可能是的浑槽。但是對于其他工作蒋失,如果要減小鏡像大小,則值得一試桐玻。
:slim圖像
如果要在默認鏡像及其Alpine變體之間找一個折中方案篙挽,可以實時:slim
鏡像。slim鏡像通衬餮ィ基于Debian(以及GNU C庫)铣卡,但是它們通過刪除許多不必要的軟件包而針對大小進行了優(yōu)化。有時候偏竟,他們可能會滿足你的需求煮落。有時,它們?nèi)鄙俦匾膬?nèi)容(例如踊谋,編譯器2醭稹),安裝這些內(nèi)容會使你再次接近原始大型首印量淌;但是有機會嘗試使用它們也是不錯的。
為了讓你有所了解嫌褪,以下是一些流行的解釋語言的 :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
在特定的Python情況下笼痛,以下是在各種Python基本鏡像上安裝流行的軟件包matplotlib裙秋,numpy和pandas所獲得的大欣虐琛:
Image and technique Size
--------------------------------------
python 1.26 GB
python:slim 407 MB
python:alpine 523 MB
python:alpine multi-stage 517 MB
我們可以看到,使用Alpine根本無法幫助我們摘刑,即使是多階段構建也無法改善這種情況进宝。(你可以在minimage存儲庫中找到相關的Dockerfile;它們是名為的文件Dockerfile.pyds.*
枷恕。)
不過党晋,不要太快得出Alpine對Python不友好的結論!以下是使用大量依賴項的Django應用程序的大行炜椤:
Image and technique Size
--------------------------------------
python 1.23 GB
python:alpine 636 MB
python:alpine multi-stage 391 MB
(在這種情況下未玻,我放棄使用:slim
映像,因為它需要安裝太多額外的軟件包胡控。)
因此扳剿,我們可以看到,它并不總是很清晰的界限昼激。有時庇绽,:alpine
會產(chǎn)生更好的結果,有時:slim會做的更好橙困。如果確實需要優(yōu)化鏡像的大小瞧掺,則需要同時嘗試兩者并查看會發(fā)生什么。未來纷宇,我們將積累經(jīng)驗并了解哪種變體適用于哪些應用程序夸盟。
解釋型語言的多階段構建
那多階段構建呢?
對于任何種類的產(chǎn)出時像捶,它們都特別有用上陕。
例如,有一個Django應用程序(可能使用一些python
基本鏡像)拓春,但你使用UglifyJS縮小了Javascript释簿,并使用Sass縮小了CSS 。天真的方法是在鏡像中包含所有jazz硼莽,但Dockerfile會變得復雜(因為我們將在Python鏡像中安裝Node)庶溶,最終鏡像當然會很大。相反懂鸵,我們可以使用多個階段:一個階段node
用于最小化你的產(chǎn)出偏螺,第二個階段python
用于應用程序本身,從第一階段引入JS和CSS的產(chǎn)出結果匆光。
這也將導致更加友好的構建時間套像,因為Python代碼的更改并不總是會導致JS和CSS的重建(反之亦然)。在這種情況下终息,我甚至建議對JS和CSS使用兩個單獨的階段夺巩,以便更改一個階段不會觸發(fā)另一個階段的重建贞让。
那Rust呢?
Rust是一種最初由Mozilla設計的現(xiàn)代編程語言柳譬,并且在Web和基礎架構領域中越來越受歡迎喳张,我一直對折中情況感到非常好奇。所以我想知道就涉及到Docker鏡像而言應該期待什么樣的表現(xiàn)美澳。
事實證明销部,Rust生成與C庫動態(tài)鏈接的二進制文件。因此制跟,與內(nèi)置的二進制rust
鏡像將與平巢穸眨基本鏡像一樣運行比如,debian
凫岖,ubuntu
,fedora
等逢净,但busybox:glibc
不會工作哥放。這是因為二進制文件與libdl
鏈接,目前不包含在busybox:glibc
內(nèi)爹土。
但是甥雕,有一個rust:alpine
鏡像,并且生成的二進制文件以Alpine為基礎可以很好地工作胀茵。
我想知道Rust是否可以生成靜態(tài)二進制文件社露。這份Rust文檔解釋了如何做到這一點。在Linux上琼娘,這是通過構建Rust編譯器的特殊版本來完成的峭弟,并且需要musl
。是的脱拼,與Alpine中的musl
相同瞒瘸。如果要使用Rust獲得最小的鏡像,請按照文檔中的說明進行操作熄浓,然后將生成的二進制文件放入scratch
鏡像中情臭,這非常容易做到。
結論
在本系列的前兩部分中赌蔑,我們介紹了用于優(yōu)化Docker鏡像大小的最常用方法俯在,并且了解了它們?nèi)绾螒糜诟鞣N語言(編譯或解釋型)。
在最后一部分娃惯,我們將討論更多跷乐。我們將看到在特定基礎鏡像上進行標準化如何不僅可以減少鏡像大小,而且可以減少I / O和內(nèi)存使用量石景。我們將提到一些并非特定于容器的技術劈猿,但它們很有用的拙吉。