我本来只想看看docker官方提供的CI/CD教程,然后官方引用了,Ben's blog提到了CI/CD的最佳实践,然后我就去阅读了大神的博客,然后大神引用了另一个大神的通过docker开发你的Go程序的系列文章。OK,我还挺喜欢这种引用的,那一层一层看吧,肯定都是好内容。
Chris大神说他刚开始加入开发团队的时候,也遇到了很多编程语言,配置开发环境的问题,经常需要问同事帮忙,还经常被各种工具困扰,这些过程非常花费时间,并且他在维护debug CI过程的时候也非常痛苦。
他提到了一个角度我觉得很好,他说Go开发的工具链,提供快速编译时间,内置依赖管理,简单的交叉编译。但工具链会遇到诸多Go版本不匹配,缺少依赖,配置不同的问题。一个很好的例子就是在许多项目中使用了gRPC,因此特定版本的protoc也很重要。
大神的博客涵盖了构建,测试,CI和优化方案帮助大家更快上手。
迎接究极干货
从简单的go程序开始:
package main import "fmt" func main() { fmt.Println("Hello world!") }
通过go build就可以编译成二进制文件。
go build -o bin/example .
外加简单的Dockerfile
FROM golang:1.14.3-alpine As build WORKDIR /src COPY . . RUN go build -o /out/example . FROM scratch AS bin COPY --from=build /out/example /
说简单也不简单,两阶段构建,第一阶段,构建,用了Go Alpine镜像,Alpine镜像大家了解吧,很多语言都有这个版本,超级轻量化,常规机遇Debian的Golang轻量镜像代替品。定义了go的版本(我这个时候还在想,要不要做一个新版本的用例)。设置了工作目录,将代码复制到容器中,然后编译。第二阶段使用了临时的空镜像(这个我头次见)然后将第一阶段的编译好的耳机只文件复制到文件系统中。大神贴心的提到,如果我们的程序需要一些其他的资源比如CA证书,这些也需要包含在最终的镜像中。
小tips:
我之前使用Alpine镜像的时候,我们是不用跑docker run -it < image_id > bash的,因为Alpine不带,那怎么进一个CLI呢?可以用/bin/sh。
升级版(交叉编译版)
FROM --platform=${BUILDPLATFORM} golang:1.14.3-alpine AS build WORKDIR /src ENV CGO_ENABLED=0 COPY . . ARG TARGETOS ARG TARGETARCH RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /out/example . FROM scratch AS bin COPY --from=build /out/example /
使用了BUILDPLATFORM设置基础镜像平台。使用TARGETOS和TARGETARCH告诉Go在那个平台构建。
大神还提供了Makefile,makfile我还没有学过多语法,一起看看吧
all: bin/example .PHONY: bin/example bin/example: @docker build . --target bin --output bin/ --platform local
使用make,或者make bin/example都能构建。
再进一步
FROM --platform=${BUILDPLATFORM} golang:1.14.3-alpine AS build WORKDIR /src ENV CGO_ENABLED=0 COPY . . ARG TARGETOS ARG TARGETARCH RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /out/example . FROM scratch AS bin-unix COPY --from=build /out/example / FROM bin-unix AS bin-linux FROM bin-unix AS bin-darwin FROM scratch AS bin-windows COPY --from=build /out/example /example.exe FROM bin-${TARGETOS} AS bin
这已经多阶段方案了吧,Linux(bin-linux),macOS(bin-darwin),windows(bin-windows)。我的天真希望我不要遇到这些问题。这些可以让我动态选择编译目标。
然后再优化Makefile
all: bin/example PLATFORM=local .PHONY: bin/example bin/example: @docker build . --target bin --output bin/ --platform ${PLATFORM}
然后我们就可以指定使用平台了
make PLATFORM=windows/amd64
makefile俩面的参数能这么直接传真实学到了
还能学到一点
大神提到了使用.dcokerignore减少不需要的内容,如果我们的项目通过git进行代码管理,我觉得大多数的项目都是git管理吧,我们可以排出.git/目录, 这一点再docker官网的教程了都没写。
reference
本文所有的例子都来自于大神的博客: https://www.docker.com/blog/containerize-your-go-developer-environment-part-1/