日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
五種方式:構(gòu)建小巧Docker容器的學(xué)問(wèn)

五種方式:構(gòu)建小巧docker容器的學(xué)問(wèn)

譯文
作者:核子可樂(lè)編譯 2018-07-30 09:00:19
云計(jì)算 幾年之前,Docker的爆炸式發(fā)展將容器與容器鏡像概念引入了大眾視野。盡管之前已經(jīng)存在Linux容器,但Docker憑借著用戶友好的命令行界面以及易于理解的Dockerfile格式顯著降低了鏡像的構(gòu)建門(mén)檻。在本文中,我們將共同了解五種優(yōu)化Linux容器大小并構(gòu)建小巧鏡像的方法。

目前創(chuàng)新互聯(lián)建站已為上千多家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、網(wǎng)站托管運(yùn)營(yíng)、企業(yè)網(wǎng)站設(shè)計(jì)、三江侗網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。

【51CTO.com快譯】在本文中,我們將共同了解五種優(yōu)化Linux容器大小并構(gòu)建小巧鏡像的方法。

幾年之前,Docker的爆炸式發(fā)展將容器與容器鏡像概念引入了大眾視野。盡管之前已經(jīng)存在Linux容器,但Docker憑借著用戶友好的命令行界面以及易于理解的Dockerfile格式顯著降低了鏡像的構(gòu)建門(mén)檻。但必須承認(rèn)的是,盡管上手難度已經(jīng)有所下降,其中仍存在著一些細(xì)微的差別與技巧,能夠幫助我們構(gòu)建功能強(qiáng)大但卻體積小巧的容器鏡像。

第一關(guān):清理內(nèi)容

下面列舉的部分示例采取與傳統(tǒng)服務(wù)器類(lèi)似的清理方式,只是具體要求更為嚴(yán)格。鏡像的體積對(duì)于快速移動(dòng)而言至關(guān)重要,而且在磁盤(pán)之上存儲(chǔ)多套不必要的數(shù)據(jù)副本無(wú)疑將浪費(fèi)大量資源。因此,我們有必要盡可能利用技術(shù)控制容器鏡像的“身材”。

下面來(lái)看如何從鏡像中刪除緩存文件,從而節(jié)約存儲(chǔ)空間。首先利用dnf以包含及不包含元數(shù)據(jù)的方式安裝Nginx,查看二者之間的鏡像大小區(qū)別; 而后利用yum進(jìn)行緩存清理:

  
 
 
  1. # Dockerfile with cache 
  2. FROM fedora:28 
  3. LABEL maintainer Chris Collins  
  4.  
  5. RUN dnf install -y nginx 
  6.  
  7. ----- 
  8.  
  9. # Dockerfile w/o cache 
  10. FROM fedora:28 
  11. LABEL maintainer Chris Collins  
  12.  
  13. RUN dnf install -y nginx \ 
  14.         && dnf clean all \ 
  15.         && rm -rf /var/cache/yum 
  16.  
  17. ----- 
  18.  
  19. [chris@krang] $ docker build -t cache -f Dockerfile .   
  20. [chris@krang] $ docker images --format "{{.Repository}}: {{.Size}}"  
  21. | head -n 1 
  22. cache: 464 MB 
  23.  
  24. [chris@krang] $ docker build -t no-cache -f Dockerfile-wo-cache . 
  25. [chris@krang] $ docker images --format "{{.Repository}}: {{.Size}}"  | head -n 1 
  26. no-cache: 271 MB 

可以看到,二者之間的體積存在顯著差異。包含dnf緩存的版本幾乎是不包含元數(shù)據(jù)及緩存的鏡像大小的兩倍。事實(shí)上,工具包管理器緩存、Ruby gem臨時(shí)文件、nodejs緩存、甚至是已下載的源代碼壓縮包都是清理工作的主要對(duì)象。

分層——一個(gè)潛在問(wèn)題

