在docker環(huán)境導(dǎo)入私有倉(cāng)庫(kù)的問題
最近我遇到了一個(gè)在 docker 環(huán)境導(dǎo)入私有倉(cāng)庫(kù)的問題:一個(gè) Golang 項(xiàng)目,使用 gitlab ci[1] 來(lái)發(fā)布,通過 gitlab runner[2] 調(diào)用 docker-compose[3] 來(lái)打包,但是在構(gòu)建時(shí)失敗了。
讓我們重回案發(fā)現(xiàn)場(chǎng),看看問題是怎么產(chǎn)生的:
首先是 .gitlab-ci.yml 文件,其相關(guān)代碼片段內(nèi)容如下:
build_job:
??stage:?build
??script:
????-?make?docker-build
然后是 Makefile 文件,其相關(guān)代碼片段內(nèi)容如下:
.PHONY:?docker-build
docker-build:
?@docker-compose?build
接著是 docker-compose.yml 文件,其相關(guān)代碼片段內(nèi)容如下:
build:
??context:?.
??dockerfile:?Dockerfile
最后是 Dockfile 文件,其相關(guān)代碼片段內(nèi)容一下:
FROM?golang:1.17?AS?builder
WORKDIR?/go/src/app
COPY?.?.
RUN?go?build
結(jié)果在 build 的時(shí)候報(bào)錯(cuò)了:
fatal: could not read Username for ‘https://git.domain.com’: terminal prompts disabled
因?yàn)?git.domain.com 是一個(gè)私有倉(cāng)庫(kù),所以問題乍一看上去會(huì)以為是 GOPRIVATE 和 GOPROXY 的配置有問題,不過我的配置都是 OK 的:
shell>?go?env?-w?GOPRIVATE=git.domain.com
shell>?go?env?-w?GOPROXY=https://goproxy.cn,direct
實(shí)際上,根本原因是因?yàn)樵L問私有倉(cāng)庫(kù)的時(shí)候是需要用戶名和密碼的,但是在 docker 容器里獲取不到用戶名密碼,所以報(bào)錯(cuò)了。下面看看如何解決問題:
第一次嘗試
既然問題出在用戶名密碼上,那么把倉(cāng)庫(kù)改成公開的不就行了么?可惜報(bào)錯(cuò):
Visibility level public is not allowed in a private group.
我用的是 gitlab,它不允許在私有組里搞一個(gè)公開項(xiàng)目。
第二次嘗試
既然搞不成公開項(xiàng)目,那么就想辦法傳遞用戶名密碼吧,不過我們?cè)谑褂?git 的時(shí)候,一般不會(huì)直接使用用戶名密碼,而是使用 KEY 來(lái)訪問倉(cāng)庫(kù),下面舉例說(shuō)明一下如何傳遞私鑰參數(shù) SSH_PRIVATE_KEY(其中牽扯到一個(gè) docker 構(gòu)建參數(shù)的概念):
首先因?yàn)榇祟愋畔⒈容^敏感,所以應(yīng)該避免硬編碼,我們選擇在 gitlab 里創(chuàng)建它:

接著是 docker-compose.yml 文件,其相關(guān)代碼片段內(nèi)容如下:
build:
??context:?.
??dockerfile:?Dockerfile
??args:
????-?SSH_PRIVATE_KEY
最后是 Dockfile 文件,其相關(guān)代碼片段內(nèi)容一下:
FROM?golang:1.17?AS?builder
ARG?SSH_PRIVATE_KEY
WORKDIR?/go/src/app
COPY?.?.
RUN?umask?0077?\
????&&?mkdir?-p?~/.ssh?\
????&&?echo?"${SSH_PRIVATE_KEY}"?>?~/.ssh/id_rsa?\
????&&?ssh-keyscan?git.domain.com?>>?~/.ssh/known_hosts?\
????&&?git?config?--global?url."[email protected]:".insteadOf?https://git.domain.com/
RUN?go?build
此方法可以解決問題,但是把敏感信息傳來(lái)傳去總覺得不安心,容易出問題,推薦閱讀:Access Private Repositories from Your Dockerfile Without Leaving Behind Your SSH Keys[4]。
第三次嘗試
如果不想把敏感信息傳來(lái)傳去,那么還有沒有安全的解決方案呢?答案是肯定的!我們只要在 gitlab runner 里執(zhí)行「go mod vendor」就可以了,這是因?yàn)?gitlab runner 本身已經(jīng)緩存了 git 認(rèn)證信息,它可以訪問所有的私有倉(cāng)庫(kù),當(dāng)執(zhí)行「go mod vendor」后,項(xiàng)目依賴就都被放到 vendor 目錄里了,接下來(lái)當(dāng)執(zhí)行到 Dockerfile 的 COPY 指令時(shí),項(xiàng)目依賴就被自然而然的拷貝到了容器中,從而不用再聯(lián)網(wǎng)執(zhí)行 git 下載。
下面是修改后的 .gitlab-ci.yaml 文件,其相關(guān)代碼片段內(nèi)容如下:
build_job:
??stage:?build
??script:
????-?go?mod?vendor
????-?make?docker-build
也就是說(shuō),我們只加了一行代碼「go mod vendor」,就解決了問題,是不是很簡(jiǎn)潔。最后友情提示一下:記得把 vendor 目錄放到 .gitignore 里哦。
參考資料
gitlab ci: https://docs.gitlab.com/ee/ci/
[2]gitlab runner: https://docs.gitlab.com/runner/
[3]docker-compose: https://docs.docker.com/compose/
[4]Access Private Repositories from Your Dockerfile Without Leaving Behind Your SSH Keys: https://vsupalov.com/build-docker-image-clone-private-repo-ssh-key/
推薦閱讀
