建立最小的Go docker 映象
雖然曾有一些文章介紹瞭如何建立一個最小的Go Docker映象,我也曾寫過一篇文章,但是隨著Go的新的版本的釋出, 以及docker本身的進化,有些技巧已經發生了變化, 本文介紹了最新的建立超小的Go映象的方法。
一個簡單Go程式的映象
首先讓我們建立一個很簡單的Go程式:
1package main
2import "fmt"
3func main() {
4 fmt.Println("hello world")
5}
執行下面的命令會建立一個超小的映象, 這是我們的第一種方式:
1GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go && tar c app | docker import - app:latest
下一節介紹其中的編譯引數
檢視映象, 生成的映象只有 1.21MB
:
1# docker images app
2REPOSITORY TAG IMAGE ID CREATED SIZE
3app latest b716e13758cd 11 seconds ago 1.21MB
這命令將編譯、打包、輸入映象整合到一條命令了。
第二種方式是使用一個Dockerfile檔案:
1FROM scratch
2ADD app /
3CMD ["/app"]
執行下面的命令建立一個映象:
1docker build -t app2 .
檢視生成的映象, 也是 1.21MB
:
1# docker images app2
2REPOSITORY TAG IMAGE ID CREATED SIZE
3app2 latest 4e2af2ffb695 4 seconds ago 1.21MB
第三種方式是利用Docker的 multistage 功能,在映象中編譯,Dockerfile檔案:
1Dockerfile.multistage
2docker build -t app3 -f Dockerfile.multistage .
檢視生成的映象, 也是``:
1# docker images app3
2REPOSITORY TAG IMAGE ID CREATED SIZE
3app3 latest 9177859dad64 16 seconds ago 1.21MB
你可以結合你的情況選擇一種生成映象的方式。
編譯Go程式
上面的例子中我們使用下面的命令編譯Go程式:
1GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go
你可能在其它一些文章中還看到installsuffix
引數:
1GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -installsuffix cgo -o app app.go
自Go 1.10以後,你不必再使用installsuffix
引數(或許更早的版本),Go的核心開發人員Ian Lance Taylor已經確認了這一點。
你可能有人還使用-a
引數,它強制重新編譯相關的包,一般你不會使用它。
-s
忽略符號表和除錯資訊,-w
忽略DWARF符號表,通過這兩個引數,可以進一步減少編譯的程式的尺寸,更多的引數可以參考go link, 或者 go tool link -help
(另一個有用的命令是go tool compile -help
)。
你也可以使用strip
工具對編譯的Go程式進行裁剪。
本身Go是靜態編譯的, 對於CGO, 如果設定CGO_ENABLED=0
,則完全靜態編譯,不會再依賴動態庫。
如果設定CGO_ENABLED=0
,並且你的程式碼中使用了標準庫的net
包的話,有可能編譯好的映象無法執行,報sh: /app: not found
的錯誤,儘管/app
這個檔案實際存在,並且如果講基礎映象換為centos
或者ubuntu
的話就能執行。這是一個奇怪的錯誤,原因在於:
預設情況下net
包會使用靜態連結庫, 比如libc
知道了原因,解決辦法也很簡單,就是完全靜態連結或者在基礎映象中加入libc庫。
下面是幾種解決辦法:
設定 CGO_ENABLED=0
編譯是使用純go的net: go build -tags netgo -a -v
使用基礎映象加glibc(或等價庫musl、uclibc), 比如 busybox:glibc、alpine + RUN apk add --no-cache libc6-compat
、frolvlad/alpine-glibc
有的同學說了,我程式碼中確實必須使用CGO,因為需要依賴一些C/C++的庫。目前沒有對應的Go庫可替代, 那麼可以使用-extldflags "-static"
,go tool link help
介紹了extldflags
的功能:
-extldflags flags
Set space-separated flags to pass to the external linker.
-static means do not link against shared libraries
基礎映象
其實前面已經列出了一些常用的基礎映象:
scratch: 空的基礎映象,最小的基礎映象
busybox: 帶一些常用的工具,方便除錯, 以及它的一些擴充套件busybox:glibc
alpine: 另一個常用的基礎映象,帶包管理功能,方便下載其它依賴的包
顯然。 你應該只在編譯階段使用Go的映象,這樣才能將你的映象減小到最小。
原文釋出時間為:2018-10-31
本文作者:smallnest
本文來自雲棲社群合作伙伴“Golang語言社群”,瞭解相關資訊可以關注“Golang語言社群”。