遺憾的是(或者可以說(shuō)幸運(yùn)的是,具體如后文所述),由于容器以分層方式使用,因此大家無(wú)法簡(jiǎn)單將RUN rm -rf /var/cache/yum 添加到Dockerfile當(dāng)中并就此作罷。Dockerfile中的每條指令都存儲(chǔ)在一個(gè)層中,各層之間的變更最終應(yīng)用于頂層。所以即使您進(jìn)行如下操作:

  
 
 
  1. RUN dnf install -y nginx 
  2. RUN dnf clean all 
  3. RUN rm -rf /var/cache/yum 

……最終仍會(huì)得到三層,其中一層包含所有緩存,兩個(gè)中間層則從鏡像中“移除”緩存。然而,緩存仍然實(shí)際存在,正如當(dāng)您將某一文件系統(tǒng)安裝在另一文件系統(tǒng)之上時(shí),文件就在這里——只是我們無(wú)法查看或者訪問(wèn)。

需要注意的是,上一節(jié)中的示例將緩存清理鏈接到了生存緩存的同一Dockerfile指令當(dāng)中:

  
 
 
  1. RUN dnf install -y nginx \ 
  2.         && dnf clean all \ 
  3.         && rm -rf /var/cache/yum 

這是一條單獨(dú)指令,最終會(huì)成為鏡像中的一層。通過(guò)這種方式,您會(huì)丟棄一部分Docker緩存——這意味著鏡像重構(gòu)時(shí)間會(huì)稍長(zhǎng),但緩存數(shù)據(jù)仍將出現(xiàn)在最終鏡像當(dāng)中。作為一種良好的折衷方案,我們只需鏈接相關(guān)命令(例如hum install與hum clean all,或者下載、釋放及移除源tarball等)即可幫助最終鏡像顯著瘦身,同時(shí)繼續(xù)利用Docker緩存加快開(kāi)發(fā)速度。

然而,這里的層將比前文中提到的更加微妙。因?yàn)殓R像各層記錄了每個(gè)層的具體變化——因此除了添加的文件之外,一切文件修改都將被納入其中。例如,即使更改了文件模式,鏡像中也會(huì)有新層出現(xiàn)以創(chuàng)建該文件的副本。

舉例來(lái)說(shuō),以下docker images輸出結(jié)果顯示出與兩套鏡像相關(guān)的信息。第一套layer_test_1通過(guò)將單一1 GB文件添加至基礎(chǔ)CentOS鏡像的方式得出。第二套鏡像layer_test_2則直接由layer_test_1創(chuàng)建而來(lái),只是利用chmod u+x命令變更了該1 GB文件的模式。

  
 
 
  1. layer_test_2        latest       e11b5e58e2fc           7 seconds ago           2.35 GB 
  2. layer_test_1        latest       6eca792a4ebe           2 minutes ago           1.27 GB 

如大家所見(jiàn),新的鏡像較前一套鏡像大出1 GB有余。盡管layer_test_1 實(shí)際上只代表著layer_test_2的前兩層,但第二套鏡像中仍然隱藏著另一個(gè)1 GB的文件。在鏡像構(gòu)建過(guò)程當(dāng)中,一切與文件相關(guān)的刪除、移除或更改都會(huì)造成這樣的結(jié)果。

專(zhuān)用鏡像與靈活鏡像

一則軼事:當(dāng)初我們大量采用Ruby on Rails應(yīng)用程序時(shí),同事們開(kāi)始慢慢接受容器這種新鮮事物。我們的第一項(xiàng)工作就是為所有團(tuán)隊(duì)創(chuàng)建一套官方的Ruby基礎(chǔ)鏡像。為了簡(jiǎn)單起見(jiàn),我們利用rebenv將四套最新的Ruby版本安裝到了鏡像當(dāng)中,從而允許我們的開(kāi)發(fā)人員能夠利用單一版本將所有應(yīng)用程序遷移到容器鏡像當(dāng)中。這實(shí)際上帶來(lái)了一套非常龐大但卻比較靈活(至少我們認(rèn)為)的鏡像,其中涵蓋我們各合作團(tuán)隊(duì)間的一切工作基礎(chǔ)。

