如何构建 Go 应用的 Docker 镜像

💡 原文中文,约10100字,阅读约需24分钟。
📝

内容提要

本文介绍Go应用Docker镜像构建实践:先编写简单REST应用,用Dockerfile基于golang:1.16-alpine安装依赖并编译,但镜像达407MB;改用多阶段构建,第一阶段编译,第二阶段用scratch仅复制二进制文件,镜像缩至约8MB;构建时通过CGO_ENABLED=0、GOOS、GOARCH交叉编译;最后用Makefile简化测试、构建等流程。

🔎

延伸解读

多阶段构建:从407MB到8MB的关键

文章通过对比展示,基础Dockerfile构建的镜像达407MB,而多阶段构建后仅约8MB。差异源于第二阶段使用scratch作为基础镜像,仅复制编译好的二进制文件,丢弃了Go工具链和依赖。这提醒读者,对于编译型语言,运行时无需完整构建环境,多阶段构建能显著减小镜像体积,节省存储和传输成本。

交叉编译:确保二进制在目标平台运行

多阶段构建中,编译命令设置了CGO_ENABLED=0、GOOS=linux和GOARCH=amd64。文章解释,CGO_ENABLED默认开启,交叉编译时需关闭以避免依赖C库;GOOS和GOARCH指定目标平台。这保证了在macOS等开发机上构建的二进制能在Linux容器中运行。读者应注意根据部署环境调整这些变量,否则可能无法运行。

Makefile:简化重复构建命令

文章末尾引入Makefile来封装测试、构建等命令,如make test、make build-docker-multistage。随着构建流程涉及多个Dockerfile和交叉编译参数,手动输入命令容易出错。Makefile将常用任务抽象为目标,提高可维护性。对于真实项目,可在此基础上扩展更多任务,但需注意Makefile的语法和依赖关系。

❓

Q&A

如何为Go应用编写一个基础的Dockerfile?

基础Dockerfile以golang:1.16-alpine为基础镜像,设置工作目录/app,复制go.mod和go.sum后运行go mod download安装依赖,再复制所有.go文件,用go build编译出二进制文件,最后用CMD指定启动命令。

为什么基础Dockerfile构建的镜像有407MB,怎么减小?

因为基础镜像包含全套Go工具和依赖,而应用运行只需二进制文件。使用多阶段构建:第一阶段用golang:1.16-alpine编译,第二阶段用scratch作为基础镜像,仅复制编译好的二进制文件,镜像可减小到约8MB。

Go交叉编译需要设置哪些环境变量?

需要设置CGO_ENABLED=0(禁用cgo)、GOOS指定目标操作系统(如linux)、GOARCH指定目标CPU架构(如amd64)。例如:CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build。

多阶段构建的Dockerfile中两个阶段分别做什么?

第一阶段(AS build)基于golang:1.16-alpine,复制源码并编译出二进制文件;第二阶段基于scratch,用COPY --from=build将二进制文件复制到新镜像,并设置ENTRYPOINT启动。

如何用Makefile简化Go应用的Docker构建流程?

创建Makefile定义变量APP和常用目标,如test运行go test,build-docker构建基础镜像,build-docker-multistage构建多阶段镜像,clean清理等。之后通过make test、make build-docker-multistage等命令执行。

构建多阶段镜像时如何指定不同的Dockerfile?

使用docker build命令的-f参数指定Dockerfile文件,例如:docker build -t docker-go-server-ping:multistage -f Dockerfile.multistage .

🏷️

标签

➡️

继续阅读