Skip to content
All writing Part 02 of 09 · 一次 Golang 版本升級的連鎖反應
Engineering · 2 min read

把 Golang 工具鏈嫁接到你需要的 base image

當 tag 矩陣裡真的沒有你要的 Golang × Alpine 組合,multi-stage build 可以把工具鏈嫁接過去,但先確認需求是真的。

當 Docker Hub 的 tag 矩陣裡真的沒有你要的 Golang × Alpine 組合(見組合 base image 前先查 tag 矩陣),multi-stage build(多階段建構:Dockerfile 裡寫多個 FROM,每個是獨立的建構步驟)可以把 Golang 工具鏈從一個 stage 複製到另一個 base。兩個 FROM兄弟,不是鏈條——最後一個才是出貨的 base:

FROM golang:1.25-alpine AS gotool          # 只取工具鏈
FROM alpine:3.20                           # 選你需要的系統函式庫版本
COPY --from=gotool /usr/local/go /usr/local/go
ENV PATH=/usr/local/go/bin:$PATH
ENV GOTOOLCHAIN=local                      # 不讓 go 自動下載另一套工具鏈
RUN apk add vips-dev                       # → Go 1.25 + 指定的 libvips,各自獨立
golang:1.25-alpine stage 1(捐贈者) go toolchain alpine libs — 丟棄 整個 stage 丟棄 alpine:3.20 stage 2 = 最終 image go toolchain(嫁接進來) vips-dev(apk add) alpine 3.20 系統函式庫 COPY
兩個 FROM 是兄弟,不是鏈條。最後一個才是出貨的 base。
  • GOTOOLCHAIN=local 阻止 go 為了滿足 go.mod 裡更高的版本指令而自動下載工具鏈。
  • build 和 runtime stage 要釘到同一個 base,否則 runtime 會靜默出貨錯誤的系統函式庫。
  • 注意 graft 本身的耦合:浮動的 golang:<v>-alpine 工具鏈是用較新的 musl(Alpine 的 C 標準函式庫,不同於 Ubuntu 的 glibc)編譯的,嫁接到較舊的 base 上可能造成函式庫版本不匹配。

什麼時候不該用這招: 兩道閘門,依序——(1) 查矩陣,你要的組合可能已經發布了;(2) 確認系統函式庫的需求是真的。一個建立在錯誤前提上的 graft 是純粹的複雜度。

graft 解決的是「矩陣裡沒有我的組合」這個問題。如果你的前提是「我需要舊版函式庫」,先確認那個需求是真的。


參考來源:

Related: 回到連鎖反應總覽,或參見組合 base image 前先查 tag 矩陣釘版要附退場計畫EOL base image 讓安全更新靜默失效

Tags #devops #debugging #docker
// connect

Be brave | Be wise | Be grateful

21 BreakinCode

// elsewhere
LinkedInMedium (lang: en)Youtube
wh:~$William Hung· © 2026 Taipei · GMT+8 · Available for collaboration