但事實(shí)證明,這一切都是在浪費(fèi)時(shí)間。維護(hù)特定鏡像的單一修改版本能夠比較輕松地實(shí)現(xiàn)自動(dòng)化,這是因?yàn)闉樘囟ㄧR像選擇特定版本實(shí)際上有助于在引入突破性變更之前意識(shí)到原有應(yīng)用程序已經(jīng)不合適接下來(lái)的需求,從而避免由此發(fā)生嚴(yán)重破壞。此外,過(guò)大的鏡像也造成了資源浪費(fèi):當(dāng)我們對(duì)不同Ruby版本進(jìn)行拆分時(shí),我們最終得到了多套共享同一基礎(chǔ)的鏡像。如果將其同時(shí)保存在服務(wù)器之上,相較于包含多個(gè)版本的巨型鏡像,其占用的額外空間其實(shí)并不大,但傳輸速度卻要快得多。

這并不是說(shuō)構(gòu)建靈活性鏡像沒(méi)有意義。只是在我們的情況下,創(chuàng)建專(zhuān)用型鏡像最終節(jié)約了存儲(chǔ)空間與維護(hù)時(shí)間,同時(shí)也確保各團(tuán)隊(duì)在享受好處的同時(shí)能夠?qū)灿谢A(chǔ)鏡像做出必要的修改。

從頭開(kāi)始:將需要的內(nèi)容添加至空白鏡像中

與Dockerfile的用戶友好與易用性類(lèi)似,還有其他一些工具能夠以極為靈活的方式創(chuàng)建小巧的Docker兼容容器鏡像且無(wú)需完整的操作系統(tǒng)——其小巧程度甚至堪比標(biāo)準(zhǔn)Docker基礎(chǔ)鏡像。

我在之前曾經(jīng)寫(xiě)過(guò)關(guān)于Buildah的文章,這里我也會(huì)再次提及,因?yàn)槠湎喈?dāng)靈活且可利用主機(jī)中的工具從零開(kāi)始創(chuàng)建鏡像,同時(shí)安裝打包軟件并修改鏡像內(nèi)容。更重要的是,這些工具將永遠(yuǎn)存在于鏡像之外,因此不會(huì)增加鏡像本身的體積。

Buildah取代了docker build命令。有了它,您可以將容器鏡像的文件系統(tǒng)掛載至主機(jī)上,并利用主機(jī)中的工具與其進(jìn)行交互。

讓我們嘗試?yán)蒙厦娴腘ginx示例看看Biuldah的效果(這里暫時(shí)不管緩存):

  
 
 
  1. #!/usr/bin/env bash 
  2. set -o errexit 
  3.  
  4. # 創(chuàng)建一個(gè)容器 
  5. container=$(buildah from scratch) 
  6.  
  7. # 掛載容器文件系統(tǒng) 
  8. mountpoint=$(buildah mount $container) 
  9.  
  10. # 安裝一個(gè)基礎(chǔ)文件系統(tǒng)與最低軟件包集,以及nginx 
  11. dnf install --installroot $mountpoint  --releasever 28 glibc-minimal-langpack nginx --setopt install_weak_deps=false -y 
  12.  
  13. # 將容器保存為鏡像 
  14. buildah commit --format docker $container nginx 
  15.  
  16. # 清理 
  17. buildah unmount $container 
  18.  
  19. # 將鏡像推著至Docker守護(hù)程序進(jìn)行存儲(chǔ) 
  20. buildah push nginx:latest docker-daemon:nginx:latest 

大家可能已經(jīng)注意到,這里我們不再使用Dockerfile構(gòu)建鏡像,而是使用簡(jiǎn)單的Bash腳本。我們利用一套從零創(chuàng)建(或空白)鏡像進(jìn)行構(gòu)建。該Bash腳本會(huì)將容器的root文件系統(tǒng)掛載至主機(jī)上的某個(gè)掛載點(diǎn),而后利用主機(jī)命令安裝各軟件包。通過(guò)這種方式,軟件包管理器甚至無(wú)需超出容器自身范圍。

