到這裡,我們的 Go + Elasticsearch 搜尋服務已經能在本機上穩定運作。
但要讓它成為「雲原生服務」,第一步就是——容器化(Containerization)。
這代表,我們要讓整個應用能被 Docker 這類容器引擎「包起來」,
能在任何地方(本機、CI/CD、Kubernetes)都以相同方式執行。
而這天的任務,就是寫出一個乾淨又高效的 多階段 Dockerfile,
並加上 健康檢查(probe) 讓 Kubernetes 能掌握服務狀態。
在 Golang 世界裡,容器化的最佳實踐之一就是「多階段構建(multi-stage build)」:
讓第一階段專門做編譯(帶 SDK、compiler),
第二階段只留下最小可執行檔(乾淨、輕量、安全)。
以下是一個範例:
# -------- Stage 1: Build --------
FROM golang:1.23 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o search-service ./cmd/server
# -------- Stage 2: Run --------
FROM gcr.io/distroless/base-debian12
WORKDIR /app
COPY --from=builder /app/search-service .
EXPOSE 8080
USER nonroot:nonroot
ENTRYPOINT ["./search-service"]
CGO_ENABLED=0
代表不使用 C 介面,產出靜態執行檔。GOOS=linux
、GOARCH=amd64
,確保相容於 Kubernetes 節點。這樣打包出來的 image,大小通常不到 30MB,非常適合自動部署。
建立 Dockerfile 後,我們先在本機驗證能否成功啟動。
docker build -t search-service:latest .
docker run -p 8080:8080 search-service:latest
接著用 curl 測試:
curl localhost:8080/healthz
應該會看到:
{"status": "ok"}
這代表服務已經能在容器中正常運行。
在進入 Kubernetes 之前,
你必須讓系統知道「什麼時候服務是健康的、可用的」。
這就需要 LivenessProbe 與 ReadinessProbe。
在 Deployment manifest ,
可先定義如下範例:
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
而你的程式要對應這兩個路由,例如:
http.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"alive"}`))
})
http.HandleFunc("/ready", func(w http.ResponseWriter, _ *http.Request) {
if esClient == nil {
http.Error(w, "not ready", http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"ready"}`))
})
/healthz
:只檢查服務進程是否存活。/ready
:檢查外部依賴(如 Elasticsearch)是否能連線。這兩者的差別很關鍵。
healthz
讓 Kubernetes 知道「容器掛了沒」,
ready
則讓它知道「可不可以分流流量進來」。
到目前為止,我們完成了以下幾件重要的里程碑:
步驟 | 成果 |
---|---|
多階段構建 | 產出輕量、安全的映像 |
本地測試 | 驗證容器可正常啟動 |
健康檢查 | 提供 Kubernetes 判斷健康與可用性的依據 |