建立最小的Go docker 鏡像

來源:互聯網
上載者:User

雖然曾有一些文章介紹了如何建立一個最小的Go Docker鏡像,我也曾寫過一篇文章,但是隨著Go的新的版本的發布, 以及docker本身的進化,有些技巧已經發生了變化, 本文介紹了最新的建立超小的Go鏡像的方法。

一個簡單Go程式的鏡像

首先讓我們建立一個很簡單的Go程式:

1234567
package mainimport "fmt"func main() {fmt.Println("hello world")}

運行下面的命令會建立一個超小的鏡像, 這是我們的第一種方式:

1
GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go && tar c app | docker import - app:latest

下一節介紹其中的編譯參數

查看鏡像, 產生的鏡像只有 1.21MB

123
# docker images appREPOSITORY          TAG                 IMAGE ID            CREATED             SIZEapp                 latest              b716e13758cd        11 seconds ago      1.21MB

這命令將編譯、打包、輸入鏡像整合到一條命令了。

第二種方式是使用一個Dockerfile檔案:

123
FROM scratchADD app /CMD ["/app"]

運行下面的命令建立一個鏡像:

1
docker build -t app2 .

查看產生的鏡像, 也是 1.21MB:

123
# docker images app2REPOSITORY          TAG                 IMAGE ID            CREATED             SIZEapp2                latest              4e2af2ffb695        4 seconds ago       1.21MB

第三種方式是利用Docker的 multistage 功能,在鏡像中編譯,Dockerfile檔案:

Dockerfile.multistage
1
docker build -t app3 -f Dockerfile.multistage .

查看產生的鏡像, 也是``:

123
# docker images app3REPOSITORY          TAG                 IMAGE ID            CREATED             SIZEapp3                latest              9177859dad64        16 seconds ago      1.21MB

你可以結合你的情況選擇一種產生鏡像的方式。

編譯Go程式

上面的例子中我們使用下面的命令編譯Go程式:

1
GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o app app.go

你可能在其它一些文章中還看到installsuffix參數:

1
GOOS=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的鏡像,這樣才能將你的鏡像減小到最小。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.