如果沒(méi)有額外的部分——例如dnf等基礎(chǔ)鏡像中的額外內(nèi)容——那么鏡像本身的大小僅為304 MB,這一體積要比之前利用Dockerfile構(gòu)建的Nginx鏡像小上100多MB。

  
 
 
  1. [chris@krang] $ docker images |grep nginx 
  2. docker.io/nginx      buildah      2505d3597457    4 minutes ago         304 MB 

注意:鏡像名稱中之所以包含docker.io部分,是因?yàn)槠浔煌扑椭罝ocker守護(hù)程序的命名空間,但其仍然是利用以上構(gòu)建腳本以本地方式構(gòu)建的鏡像。

考慮到基礎(chǔ)鏡像本身只有300 MB左右,100 MB的節(jié)約幅度顯然相當(dāng)驚人。利用軟件管理器安裝Nginx,也會(huì)帶來(lái)大量的依賴關(guān)系。如果使用由主機(jī)提供的工具進(jìn)行源代碼編譯的處理方式,由于您可以選擇確切的依賴關(guān)系而非引入任何不必要的額外文件,大家將能夠進(jìn)一步節(jié)約存儲(chǔ)空間。

利用Buildah構(gòu)建鏡像能夠有效擺脫完整操作系統(tǒng)以及構(gòu)建工具,從而進(jìn)一步壓縮您的鏡像體積。而對(duì)于某些特定類(lèi)型的鏡像,我們還可以采取同樣的方法創(chuàng)建出僅包含應(yīng)用程序本身的鏡像。

僅使用靜態(tài)鏈接的二進(jìn)制文件創(chuàng)建鏡像

遵循相同的理念,我們可以進(jìn)一步將管理與構(gòu)建工具從鏡像中清理出去。如果我們擁有必要的專(zhuān)業(yè)知識(shí),且不再需要立足容器內(nèi)部進(jìn)行故障排查,那么我們是否可以棄用Bash?我們還需要GNU核心程序嗎?我們還需要基礎(chǔ)的Linux文件系統(tǒng)嗎?大家可以使用任何編譯語(yǔ)言執(zhí)行此項(xiàng)操作,即利用靜態(tài)鏈接庫(kù)創(chuàng)建二進(jìn)制文件——程序運(yùn)行所需要的一切庫(kù)及函數(shù)都將被復(fù)制并存儲(chǔ)在二進(jìn)制文件當(dāng)中。

這是一種在Golang社區(qū)中擁有一定人氣的處理方式,因此我們這里使用Go應(yīng)用程序進(jìn)行演示。以下是Dockerfile采用一個(gè)小巧的Go Hello-World應(yīng)用程序,并將其編譯在一套FROM golang:1.8鏡像當(dāng)中:

  
 
 
  1. FROM golang:1.8 
  2.  
  3. ENV GOOS=linux 
  4. ENV appdir=/go/src/gohelloworld 
  5.  
  6. COPY ./ /go/src/goHelloWorld 
  7. WORKDIR /go/src/goHelloWorld 
  8.  
  9. RUN go get 
  10. RUN go build -o /goHelloWorld -a 
  11.  
  12. CMD ["/goHelloWorld"] 

最終得到的鏡像包含二進(jìn)制文件、源代碼以及基礎(chǔ)鏡像層,總體積為716 MB。但是,我們的應(yīng)用程序最終真正需要的只有編譯后的二進(jìn)制文件,其他所有內(nèi)容都是多余的。

如果我們?cè)诮y(tǒng)計(jì)時(shí)利用CGO_ENABLED=0禁用cgo,則可創(chuàng)建出一套不打包C庫(kù)的二進(jìn)制文件:

  
 
 
  1. GOOS=linux CGO_ENABLED=0 go build -a goHelloWorld.go 

