簡體   English   中英

在Docker構建中緩存“獲取”

[英]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.tomlGopkg.lock復制到您的工作目錄中,運行dep ensure Gopkg.lock ,然后復制您的代碼。 這只會在Gopkg更新后拉取依賴關系-否則docker將能夠在安裝了先前依賴關系的情況下重用緩存的層。 抱歉,長時間編輯!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM