[英]Cache “go get” in docker build
我想將golang單元測試封裝在docker-compose腳本中,因為它取決於多個外部服務。 我的應用程序具有很多依賴關系,因此需要一段時間才能go get
。
如何以一種允許docker容器構建的方式緩存程序包,而不必每次我要測試時都下載所有依賴項?
我的Dockerfile:
FROM golang:1.7
CMD ["go", "test", "-v"]
RUN mkdir -p /go/src/app
WORKDIR /go/src/app
COPY . /go/src/app
RUN go-wrapper download
RUN go-wrapper install
每次我想運行單元測試時,都會在以下腳本上運行docker-compose up --build backend-test
:
version: '2'
services:
...
backend-test:
build:
context: .
dockerfile: Dockerfile
image: backend-test
depends_on:
...
但是現在每次我要運行測試時都會調用go-wrapper download
,這需要很短的時間才能完成。
解決方案? 提前致謝!
我個人使用govendor 。 根據golang供應商約定,它將依賴項保留在項目內的供應商目錄中。 在構建時,仍然需要將其復制到您的Docker映像。
但是有很好的理由不與供應商合作。 例如,當您構建pkg時,您不應供應商。 當您使用不同版本的依賴項使用不同的pkg時,情況會變得混亂。 只有供應商提供的可執行文件可以解決此問題。
因此,如果您有充分的理由不願與供應商合作,則可以分開幾個步驟。 按照正確的順序放置它們可以加快處理速度。
您可以使用一些用於獲取依賴項的go get
命令來創建Shell腳本( get.sh
)。 (您可以將它們放在Dockerfile中,但是它們有行限制)
go get github.com/golang/protobuf/proto
go get github.com/pborman/uuid
go get golang.org/x/net/context
go get golang.org/x/net/http2
go get golang.org/x/net/http2/hpack
然后,在您的Dockerfile中,首先復制並執行shell腳本。 每次更新get.sh時,它將完全重建。 它仍然運行got get ./...
來確保所有依賴項都在那里。 但是,如果將所有內容添加到get.sh
腳本中,您將獲得不錯的速度提升。
FROM golang:1.6
RUN mkdir -p /go/src/app
COPY get.sh /go/src/app
WORKDIR /go/src/app
RUN bash get.sh
COPY . /go/src/app
RUN go get ./...
CMD go test -v
通常的想法是,您要經常在Dockerfile中降低內容的更改頻率,而在頂部保持不變。 即使您必須添加另一個或兩個命令。 Docker會逐行處理,直到找到需要重建的內容,然后再進行每一行。
我一直在尋找您問題的答案,但具有諷刺意味的是,我找到了一個答案(如何快速運行Docker測試)。 如果您確實需要快速測試,則理想情況下,應在運行它們時完全避免重建容器。 但是,等等,如何將新的源代碼放入容器? 卷我的朋友,卷。 這是我的設置方法:
docker-compose.dev.yml:
backend-test:
volumes:
- .:/path/to/myapp
當然,/ path / to / myapp是圖像中的路徑。 您必須為開發人員顯式傳遞此圖像:
docker-compose up -f docker-compose.dev.yml
但是現在,當您運行測試時,您將不再使用docker-compose,而將使用docker exec:
docker exec -it backend-test go test
如果正確執行此操作,則后端測試容器中的src目錄將始終是最新的,因為它實際上是已裝入的卷。 事實證明,連接到運行中的容器並運行測試要比每次旋轉一個新容器快得多。
編輯:Commenter正確指出,這僅避免在您依賴項沒有更改時避免重建圖像(無需go get
)。 令人高興的是,它不僅避免了重建,而且還避免了重新啟動。 當我像這樣進行測試並添加依賴項時,通常只go get
直接從測試控制台go get
即可。 它可以是一個有點棘手得到go get
到工作中的容器內,但一個方法是通過您的容器轉發你的SSH代理安裝SSH_AUTH_SOCK 。 遺憾的是,您無法在構建期間掛載卷,因此,如果您希望構建目標能夠在運行測試之前提取新的依賴項,則可能需要在映像中包括某種部署密鑰。 但是,我的回答的重點是分離構建和測試,以避免完整構建,直到您准備生成最終工件為止。
就是說,我想我可能會理解,我不是按照您提出的方式回答問題。 在ruby中,答案很簡單,就是復制Gemfile和Gemfile.lock,然后運行bundle install --deploy
,然后再復制已更改的代碼。 就我個人而言,我不介意添加依賴項時的重建成本,因為99%的更改仍然不會涉及重建。 也就是說,您可能會考慮使用golang的新Bundler啟發式依賴管理器: dep 。 安裝dep后,我敢肯定您可以將Gopkg.toml
和Gopkg.lock
復制到您的工作目錄中,運行dep ensure
Gopkg.lock
,然后復制您的代碼。 這只會在Gopkg更新后拉取依賴關系-否則docker將能夠在安裝了先前依賴關系的情況下重用緩存的層。 抱歉,長時間編輯!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.