
Docker 的口號是 Build, Ship, and Run Any App, Anywhere.
但是我們在應(yīng)用過程中會遇到一個問題可训,我們在 build 的時候淘菩,把源碼也 build 進(jìn)去了呢袱。
然后就繼續(xù)把源碼 Ship 出去嗎?這可不行苇瓣。所有的編譯型語言都面臨這個困擾区匠。
即使是腳本型語言喧务,build 的時候也會使用很多上線時用不到的構(gòu)建工具仰税,
而我們希望減小生產(chǎn)鏡像的體積聚凹,這樣我們的小鯨魚才能多拉一點集裝箱嘛割坠。
傳統(tǒng)做法
我們最終的目的是要將編譯好的可執(zhí)行文件復(fù)制到 alpine
這樣的迷你鏡像里,
那么該怎么弄到編譯好的文件呢妒牙?基于 Docker 的思想彼哼,我們肯定需要在一個標(biāo)準(zhǔn)容器中編譯,
這樣這個過程才是標(biāo)準(zhǔn)化的湘今,再說敢朱,你在 Ubuntu 編譯出一個二進(jìn)制文件在 alpine 也運行不了。
于是我們先需要準(zhǔn)備一個編譯用的自定義鏡像摩瞎。一般是用相應(yīng)語言的 alpine 基礎(chǔ)鏡像拴签,
把編譯項目額外需要的各種工具打包進(jìn)去,比如 golang 目前沒有官方的包管理旗们,
你就需要把你用的包管理工具裝進(jìn)去蚓哩。
然后我們需要在運行 container 時把主機(jī)的一個目錄通過 -v 掛載到 container上,
讓它把編譯的結(jié)果輸出到這個掛載的目錄上渴,這樣我們就在主機(jī)上拿到這個文件了岸梨。
最后,我們用一個最小的 alpine
鏡像稠氮,把二進(jìn)制文件復(fù)制進(jìn)去曹阔。
可能你還需要設(shè)置一下時區(qū)之類的。
持續(xù)集成
上面的流程隔披,在用持續(xù)集成工具時又變成了一個問題赃份。你會發(fā)現(xiàn)每一家 CI 提供商都不太一樣。
你未必有權(quán)限控制 CI 時的宿主機(jī)奢米。
比如 Docker Cloud
芥炭,你需要定義 pre-build 的 hook 去完成這個工作,
在 SEMAPHORE
恃慧,你發(fā)現(xiàn)你有了一臺宿主機(jī),這下和我們在本地的做法可以一樣了渺蒿。
在更多的提供商痢士,你會發(fā)現(xiàn)他們只是能根據(jù) git 倉庫和 Dockerfile 構(gòu)建鏡像,
你用他們的系統(tǒng)甚至沒辦法做出一個最小鏡像……
中國的 DaoCloud
其實挺先進(jìn)的,很早就推出了安全鏡像的概念怠蹂,讓你的構(gòu)建通過兩步完成善延。
但是,那個配置的內(nèi)容太多讓不太懂的人看了直接暈掉城侧。
官方方案
在2017年5月3日即將發(fā)行的 Docker 17.05.0-ce
中易遣,Docker 官方提供了簡便的多階段構(gòu)建
(multi-stage build) 方案。我用例子為大家介紹下:
FROM muninn/glide:alpine AS build-env
ADD . /go/src/app
WORKDIR /go/src/app
RUN glide install
RUN go build -v -o /go/src/app/app-server
FROM alpine
RUN apk add -U tzdata
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY --from=build-env /go/src/app/app-server /usr/local/bin/app-server
EXPOSE 80
CMD ["app-server"]
首先嫌佑,第一個 FROM
后邊多了個 AS
關(guān)鍵字豆茫,可以給這個階段起個名字。
我舉例子這個鏡像是官方
golang:alpine 加上構(gòu)建工具 glide 屋摇,我們照舊安裝依賴揩魂, build 出一個二進(jìn)制程序。
然后炮温,第二部分用了官方的 alpine
鏡像火脉,改變時區(qū)到中國,新特性體現(xiàn)在 COPY
關(guān)鍵字柒啤,
它現(xiàn)在可以接受 --from=
這樣的參數(shù)倦挂,從上個我們起名字的階段復(fù)制文件過來。
就這么簡單担巩,現(xiàn)在你只需要一個 Dockerfile 就什么都搞定了方援。
多項目構(gòu)建
于是現(xiàn)在你可以把好幾個項目的二進(jìn)制文件構(gòu)建在一個迷你鏡像中發(fā)布了,繼續(xù)舉個栗子:
from debian as build-essential
arg APT_MIRROR
run apt-get update
run apt-get install -y make gcc
workdir /src
from build-essential as foo
copy src1 .
run make
from build-essential as bar
copy src2 .
run make
from alpine
copy --from=foo bin1 .
copy --from=bar bin2 .
cmd ...
這個就是把兩個項目編譯出來的文件最終合并到了一個鏡像里兵睛。
好了肯骇,祝賀那些不支持多段構(gòu)建的 CI 服務(wù),Docker 幫你們追平了競爭對手祖很。
我有機(jī)會會寫一個支持 Docker 的 CI 的主觀評論笛丙,也歡迎大家吐槽各路 CI 給我提供素材。