生成的二進(jìn)制文件可被添加至空的,或者“從頭構(gòu)建”鏡像當(dāng)中:

  
 
 
  1. FROM scratch 
  2. COPY goHelloWorld / 
  3. CMD ["/goHelloWorld"] 

下面,我們來(lái)比較兩套鏡像之間的體積差異:

  
 
 
  1. [ chris@krang ] $ docker images 
  2. REPOSITORY      TAG             IMAGE ID                CREATED                 SIZE 
  3. goHello     scratch     a5881650d6e9            13 seconds ago          1.55 MB 
  4. goHello     builder     980290a100db            14 seconds ago          716 MB 

可以看到,差別非常巨大。由golang:1.8構(gòu)建出的鏡像中包含goHelloWorld庫(kù)(標(biāo)記為‘builder’),其體積達(dá)到純二進(jìn)制文件鏡像的460倍。而純二進(jìn)制文件鏡像的體積僅為1.55 MB。這意味著如果我們使用由builder構(gòu)建的鏡像,其中將有約713 MB的數(shù)據(jù)根本不必存在。

如果適合,不妨考慮壓縮方法

還有一種方法可以通過(guò)將所有命令鏈接至層內(nèi)以節(jié)約空間,就是鏡像壓縮(squash)。在進(jìn)行鏡像壓縮時(shí),您實(shí)際上是在導(dǎo)出鏡像,刪除所有中間層,并將鏡像的當(dāng)前狀態(tài)保存為單一層。這將有效控制鏡像的實(shí)際體積。

過(guò)去,我們需要利用一些創(chuàng)造性的解決方案才能將經(jīng)過(guò)壓縮的層進(jìn)行還原——例如導(dǎo)出容器內(nèi)容并將其重新導(dǎo)入為單層鏡像,或者利用docker-squash等工具。但從1.13版本開(kāi)始,Docker引入了一種便利的標(biāo)記——squash,其能夠在構(gòu)建過(guò)程中完成同樣的操作:

  
 
 
  1. FROM fedora:28 
  2. LABEL maintainer Chris Collins  
  3.  
  4. RUN dnf install -y nginx 
  5. RUN dnf clean all 
  6. RUN rm -rf /var/cache/yum 
  7.  
  8. [chris@krang] $ docker build -t squash -f Dockerfile-squash --squash . 
  9. [chris@krang] $ docker images --format "{{.Repository}}: {{.Size}}"  | head -n 1 
  10. squash: 271 MB 

利用docker squash處理這個(gè)多層Dockerfile,我們最終得到了一個(gè)大小為271 MB的鏡像,且功能與之前的鏈接指令鏡像一樣。但這,又帶來(lái)了新的潛在問(wèn)題。

太過(guò)極端:過(guò)度壓縮、過(guò)度“瘦身”、過(guò)度專(zhuān)用

鏡像之間可以進(jìn)行層共享。其基礎(chǔ)可能為x MB,但只需要拉取/存儲(chǔ)一次,其他鏡像就能夠加以使用。進(jìn)行層共享的各鏡像的實(shí)際大小,為基礎(chǔ)層加上特定變化帶來(lái)的差異。通過(guò)這種方式,我們能夠以極低的額外空間投入,換取數(shù)千套基于同一鏡像的修改版鏡像。

而這也正是鏡像壓縮或者專(zhuān)用化方法帶來(lái)的弊端。在將鏡像壓縮為單層形式時(shí),我們將徹底失去其與其他鏡像進(jìn)行層共享的機(jī)會(huì)。每套鏡像最終都將與其單一層的體積保持一致。因此,如果大家只需要使用少量鏡像并在其中運(yùn)行大量容器,那么過(guò)度壓縮還沒(méi)什么問(wèn)題; 但如果您面對(duì)著多種不同鏡像,那么從長(zhǎng)遠(yuǎn)角度來(lái)看,這最終反而會(huì)消耗您的存儲(chǔ)空間。

