在Docker容器中使用Golang构建私有依赖不可靠的问题

在Docker容器中使用Golang构建私有依赖不可靠的问题 我遇到过好几次这样的情况:它似乎神奇地只对某个特定版本有效。但一旦我更新版本,就会再次陷入同样的问题,而这些问题往往需要花费数小时来解决。

以下是我目前的情况:

  1. 据我所知,GitHub SSH 已设置好并且可以正常工作。
  2. 本地构建可以正常工作
  3. Go mod 文件中包含了我想要使用的版本

在少数几次成功构建的情况下,我使用了以下构建流程:

在一个 bash 脚本中,我执行以下操作:

go clean -modcache
go mod tidy
go mod download
go mod vendor

在 Dockerfile 中:

FROM golang:1.16-buster AS build
WORKDIR /app
COPY go.mod ./
COPY go.sum ./
COPY vendor ./
COPY *.go ./
ENV GO111MODULE=on
RUN go build -o /<product-name>

这个方法会由于一些难以理解的原因而停止工作,并出现以下错误信息:

go: github.com/.../…@v0.0.3: reading github.com/.../.../go.mod at revision v0.0.3: unknown revision v0.0.3

然而,本地构建却可以完美运行,并且 vendor 文件夹中也包含了该版本,modules.txt 文件内容如下:

# github.com/.../... v0.0.3
## explicit
github.com/.../.../...

由于这个错误反复出现,我对自己在 Go 模块系统方面的理解已经失去了信心。

如果有人能提供一个分步指南,可靠地在 Docker 容器中构建具有私有依赖项的 Go 项目,并且能以可重复的方式进行,我将非常高兴。

提前感谢。


更多关于在Docker容器中使用Golang构建私有依赖不可靠的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

所以,如果你的问题仅仅是使用私有依赖项,我认为你需要仓库的凭据,并且配置好 GOPRIVATE。关于这一点,可以参考这个教程:如何在您自己的项目中使用私有 Go 模块 | DigitalOcean

更多关于在Docker容器中使用Golang构建私有依赖不可靠的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢您的回复。我知道这个链接,并且使用过几次。它并未为这个问题提供一个可靠的解决方案。几周后或一个发布版本之后,我可以重复整个过程,却始终无法确切知道它最初为何停止工作,或者哪一步是导致它不再工作的原因。

因此,在我看来,这个过程(尽管是官方的“正确”方式)并不稳固。我怀疑这是因为错误信息具有误导性。根据我的经验,这可能意味着实现中存在某些问题。我的意思是,如果错误信息不够精确,无法有效地解决问题。

我转而使用指向本地副本的 replace 指令来处理,从而绕过了所有关于获取修订版本/版本以使其工作的不必要的复杂性——如果这确实是问题所在的话。我怀疑并非如此。

我更希望有一个像 NodeJS 那样可靠且易于使用的模块系统。在我看来,以下默认设置将使模块系统更易于使用:

  • 存储依赖项的默认位置是 vendor 文件夹
  • 版本是可选的,vendor 内的本地版本始终作为后备
  • gopath/pkg 中的依赖项可以是一个可选的配置

总的来说,模块系统的设计应围绕这样一个流程:使得在每个步骤中都能拥有易于使用和控制(即使在容器中)的默认后备方案成为可能。

这是一个典型的私有依赖在Docker构建中的认证问题。问题不在于Go模块系统本身,而在于Docker构建环境缺少访问私有仓库所需的SSH密钥或令牌。

以下是可靠的分步解决方案:

1. 使用SSH密钥的Docker多阶段构建方案

# 第一阶段:构建阶段
FROM golang:1.16-buster AS builder

# 安装git并配置SSH
RUN apt-get update && apt-get install -y git openssh-client

# 创建SSH目录并设置权限
RUN mkdir -p /root/.ssh && chmod 700 /root/.ssh

# 复制SSH密钥(在构建时通过--build-arg传入)
ARG SSH_PRIVATE_KEY
RUN echo "${SSH_PRIVATE_KEY}" > /root/.ssh/id_rsa && \
    chmod 600 /root/.ssh/id_rsa

# 配置SSH known hosts(添加你的Git服务器)
RUN ssh-keyscan github.com >> /root/.ssh/known_hosts

# 配置git使用SSH
RUN git config --global url."git@github.com:".insteadOf "https://github.com/"

WORKDIR /app

# 复制go模块文件
COPY go.mod go.sum ./

# 下载依赖
RUN go mod download

# 复制源代码
COPY . .

# 构建应用
RUN go build -o /app/main .

# 第二阶段:运行阶段
FROM debian:buster-slim
WORKDIR /root/
COPY --from=builder /app/main .
CMD ["./main"]

2. 构建命令示例

# 构建Docker镜像时传入SSH密钥
docker build \
  --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)" \
  -t myapp .

3. 使用Docker BuildKit和SSH代理(推荐)

# syntax=docker/dockerfile:1.2
FROM golang:1.16-buster AS builder

# 启用BuildKit的SSH代理功能
RUN --mount=type=ssh \
    apt-get update && apt-get install -y git

WORKDIR /app

# 复制go模块文件
COPY go.mod go.sum ./

# 使用SSH代理下载私有依赖
RUN --mount=type=ssh \
    go mod download

COPY . .

RUN go build -o /app/main .

FROM debian:buster-slim
WORKDIR /root/
COPY --from=builder /app/main .
CMD ["./main"]

构建命令:

# 使用BuildKit并传递SSH代理
DOCKER_BUILDKIT=1 docker build \
  --ssh default \
  -t myapp .

4. 使用GitHub令牌的替代方案

FROM golang:1.16-buster AS builder

# 通过环境变量传入GitHub令牌
ARG GITHUB_TOKEN
ENV GOPRIVATE=github.com/your-org/*

WORKDIR /app

# 配置git使用令牌
RUN git config --global url."https://${GITHUB_TOKEN}:x-oauth-basic@github.com/".insteadOf "https://github.com/"

COPY go.mod go.sum ./

RUN go mod download

COPY . .

RUN go build -o /app/main .

FROM debian:buster-slim
WORKDIR /root/
COPY --from=builder /app/main .
CMD ["./main"]

构建命令:

docker build \
  --build-arg GITHUB_TOKEN=your_github_token_here \
  -t myapp .

5. 完整的项目结构和脚本

创建 build.sh

#!/bin/bash
set -e

# 清理缓存
go clean -modcache

# 更新依赖
go mod tidy
go mod download

# 使用BuildKit构建
DOCKER_BUILDKIT=1 docker build \
  --ssh default \
  -t myapp:latest .

关键配置说明:

  1. 设置GOPRIVATE环境变量
# 在Dockerfile中或构建时设置
ENV GOPRIVATE=github.com/your-org/*
  1. 确保正确的git配置
# 在Dockerfile中
RUN git config --global url."git@github.com:".insteadOf "https://github.com/"
  1. 避免vendor目录问题
# 不要复制vendor目录,让go mod download在容器内处理
COPY go.mod go.sum ./
RUN go mod download
COPY . .

这个方案确保了Docker构建环境与本地开发环境具有相同的认证权限,从而解决了私有依赖访问不可靠的问题。

回到顶部