Docker分阶段构建
其实之前一直用docker都是无脑直接把对应的代码都拖进去同一个容器然后编译运行,但是这样子会带来一个问题,就是我们这个容器会变得很大,因为它不仅包含了运行所需要的环境,同时也包含了编译所需要的环境。
这时候,我们可以敏锐地察觉到,其实运行环境并不需要和编译环境一样,我们实际运行往往只需要更小的环境,能够执行对应的命令操作,以及查看对应的日志就可以了。
所以我们将编译这一步隔离出来,我们直接将编译的结果放进对应的容器就可以了
FROM alpine
WORKDIR /build
COPY server .
CMD ["./server"]
可以看到,我们将对应的编译结果,拷贝到对应的容器中,然后运行它就可以了
这样子一来,我们就解决了运行容器过大的问题。
但是,依旧有个问题接踵而至了,比如我们开发的时候,往往是协同开发的,这时候,如果协同开发的服务器中,有人更改了服务器环境中的一些选项,这时候,你再来编译你的项目,就可能出现了一些难以发现的隐藏的问题,等待着哪一天爆发出来。
这时候,联想到我们先前采用的方法,我们把编译的这一个过程,也放到对应的容器中去执行,然后再将执行的结果,放入到运行的容器中,而这时候,我们只需要规定好这个编译容器的对应的参数,就可以保证我们每次编译的时候,对应的选项都是确定的。
FROM golang:alpine AS builder
LABEL stage=gobuilder
ENV CGO_ENABLED 0
ENV GOPROXY https://goproxy.cn,direct
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
RUN apk update --no-cache && apk add --no-cache tzdata
WORKDIR /build
ADD go.mod .
ADD go.sum .
RUN go mod download
COPY . .
RUN go build -ldflags="-s -w" -o /app/server ./cmd/cyclopropane/server.go
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai
ENV TZ Asia/Shanghai
WORKDIR /app
COPY --from=builder /app/server /app/server
COPY --from=builder /build/test-conf.yaml /app/test-conf.yaml
CMD ["./server"]
其实这种加中间层的方式在计算机行业其实也是蛮常见的,现在的计算机的整个体系,无不是在一点一点增加中间层,可能是为了确保安全,也可能是为了增加更多的功能,当遇到一些问题的时候,我们不妨也尝试着加一点中间层,说不定哪天,我们就开创了一个新的方向呢?
鸣谢万俊峰Kevin大佬的博客:构建 Go 应用 docker 镜像的十八种姿势 - 万俊峰Kevin - 博客园 (cnblogs.com)