快轉到主要內容

Docker 建構 Golang 專案時,下載私有庫依賴失敗

·3 分鐘
賴炳維
作者
賴炳維
畢業後,進入 devops 領域。目前擔任 SRE 工程師,專注於系統可靠性和自動化。喜歡探索新技術,並致力於提升系統性能和穩定性。
目錄

問題描述❓
#

在進行 Golang 專案建構時,go.mod 可能會需要指定在同一個私有庫中的其他專案作為依賴。在建構的過程中如果遇到無法下載私有庫依賴的問題,可能會導致建構的過程中失敗!

例如以下 go.mod 文件中,專案需要依賴在同一個私有 GitLab 中的其他 Golang Module 專案:

module project

go 1.24.2

require (
  github.com/go-sql-driver/mysql v1.9.3
  github.com/redis/go-redis/v9 v9.18.0
  private.gitlab.com/golibrary/module v1.0.34 // 這是私有 GitLab 中的 Golang Module 專案
)

require (
  cloud.google.com/go/auth v0.15.0
  cloud.google.com/go/auth/oauth2adapt v0.2.7
  cloud.google.com/go/compute/metadata v0.6.0
)
flowchart LR

subgraph private_network[Private Network]
subgraph private_gitlab[Private GitLab]
golang_projcet[Golang 專案]
golang_module_project[Golang Module 專案]

golang_projcet -->|go.mod| golang_module_project
end
end

這是因為私有 GitLab 通常會有防火牆或是需要認證的限制,如果直接使用 go getgo mod tidy,Golang 會嘗試去抓公開的 Proxy 伺服器,導致下載私有庫時出現 404 / 410 錯誤。

下面是 Golang 在建構專案時,下載私有庫依賴失敗的流程圖:

flowchart LR

subgraph CICD[CI/CD Pipeline]
A[執行 go get / go build] --> B{Go 判斷模組路徑}
B -->|未設定 GOPRIVATE| C[走公開 GOPROXY]
C --> D[回報 404 / 410 錯誤]
D --> E[下載失敗 ❌]
B -->|已設定 GOPRIVATE| F[繞過 Proxy 直連 Git 伺服器]
F --> G{檢查 Git 驗證機制}
G -->|HTTPS 驗證失敗| H[提示輸入帳密或 Token 錯誤]
G -->|SSH 密鑰未設定/無權限| I[提示 Permission denied]
H --> E
I --> E
%% 解決方案分支
F -->|設定正確的憑證/SSH insteadOf| J[成功下載私有庫依賴 ✅]
style E fill:#f96,stroke:#333,stroke-width:2px
style J fill:#9f9,stroke:#333,stroke-width:2px

end

可以知道問題的癥結點在於要正確的設定 Golang 的私有倉庫環境變量,並且配置 Git 以使用帶有認證的 URL。這樣才能夠順利存取 Private GitLab 儲存庫。

解決方案✅
#

服務的建構工具使用 Dockerfile,所以會使用 Dockerfile 當作範例。

ARG GO_VERSION=1.22
ARG ALPINE_VERSION=3.18

# 階段 1: 構建階段
FROM golang:${GO_VERSION}-alpine AS builder

# 重新宣告 ARG 以在此階段使用
ARG SERVICE_NAME
ARG USER
ARG TOKEN

# 安裝必要的構建工具
RUN apk add --no-cache git make bash

# 設置工作目錄
WORKDIR /app

# 設置 Go 私有倉庫環境變量
RUN go env -w GOPRIVATE="private.gitlab.com" && \
  go env -w GONOSUMDB="private.gitlab.com" && \
  go env -w GONOPROXY="private.gitlab.com"

# 配置 Git,使用帶有認證的 URL
RUN git config --global url."https://${USER}:${TOKEN}@private.gitlab.com/".insteadOf "https://private.gitlab.com/" && \
  git config --global url."https://${USER}:${TOKEN}@private.gitlab.com/".insteadOf "http://private.gitlab.com/"

# 複製依賴文件
COPY go.mod go.sum ./

# 下載依賴
RUN go mod tidy -download -x

# 複製整個專案
COPY . .

# 創建輸出目錄並構建應用
RUN mkdir -p /app/bin && \
  CGO_ENABLED=0 GOOS=linux go build -o /app/bin/${SERVICE_NAME} main.go && \
  echo "Build completed. Checking output file:" && \
  ls -lh /app/bin/ && \
  test -f /app/bin/${SERVICE_NAME} || (echo "ERROR: Binary file not found!" && exit 1)

# 階段 2: 運行階段
FROM alpine:${ALPINE_VERSION}

# 重新宣告 ARG 以在此階段使用
ARG SERVICE_NAME
ARG SERVICE_PORT
ARG SERVICE_CMD

# 將 ARG 轉換為 ENV 以便運行時使用
ENV SERVICE_NAME=${SERVICE_NAME}
ENV SERVICE_PORT=${SERVICE_PORT}
ENV SERVICE_CMD=${SERVICE_CMD}

# 安裝 CA 證書和時區數據
RUN apk --no-cache add ca-certificates tzdata

# 創建非 root 用戶
RUN addgroup -g 1000 appuser && \
  adduser -D -u 1000 -G appuser appuser

# 設置工作目錄
WORKDIR /app

# 從構建階段複製可執行文件
COPY --from=builder --chown=appuser:appuser /app/bin/${SERVICE_NAME} ./${SERVICE_NAME}

# 創建日誌目錄
RUN mkdir -p logs && chown -R appuser:appuser logs

# 切換到非 root 用戶
USER appuser

# 暴露應用端口
EXPOSE ${SERVICE_PORT}

# 啟動應用
CMD ["sh", "-c", "./${SERVICE_NAME} ${SERVICE_CMD}"]

主要的修改點包括:

  1. 設置 Go 私有倉庫環境變量:

    RUN go env -w GOPRIVATE="private.gitlab.com" && \
      go env -w GONOSUMDB="private.gitlab.com" && \
      go env -w GONOPROXY="private.gitlab.com"
    • GOPRIVATE: 指定哪些網域或模組路徑屬於私有
    • GONOPROXY: 決定哪些模組路徑不要透過公共的 Proxy 伺服器(如 proxy.golang.org)抓取
    • GONOSUMDB: 決定哪些模組路徑不要送到公共的驗證和校驗和資料庫(sum.golang.org)進行安全檢查

    📌如果有設置 GOPRIVATE,會自動設定 GONOPROXY 與 GONOSUMDB!

  2. 配置 Git 以使用帶有認證的 URL:

    RUN git config --global url."https://${USER}:${TOKEN}@private.gitlab.com/".insteadOf "https://private.gitlab.com/" && \
      git config --global url."https://${USER}:${TOKEN}@private.gitlab.com/".insteadOf "http://private.gitlab.com/"

正確配置以後,Golang 專案在建構時就能夠順利下載私有庫依賴!

參考文獻📚
#

相關文章