使用Docker来管理golang的编译依赖

golang开发在依赖管理一直不太方便,主要有一下问题:

  • golang.org包下载不方便
  • 如果不提前下载好所有依赖,glide install速度慢

golang.org被墙的问题可以通过设置glide 的mirror来解决,glide install下载慢的问题也可以通过提前下的来解决。但是,但是服务器上进行CI就不方便,如果需要每次都重新下载依赖,显然编译速度慢,导致集成速度慢,这不是我想要的。

我们的所有的golang项目都是在golang的容器里面编译,所以,我们可以通过这里来下手,尽可能的降我们会用到的依赖安装在容器的GOPATH中,这样glide在安装依赖的不需要从github重新下载代码了,国内网络连接github还是挺慢的,这样做能节约不少构建时间, 还有一个好处就是如果是用的github上的某个包,被作者删除了,也不会影响你的正常编译。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FROM golang

RUN apt-get update && apt-get -y upgrade
RUN apt-get install -y ca-certificates git build-essential && rm -rf /var/lib/apt/lists/*
RUN go get -u github.com/Masterminds/glide
RUN go get -u github.com/jstemmer/go-junit-report
RUN go get -u github.com/go-bindata/go-bindata/...
RUN go get -u github.com/golang/dep/cmd/dep
RUN go get -u golang.org/x/crypto
RUN go get -u golang.org/x/net
RUN go get -u golang.org/x/tools
RUN go get -u golang.org/x/text
RUN go get -u golang.org/x/image
RUN go get -u golang.org/x/sys
RUN go get -u github.com/gin-gonic/gin

比如,这里我安装了golang.org的包,同理,我还以安装其他的包。我们将这个Dockerfile推送到github上,让后关联到DockerHub就能自动编译出一个属于我自己的golang编译器容器了

利用这个容器,我们可以我们的项目代码,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ipackage main

import (
"net/http"
"github.com/gin-gonic/gin"
)

func main() {
router := gin.Default()

router.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "%s", "Hello World")
})
router.Run()
}

这是我们的源码,是一个gin框架的web项目。我们已经为这个项目生产了glide的文件,glide.yaml和glide.lock文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM  golang:mygolang as builder
RUN mkdir /golang/src/golang-example
WORKDIR /golang/src/golang-example
COPY . .
RUN glide install
RUN go build -o main

FROM alpine:v3.8
RUN mkdir /app/main
RUN adduser -S -D -H -h /app appuser
COPY --from=builder /golang/src/golang-example/main /app/main
USER appuser
WORKDIR /app
CMD [ "./main" ]

这里我们使用多步骤编译的方式来来编译我们的镜像,这样编译出来的镜像是不包含golang编译和glide等编译期间依赖,体积非常小。同事应为不在需要从网络下载依赖,编译速度也变快了不少。

说明

文中提搞的golang:mygolang这自定义的镜像应该放在自己的私有仓库,这样我们就能在任何地方我们的项目了,并且迁移方便,不管你是使用gitlab ci还是Jenkins ci。并且,编译好了的镜像应该加入到私有仓库。