讓我們重新審視Nginx壓縮示例,可以看到在這種情況下,“瘦身”過(guò)程并不會(huì)帶來(lái)什么問(wèn)題。我們最終安裝了Fedora與Nginx,清理了緩存,并進(jìn)行了有效壓縮。不過(guò),Nginx本身并沒(méi)有多大作用,大家通常需要以自定義方式執(zhí)行各類(lèi)針對(duì)性操作——例如配置文件、其他軟件包甚至是某些應(yīng)用代碼。而其中每一項(xiàng)操作都會(huì)在Dockerfile中添加更多指令。

如果以傳統(tǒng)方式進(jìn)行鏡像構(gòu)建,那么您將在鏡像中擁有一個(gè)承載Fedora的獨(dú)立基礎(chǔ)鏡像層,一個(gè)安裝有Nginx的層(包含或不包含緩存),而后每項(xiàng)自定義又有自己的層。包含F(xiàn)edora與Nginx等的其他鏡像將能夠共享這些層。

在這種情況下,需要的鏡像為:

  
 
 
  1. [   App 1 Layer (  5 MB) ]          [   App 2 Layer (6 MB) ] 
  2. [   Nginx Layer ( 21 MB) ] ------------------^ 
  3. [ Fedora  Layer (249 MB) ]   

但如果大家對(duì)該鏡像進(jìn)行壓縮,那么Fedora基礎(chǔ)層也會(huì)被壓縮。基于Fedora的被壓縮鏡像需要釋放相關(guān)Fedora內(nèi)容,這意味著每套鏡像將新增249 MB!

  
 
 
  1. [ Fedora + Nginx + App 1 (275 MB)] [ Fedora + Nginx + App 2 (276 MB) ] 

如果大家構(gòu)建出大量高度專(zhuān)用且超級(jí)小巧的鏡像,那么這絕對(duì)會(huì)帶來(lái)大麻煩。

因?yàn)榕c生活中的其他事務(wù)一樣,適度才是鏡像體積控制的關(guān)鍵所在。而且考慮到鏡像層的工作原理,隨著容器鏡像的壓縮度與專(zhuān)用性逐漸提高,其將無(wú)法與其他相關(guān)鏡像共享基礎(chǔ)鏡像層,而壓縮帶來(lái)的瘦身效果也將因此遞減甚至消失。

經(jīng)過(guò)一定程度自定義的鏡像可以共享基礎(chǔ)層。如前文所述,這一基礎(chǔ)層可以是x MB,但只需要進(jìn)行一次拉取/存儲(chǔ),所有鏡像就都能夠?qū)ζ浼右允褂?。所有鏡像的有效大小為基礎(chǔ)層加上每種特定變化造成的差異。通過(guò)這種方式,我們能夠以極低的額外空間投入,換取數(shù)千套基于同一鏡像的修改版鏡像。

  
 
 
  1. [ specific app   ]      [ specific app 2 ] 
  2. [ customizations ]--------------^ 
  3. [ base layer     ] 

但如果您的鏡像壓縮得太狠或者存在太多修改或?qū)S谜{(diào)整,那么我們將不得不面對(duì)大量鏡像。由于這些鏡像之間沒(méi)有同一套共享基礎(chǔ)層,因此其將各自占用磁盤(pán)上的存儲(chǔ)空間。

  
 
 
  1. [ specific app 1 ] [ specific app 2 ] [ specific app 3 ] 

總結(jié)

我們擁有多種能夠有效減少容器鏡像所需存儲(chǔ)空間與傳輸帶寬的處理方法,但其中最有效的方法無(wú)疑是降低鏡像本身的體積。無(wú)論您選擇單純清理其中的緩存(避免將其保留在中間層內(nèi))、將全部層壓縮為單一層,或者只是在空鏡像中添加靜態(tài)二進(jìn)制文件,大家都有必要花些時(shí)間研究鏡像中可能存在的不必要內(nèi)容,并將其縮小至合理的水平。


網(wǎng)站欄目:五種方式:構(gòu)建小巧Docker容器的學(xué)問(wèn)
分享路徑:http://m.5511xx.com/article/dpopihi.html