微容器——小的,輕便的Docker容器
【編者的話】本文介紹了微容器的概念和好處,并用一些例子介紹了如何構建微鏡像,從scratch到Alpine Linux,并推薦了一些已有的基礎微鏡像,方便為幾乎所有主流語言的應用構建微鏡像。構建微鏡像的基本原理本文也指出了:將構建時依賴和運行時依賴分開,構建時所用的鏡像包含所有構建所用的工具,它可以比較大,但運行時的基礎鏡像應該僅包含運行時依賴。使用微容器, no going back!
Docker 使你能把你的應用和應用的依賴打包到一個良好的自包含鏡像中。然后你可以用那個鏡像來在容器中運行你的應用。問題是你通常打包了比你需要的更多的東西,座椅最重你得到了一個巨大的鏡像和巨大的容器。大多數開始使用Docker的人會使用Docker的 官方倉庫 作為他們的語言的選擇,但是不幸的是,如果你使用它們,你會得到一個巨大的鏡像,而奔來你可以得到一個小鏡像的。你并不需要和這些鏡像一起的許多復雜的東西。如果你使用 官方的Node鏡像 構建一個你的應用的Node的鏡像,它至少有643MB大,因為這是 官方Node鏡像的大小 。
我構建了一個簡單的 Hello World Node 應用 ,在官方Node鏡像上構建,它的大小是644MB.
這很巨大!我的應用加上依賴也不超過1MB,Node.js的運行時大概20MB,什么占據了其他的620MB?我們必須能做的更好。
什么是微容器?
一個微容器僅包含OS庫和運行應用所需要的語言依賴以及應用本身。不需要更多的。
與其從所有都包含的開始,不如從僅包含最小的開始,然后在需要的時候添加依賴。
以上面的Node應用為例,使用一個小的基礎鏡像,然后安裝核心的部分,即Node.js和它的依賴,它只有29MB,小了22倍!
如果你想,現在試試運行這兩個鏡像, 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。
這是關于如何得到盡可能小的鏡像:scratch鏡像+你的應用的二進制文件。
并不是所有人都是用Go(不幸地)所以你可能有更多的依賴并且你需要比scratch鏡像要多一些的東西。關于 Alpine Linux ,我不會枯燥的告訴你關于它的細節,但是他們的廣告語說出了全部:“Alpine Linux是一個面向安全的,輕量的Linux發行版,基于musl libc和busybox。” 你可以在 這里 得到詳細說明,但是我們這篇文章最關心的是“輕量”的部分。基礎的Alpine鏡像只有5MB。
現在我們有一個非常好的OS最為一個基礎鏡像,它有一個 很好的包管理系統 來添加我們的依賴。對于我們的簡單的Node應用,我們只需要Node自己,所以我們可以只添加Node包。我們的Dockerfile看起來像這樣:
FROM alpineRUN apk update && apk upgrade
RUN apk add nodejs</pre>
簡單而整潔。現在我們只在鏡像中有Node和Node的依賴。
現在為了添加我們的代碼到鏡像中,只需要在我們的Dockerfile中添加幾行:
FROM alpineRUN apk update && apk upgrade
RUN apk add nodejs
WORKDIR /app
ADD . /app
ENTRYPOINT [ "node", "server.js" ]</pre>
你可以獲得示例代碼并且在 這里 查看完整的構建指導。
同樣的規則適用于所有其他的語言。
適用于所有語言的基礎鏡像
幸運的是,我們已經構建了一個適用所有主要語言的基礎鏡像,你可以在這里找到它們: https://github.com/iron-io/dockers
它們有一些優化來使它們盡可能的小,并且我們會定期更新,使得它們比起你自己來做是一個更加好的選擇。適用Iron.io的基礎鏡像,上面Node應用的Dockerfile變成這樣:
FROM iron/nodeWORKDIR /app
ADD . /app
ENTRYPOINT [ "node", "server.js" ]</pre>
另外,對于每一個其他語言,我們構建了兩個版本的這種鏡像,一個用于構建,另一個用于運行。用于構建的鏡像有所有的構建工具在其中,所以可能比運行時要更大。
例如,為了構建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 (翻譯:陳光)
來自: http://dockone.io/article/1035