微容器:更小的,更輕便的Docker容器

ttyr0957 8年前發布 | 24K 次閱讀 Docker

來自: http://dockone.io/article/1035



【編者的話】本文介紹了微容器的概念和好處,并用一些例子介紹了如何構建微鏡像,從scratch到Alpine Linux,并推薦了一些已有的基礎微鏡像,方便為幾乎所有主流語言的應用構建微鏡像。本文也指出了構建微鏡像的基本原理:將構建時依賴和運行時依賴分開,構建時所用的鏡像包含所有構建所用的工具,它可以比較大,但運行時的基礎鏡像應該僅包含運行時依賴。使用微容器,no going back!
microwhale-vs-bigwhale.png

Docker 使你能把你的應用和應用的依賴打包到一個良好的自包含鏡像中。然后你可以用該那個鏡像來在容器中運行你的應用。問題是,你通常也打包了一些你可能不需要比你需要的更多的東西,最終座椅最重你得到了一個巨大的鏡像和巨大的容器。大多數開始使用Docker的人會使用Docker的官方倉庫作為他們的語言的選擇,但是不幸的是,如果你使用官方鏡像,你會得到一個巨大的鏡像,而本來你可以得到一個小鏡像的。你并不需要和這些官方鏡像中一起的許多復雜的東西。例如,如果你使用官方的Node鏡像構建一個你的應用的Node的鏡像,它至少有643MB大,因為這是官方Node鏡像的大小

我構建了一個簡單的Hello World Node 應用,在官方Node鏡像上構建,它的大小是644MB。
tnf.jpg

這太大了!我的應用加上依賴也不超過1MB,Node.js的運行時大概20MB,那是什么占據了剩下的620MB?我們應該能做得更好。

什么是微容器?

一個微容器僅包含OS庫和運行應用所需要的語言依賴以及應用本身。其他都不需要。

與其包含所有,不如僅包含最基本的,在需要的時候添加依賴。

以上面的Node應用為例,使用一個小的基礎鏡像,然后安裝核心的部分,即Node.js和它的依賴,它只有29MB,小了22倍(見下圖)!
tnl.jpg

pasted_image_at_2016_01_22_11_20_am.png

如果你想,現在試試運行這兩個鏡像,docker run –rm -p 8080:8080 treeder/tiny-node:fat 然后 docker run –rm -p 8080:8080 treeder/tiny-node:latest。完全一樣的應用,而大小大不相同。

為什么微容器很棒?

有許多使用微容器的好處:
  • 大小 —— 微容器很小。像上面展示的,沒有改變任何代碼,鏡像大小減少了22倍。
  • 快速/簡單的發布 —— 因為鏡像非常小,可以更快地從 Docker registry(例如 Docker Hub)下載鏡像,因而可以更快地發布到不同的機器。
  • 提高安全性 —— 更少的代碼和程序在容器中意味著更小的攻擊面。基礎OS就更安全(詳見下文)。


這些好處和Unikernels的好處類似,沒有任何缺點。

如何構建微容器

所有Docker鏡像的基礎鏡像是scratch鏡像。它本質上什么都沒有。聽起來它好像沒什么無用,但是你可以用它創建你的應用的最小可能鏡像,如果你把你的應用編譯為一個沒有依賴的靜態二進制文件,像Go或C那樣。例如,我的treeder/static-go 鏡像 包含了一個Go的Web應用,則整個鏡像(包括我的應用)是5MB。
sgl.jpg

這是關于如何得到盡可能小的鏡像:scratch鏡像+你的應用的二進制文件。

然而并不是所有人都是用Go,所以你可能有更多的依賴,并且你需要比scratch鏡像要多一些的東西。關于Alpine Linux,我不會枯燥地告訴你關于它的細節,但是他們的廣告語說出了全部:“Alpine Linux是一個面向安全的,輕量的Linux發行版,基于musl libc和busybox。” 你可以在這里得到詳細說明,但是我們這篇文章最關心的是“輕量”的部分。基礎的Alpine鏡像只有5MB。
apl.jpg

現在我們有一個非常好的OS作為一個基礎鏡像,它有一個很好的包管理系統來添加我們的依賴。對于我們的簡單的Node應用而言,我們只需要Node自己,所以我們可以只添加Node包。我們的Dockerfile看起來像這樣:
FROM alpine
RUN apk update && apk upgrade
RUN apk add nodejs

簡單而整潔。現在我們只在鏡像中有Node和Node的依賴。
現在為了添加我們的代碼到鏡像中,只需要在我們的Dockerfile中添加幾行:
FROM alpine
RUN apk update && apk upgrade
RUN apk add nodejs
WORKDIR /app
ADD . /app
ENTRYPOINT [ "node", "server.js" ]

你可以獲得示例代碼并且在這里查看完整的構建指導。

同樣的規則適用于所有其他的語言。

適用于所有語言的基礎鏡像

幸運的是,我們已經構建了一個適用所有主要語言的基礎鏡像,你可以在這里找到它們: https://github.com/iron-io/dockers

它們有一些優化來使它們盡可能的小,并且我們會定期更新,使用基礎鏡像使得它們比起你自己來更好。通過使用Iron.io的基礎鏡像,上面Node應用的Dockerfile變成這樣:
FROM iron/node
WORKDIR /app
ADD . /app
ENTRYPOINT [ "node", "server.js" ]

另外,對于每一種其他語言,我們構建了兩個版本的這種鏡像,一個用于構建,另一個用于運行。用于構建的鏡像有所有的構建工具在其中,所以可能比運行時要更大。

例如,為了構建Node的依賴,你要像這樣使用iron/node:dev
docker run --rm -v "$PWD":/app -w /app iron/node:dev npm install

然后在你的Dockerfile中使用iron/node然后運行它:
docker run --rm -it -p 8080:8080 -v "$PWD":/app -w /app iron/node node server.js

上述方法同樣適用于其他語言,但是你需要使用它們自己的build/vendor/run的指令。

如果你想要一個語言的不同版本,你可以改變tag,例如你可以使用iron/node:4.1或者iron/node:0.12。你可以在Docker Hub上找到每個語言的所有的版本tag。例如Node的tag在這里: https://hub.docker.com/r/iron/node/tags/。你可以在iron-io/dockers的項目里找到所有其他Docker Hub tags的鏈接。

如何為所有的語言構建和打包

這可能沒那么幸運了,但是我們有一些例子可以讓大多數主流語言使用上面的基礎鏡像: https://github.com/iron-io/dockerworker

你可以看看那個項目中的每個語言的README,它會指引你如何構建你的依賴,測試你的代碼,構建一個小的Docker鏡像和測試鏡像。

沒有回頭

讀完本文之后,你應該可以為你的應用創建只包含運行應用所需要的東西的Docker鏡像。容器本質是一個鏡像的實例,所以一旦你開始用你的鏡像來運行容器,你就進入了微容器的世界。沒有(理由)回頭。


剛使用了你的“小鏡像”技術在我的一個golang項目上,很棒!感謝這篇偉大的文章。竟然令人震驚地減小到5mb。 —— Harlow Ward @ Clearbit
原文鏈接:Microcontainers – Tiny, Portable Docker Containers (翻譯:陳光 審校:高婧雅)

 本文由用戶 ttyr0957 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!