1. 程式人生 > >Docker 映象製作教程:針對不同語言的精簡策略

Docker 映象製作教程:針對不同語言的精簡策略

本系列文章將分為三個部分: 第一部分著重介紹多階段構建(multi-stage builds),因為這是映象精簡之路至關重要的一環。在這部分內容中,我會解釋靜態連結和動態連結的區別,它們對映象帶來的影響,以及如何避免那些不好的影響。中間會穿插一部分對 `Alpine` 映象的介紹。連結:[Docker 映象製作教程:減小映象體積](https://fuckcloudnative.io/posts/docker-images-part1-reducing-image-size/) 第二部分將會針對不同的語言來選擇適當的精簡策略,其中主要討論 `Go`,同時也涉及到了 `Java`,`Node`,`Python`,`Ruby` 和 `Rust`。這一部分也會詳細介紹 Alpine 映象的避坑指南。什麼?你不知道 `Alpine` 映象有哪些坑?我來告訴你。連結:[Docker 映象製作教程:針對不同語言的精簡策略](https://fuckcloudnative.io/posts/docker-images-part2-details-specific-to-different-languages/) 第三部分將會探討適用於大多數語言和框架的通用精簡策略,例如使用常見的基礎映象、提取可執行檔案和減小每一層的體積。同時還會介紹一些更加奇特或激進的工具,例如 `Bazel`,`Distroless`,`DockerSlim` 和 `UPX`,雖然這些工具在某些特定場景下能帶來奇效,但大多情況下會起到反作用。 本文介紹第二部分。 ## 1. Go 語言映象精簡 `Go` 語言程式編譯時會將所有必須的依賴編譯到二進位制檔案中,但也不能完全肯定它使用的是靜態連結,因為 `Go` 的某些包是依賴系統標準庫的,例如使用到 DNS 解析的包。只要程式碼中匯入了這些包,編譯的二進位制檔案就需要呼叫到某些系統庫,為了這個需求,Go 實現了一種機制叫 `cgo`,以允許 Go 呼叫 C 程式碼,這樣編譯好的二進位制檔案就可以呼叫系統庫。 也就是說,如果 Go 程式使用了 `net` 包,就會生成一個動態的二進位制檔案,如果想讓映象能夠正常工作,必須將需要的庫檔案複製到映象中,或者直接使用 `busybox:glibc` 映象。 當然,你也可以禁止 `cgo`,這樣 Go 就不會使用系統庫,使用內建的實現來替代系統庫(例如使用內建的 DNS 解析器),這種情況下生成的二進位制檔案就是靜態的。可以通過設定環境變數 `CGO_ENABLED=0` 來禁用 cgo,例如: ```dockerfile FROM golang COPY whatsmyip.go . ENV CGO_ENABLED=0 RUN go build whatsmyip.go FROM scratch COPY --from=0 /go/whatsmyip . CMD ["./whatsmyip"] ``` 由於編譯生成的是靜態二進位制檔案,因此可以直接跑在 `scratch` 映象中