在Docker容器中使用Golang构建私有依赖不可靠的问题
在Docker容器中使用Golang构建私有依赖不可靠的问题 我遇到过好几次这样的情况:它似乎神奇地只对某个特定版本有效。但一旦我更新版本,就会再次陷入同样的问题,而这些问题往往需要花费数小时来解决。
以下是我目前的情况:
- 据我所知,GitHub SSH 已设置好并且可以正常工作。
- 本地构建可以正常工作
- 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
所以,如果你的问题仅仅是使用私有依赖项,我认为你需要仓库的凭据,并且配置好 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 .
关键配置说明:
- 设置GOPRIVATE环境变量:
# 在Dockerfile中或构建时设置
ENV GOPRIVATE=github.com/your-org/*
- 确保正确的git配置:
# 在Dockerfile中
RUN git config --global url."git@github.com:".insteadOf "https://github.com/"
- 避免vendor目录问题:
# 不要复制vendor目录,让go mod download在容器内处理
COPY go.mod go.sum ./
RUN go mod download
COPY . .
这个方案确保了Docker构建环境与本地开发环境具有相同的认证权限,从而解决了私有依赖访问不可靠的问题。

