以前写的golang项目一直使用的都是公开的module,最近使用私有gitlab仓库的module时,发现go get mod时需要输入用户名密码,开发环境还好解决,手动输一次让他记住就好了。但是项目正式上线,通过公司统一的jenkins Pipeline执行构建时,没有办法去手动输用户名密码。

Dockerfile配置

要解决这个问题,可以通过.netrc文件来处理。Dockerfile如下:

FROM mirror.ccs.tencentyun.com/library/golang:1.17 as builder

ARG GIT_USR
ARG GIT_PWD

ENV GOPROXY=https://goproxy.cn,direct
ENV GOPRIVATE=stash.xxxx.com
ENV GOOS=linux
ENV GIT_TERMINAL_PROMPT=1

WORKDIR /build
COPY . ./

RUN go env -w GOPRIVATE=stash.xxxx.com \
    && echo "machine stash.xxxx.com login ${GIT_USR} password ${GIT_PWD}" > ~/.netrc \
    && GO111MODULE=on CGO_ENABLED=0 GOOS=${GOOS} GOPROXY=${GOPROXY} go build -o=knative-audit-log

################################################################################
##                               MAIN STAGE                                   ##
################################################################################
# Copy the manager into the distroless image.
FROM mirror.ccs.tencentyun.com/library/alpine:3.13

RUN echo 'https://mirrors.cloud.tencent.com/alpine/v3.13/main' > /etc/apk/repositories \
    && echo 'https://mirrors.cloud.tencent.com/alpine/v3.13/community' >>/etc/apk/repositories \
    && apk update && apk add tzdata && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone

WORKDIR /usr/local/app
COPY --from=builder /build/knative-audit-log /usr/local/app/knative-audit-log
RUN chmod 755 /usr/local/app/knative-audit-log

ENTRYPOINT ["/usr/local/app/knative-audit-log"]

重点在3,4行和15行,3,4行通过传入GIT_USR和GIT_PWD两个参数到docker构建内,第15行生成.netrc配置。

现在我们就可以通过传参的方式来构建了:

docker build -t hub.docker.com/xxx/knative-audit-log:v0.1 --build-arg GIT_USR=**** --build-arg 'GIT_PWD=****' -f ./Dockerfile .

Jenkins配置

修改Jenkins Pipeline脚本,通过withCredentials将GIT的用户名和密码传入到docker.build的参数内。使用withCredentials后,jenkins的构建记录内,GIT_USR和GIT_PWD将被显示为××××。以提高安全性。

    stage('Docker build and push image'){
        echo "Start Building..."

        env.git_branch=env.git_branch.replaceAll("/","-")
        image_url = "${image_url}-${git_branch}-${git_commit}"
        currentBuild.displayName = "#${BUILD_ID} $image_url"
        withCredentials([usernamePassword(credentialsId: '1', usernameVariable: 'GIT_USR', passwordVariable: 'GIT_PWD')]) {
            if ( env.root_dir ) {
              def root_dir=env.root_dir
              echo "$root_dir"
              customImage = docker.build(image_url, "--build-arg GIT_USR=${GIT_USR} --build-arg GIT_PWD=${GIT_PWD} --build-arg root_dir=${root_dir} -f ${dockerfile} .")
            } else {
              customImage = docker.build(image_url, "--build-arg GIT_USR=${GIT_USR} --build-arg GIT_PWD=${GIT_PWD} -f ${dockerfile} .")
            }
        }
        docker.withRegistry('https://dockerhub.xxxx.com', 'dockerhub.xxxx.com') {
            customImage.push()
        }
        echo "Build Done, Image Name: ${image_url}"
    }

netrc参考

.netrc是linux系统提供的一个自动保存用户名密码的功能,支持ftp,curl,git等。.netrc文件格式为:

machine name

标识远程计算机名称. curl在.netrc文件中搜索与URL中指定的远程机器相匹配的机器令牌. 一旦匹配,随后的.netrc令牌将被处理,当获取的文件末尾或遇到另一台机器时停止.

login name

远程机器的用户名字符串.

password string

提供密码.如果存在此令牌,则在远程服务器需要密码作为登录过程的一部分时,curl将提供指定的字符串.请注意,如果这个令牌存在.netrc文件中,您确实是 应该 确保文件不可被任何人读到,除了用户.

一个例子.netrc对于主机 stash.xxxx.com 和 名为”username”的用户,使用密码’pwdxxxxx’, 像这样:

machine stash.xxxx.com
login username
password pwdxxxxx