使用docker打包go项目时私有仓库打包失败的解决方案

914 阅读3分钟

简介

最近在使用docker打包go项目,由于go项目里包含了自建私有仓库的包,碰到了好几个问题,这边针对各种情况介绍可行的解决方案。

准备

假设我们一开始有一份这样的Dockerfile。

FROM golang:1.19

COPY . /src
WORKDIR /src

RUN go build -o /my-app

CMD ["/my-app"]

国内网络

最常遇到的就是go的默认仓库地址是github,go getgo mod download 时会失败。在本地开发时我们一般是设置goproxy,比如可以用goproxy.cn的镜像,执行
go env -w GOPROXY=https://goproxy.cn,direct 就好了。
而在docker中我们可以在RUN 后面加一句 GOPROXY=https://goproxy.cn 这样就会用国内的镜像拉取模块。
修改后的Dockerfile

FROM golang:1.19

COPY . /src
WORKDIR /src

RUN GOPROXY=https://goproxy.cn go build -o /my-app

CMD ["/my-app"]

私有仓库

我们在go项目中可能import自建的仓库模块,例如

package myapp

import (
        "my-private-repo.com/util"
        "fmt"
        )

func UseUtil(){
    util.Call()
    fmt.Println("util called")
}

那么执行 docker build 时可能会遇到类似报错

reading https://goproxy.cn/my-private-repo.com/util/@v/v0.0.0.zip: 404 Not Found

因为我们指定了GOPROXY为goproxy.cn,而goproxy.cn只缓存了例如github.com上公开的go仓库,肯定不会缓存我们的私有仓库。这时候就需要设置GOPRIVATE,指定私有仓库的地址,那么go就不会使用GOPROXY来拉取模块。
我们修改新的dockerfile如下:

FROM golang:1.19

COPY . /src
WORKDIR /src

RUN GOPROXY=https://goproxy.cn GOPRIVATE=my-private-repo.com go build -o /my-app

CMD ["/my-app"]

使用http的git仓库

go在拉取模块时使用的是git,而我们的私有仓库有时候部署在内网,且只使用http协议,那么go拉取私有模块时也会失败。此时可能会报错:

https fetch: Get "https://my-private-repo.com/util/": EOF

出现这种错误要么我们根本没有部署https服务,要么证书无效。
此时可以指定GOINSECURE来强制go使用http协议拉取私有模块。
我们修改新的dockerfile如下:

FROM golang:1.19

COPY . /src
WORKDIR /src

RUN GOPROXY=https://goproxy.cn GOPRIVATE=my-private-repo.com GOINSECURE=my-private-repo.com go build -o /my-app

CMD ["/my-app"]

私有仓库鉴权

git仓库一般都需要鉴权,比如输入用户名和密码。我们在本地环境执行go mod download,如果遇到需要鉴权的私有仓库会提示让你输入用户名和密码,鉴权通过后便可以正常下载私有模块。而docker build不具备交互环境,此时docker build可能会报错:

fatal: could not read Username for 'http://my-private-repo.com': terminal prompts disabled

我这边找到的比较便捷的方案是设置 ~/.netrc
gnu上关于netrc的介绍:

The .netrc file contains login and initialization information used by the auto-login process. It generally resides in the user’s home directory, but a location outside of the home directory can be set using the environment variable NETRC. Both locations are overridden by the command line option -N. The selected file must be a regular file, or access will be denied.

netrc就是用来实现自动登录用的,不止可用于git,很多带交互cli输入用户名密码的服务都可以使用,他的格式为

machine my-domain.com login my-account password my-password

machine 配置域
login 配置用户名
password 配置密码

我们在Dockerfile中将我们git私有仓库的鉴权信息先输入到 ~/.netrc 就可以实现go get 私有仓库时自动登录了。
将上面的 my-domain.commy-accountmy-password修改为你自己的git仓库地址,git用户名和git密码即可。
修改Dockerfile如下:

FROM golang:1.19

COPY . /src
WORKDIR /src

RUN echo "machine my-private-repo.com login my-user password my-password" > ~/.netrc
RUN GOPROXY=https://goproxy.cn GOPRIVATE=my-private-repo.com GOINSECURE=my-private-repo.com go build -o /my-app

CMD ["/my-app"]