這(zhè)篇文章是關(guān)于如(rú)何為(wèi)Go程序創建一(yī)個(gè)最小的Docker映像。微子(zǐ)網絡覺得很實用,就(jiù)分(fēn)享給大家參考,跟着微子(zǐ)網絡看了(le)看。
前言
之前介紹了(le)關(guān)于在docker部署golang項目的相關(guān)内容,對你入門有一(yī)定的參考價值。本文将向您介紹如(rú)何使用docker來(lái)打包golang編寫的應用程序,最終産品是一(yī)個(gè)Dockerfile。不要小看這(zhè)短短的幾行代碼,其中涉及到很多知識點。接下(xià)來(lái)我們仔細分(fēn)析一(yī)下(xià)。
來(lái)自德國:阿爾卑斯山
ADDsrc/go/src
RUNgoinstall-vtest
ENTRYPOINT['/go/bin/test']
1. 基礎鏡像選擇
第一(yī)行是指定一(yī)個(gè)基本圖像,并基于它創建我們的圖像。這(zhè)裏我們使用golang:alpine版本。
這(zhè)是一(yī)個(gè)相對較小的linux系統。linux中的很多工具都被切斷了(le)。包管理(lǐ)工具使用apk。你可以拉這(zhè)個(gè)圖像Docker玩(wán)玩(wán)。默認外殼是sh。執行命令docker pull-t-I Golang : Alpine/bin/sh進入命令行。輸入後執行env查看環境變量,因為(wèi)其環境變量GOPATH對後續環境部署很有用,可以看到環境變量GOPATH的默認值是/go
2. 映射代碼文件并安裝
使用ADD src /go/src将主機scr文件映射到/go/src目錄。為(wèi)什(shén)麽一(yī)定是這(zhè)個(gè)/go/src目錄?沒錯,就(jiù)是上(shàng)面的GOPATH環境變量的路(lù)徑,因為(wèi)我們需要執行go install命令來(lái)稍後安裝,否則,我們需要重置GOPATH來(lái)安裝編譯後的二進制文件。
此時(shí),在需要注意的是:本地主機的src目錄中的文件組織必須嚴格遵循将要安裝時(shí)生(shēng)成的包的文件結構。test是程序的主程序,glog是使用的開源日志庫。整個(gè)文件結構如(rú)下(xià)。因為(wèi)main.go在導入包時(shí)使用了(le)“github.com/golang/glog'”路(lù)徑,所以有必要給它一(yī)個(gè)合理(lǐ)的路(lù)徑。
Dockerfile
src
github.com
golang
glog
glog_file.go
glog.go
glog_test.go
LICENSE
README
test
main.go還有一(yī)個(gè)小提示,程序的日志庫使用了(le)第三方開源glog。當我們使用git對我們上(shàng)面的代碼進行版本管理(lǐ)的時(shí)候,我們不需要重複包含glog的代碼,直接添加一(yī)個(gè)引用就(jiù)可以了(le)。這(zhè)樣有很多好(hǎo)(hǎo)處。當庫中的代碼被修改時(shí),可以直接更新(xīn)到遠(yuǎn)程代碼倉庫,克隆時(shí)可以自動導入庫,也(yě)就(jiù)是說(shuō)具體(tǐ)的代碼會被本地拉出來(lái)。
Glog可以通過命令生(shēng)成:gi子(zǐ)模式添加https://github.com/golang/glog.git src/github.com/golang/glog。注意:的git remoule命令中引用的位置是src/github.com/golang而不是src/direct,因為(wèi)執行這(zhè)個(gè)命令後,本地代碼倉庫會把glog克隆為(wèi)代碼倉庫,下(xià)拉它的代碼,隻把glog創建為(wèi)目錄,所以之前的一(yī)些(xiē)父目錄需要自己創建。
有關(guān)命令的更多信息,請參見Git。
Go install可以在組織好(hǎo)(hǎo)文件結構後進行,生(shēng)成的文件可以在$GOPATH/bin中執行,後面是基本的指定入口程序和參數。通過docker build -t='name '生(shēng)成圖像。
3.更進一(yī)步:提前編譯
上(shàng)面的方法是把代碼複制到基本鏡像裏面編譯。毫無疑問golang:alpine包含了(le)一(yī)系列的程序運行依賴,這(zhè)些(xiē)庫會在程序運行時(shí)動态加載。我們可以使用ldd命令來(lái)查看生(shēng)成的二進制文件的依賴關(guān)系:
Linux-vdso . so . 1=(0x 00007 ffc 5b 1 e 4000)
libpthread . so . 0=/lib/x86 _ 64-Linux-GNU/libpthread . so . 0(0x 00007 f 50 a1 f 13000)
libc . so . 6=/lib/x86 _ 64-Linux-GNU/libc . so . 6(0x 00007 f 50 a1 B4 a 000)
/lib64/ld-linux-x86-64.so.2
(0x00005611a4b0a000)那麽問題來(lái)了(le)? 如(rú)果将這(zhè)些(xiē)依賴靜态編譯至可執行文件中那就(jiù)不需要在環境中保存這(zhè)些(xiē)多餘的信息了(le),就(jiù)可以創建一(yī)個(gè)更小的鏡像了(le)。幸運的是無論是golang的編譯機制還是docker的基礎鏡像都提供這(zhè)樣的實現(xiàn):
使用命令生(shēng)成靜态編譯的二進制文件:CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main
.
此時(shí)用ldd查看生(shēng)成的可執行文件的依賴,可以看到顯示not a dynamic executable
,這(zhè)裏我們禁用CGO使其生(shēng)成靜态二進制文件,同時(shí)設置系統為(wèi)linux。我們将基礎鏡像設置為(wèi) scratch,這(zhè)是一(yī)個(gè)很小的的鏡像。
重新(xīn)編寫的Dockerfile如(rú)下(xià):
FROMscratch ADDmain/ ENTRYPOINT["/main"] CMD["-logtostderr"]
執行docker build -t example-scratch
.生(shēng)成鏡像,可以看到該鏡像的大小隻有8.27M大小,并且可以正常執行。
在實際情況中有時(shí)會将兩種情況結合使用,先在一(yī)個(gè)鏡像中構建,在另一(yī)個(gè)鏡像中執行。下(xià)面的Dockerfile摘自prometheus這(zhè)個(gè)第三方監控的演示案例的Dockerfile,可以看到它是首先在builder鏡像中下(xià)載對應的依賴并且編譯程序,最後在scratch基礎鏡像中執行程序。
#ThisDockerfilebuildsanimageforaclient_golangexample. # #Useas(fromtherootfortheclient_golangrepository):jingx #dockerbuild-fexamples/$name/Dockerfile-tprometheus/golang-example-$name. #Builderimage,wherewebuildtheexample. FROMgolang:1.9.0ASbuilder WORKDIR/go/src/github.com/prometheus/client_golang COPY.. WORKDIR/go/src/github.com/prometheus/client_golang/prometheus RUNgoget-d WORKDIR/go/src/github.com/prometheus/client_golang/examples/simple RUNCGO_ENABLED=0GOOS=linuxgobuild-a-tagsnetgo-ldflags'-w' #Finalimage. FROMscratch LABELmaintainer"ThePrometheusAuthors<prometheus-developers@googlegroups.com>" COPY--from=builder/go/src/github.com/prometheus/client_golang/examples/simple. EXPOSE8080 ENTRYPOINT["/simple"]
感謝各位的閱讀!關(guān)于“怎麽為(wèi)Go程序創建一(yī)個(gè)最小的Docker Image”這(zhè)篇文章就(jiù)分(fēn)享到這(zhè)裏了(le),希望以上(shàng)内容可以對大家有一(yī)定的幫助,讓大家可以學到更多知識,如(rú)果覺得文章不錯,可以把它分(fēn)享出去讓更多的人(rén)看到吧(ba)!
Copyright © 2013-2016 WWW.VZIDC.COM . All Rights Reserved. 微子(zǐ)網絡 版權所有 江蘇微子(zǐ)網絡科技有限公司