构建一个超简约的 Docker 镜像来运行你的 Golang 应用程序
为什么要关心 Docker 镜像的大小?
实例
结论
为什么要关心 Docker 镜像的大小?
基本上,如果您使用某些云提供商,可以加快构建和部署速度,并降低存储和网络成本。 我们可以使用注重极简主义的基础镜像(例如 Alpine Linux)和其他策略(例如多阶段构建,这是我结合基础镜像使用的方法)来实现最小的 Docker 镜像大小。egress
SCRATCH
实例
让我们玩一下 Docker,即使您的机器上没有安装它,也可以使用🐋在线实验室,它非常棒,并且可以通过 Web 浏览器提供真正的 Docker 体验。
当你登录在线实验室时,你可以克隆演示项目,你猜怎么着?在运行实例中有一个随时可用的 git 二进制文件,所以:
git clone -b super-minimalistic-docker-image https://github.com/iamseki/dev-to.git
多阶段构建简介
主要思想是将 Dockerfile 分成多个阶段,然后只将镜像正常运行所需的组件传递给下一个阶段。很酷,但是怎么做呢?Docker 官网的
官方解释如下:
FROM
在 Dockerfile 中使用多个语句。每条FROM
指令可以使用不同的基础,并且每个指令都会开始构建的新阶段。
容器化 Golang Web 应用
在这个例子中,我延续了之前博文中的例子,公开一个 http 服务器来处理一个简单的GET
请求。你可以在GitHub 仓库
中查看完整的源代码。Dockerfile 的编写如下:
FROM golang:alpine as builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" .
FROM scratch
WORKDIR /app
COPY --from=builder /app/dev-to /usr/bin/
ENTRYPOINT ["dev-to"]
构建并检查图像大小:
- 如果你还没有
cd dev-to
docker build -t dev-to .
docker images | grep dev-to -B 1
预期输出:
瞧!生成的 Docker 镜像大小为4.55MB,是一个可运行的 Web 服务器 ->docker run --rm -p 8080:8080 -d dev-to
HTTP GET
在服务器公开的唯一路由中发出请求:
curl localhost:8080/events
响应应该是虚假事件的 JSON。
如果我们从 Dockerfile 中删除多阶段构建会怎样?
注释一些行或者重写 Dockerfile,例如:
FROM golang:alpine as builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" .
RUN mv dev-to /usr/bin/
ENTRYPOINT ["dev-to"]
我们得到了一个大小为324MB的图像。
结论
这种方法非常适合 Golang 这样的静态语言,但即使这些语言会编译原始二进制文件供操作系统执行,在编写 Dockerfile 时也应谨慎,以优化 CI/CD 流程并降低成本。
临时基础镜像不包含任何内容,因此它很轻量,但您无法从内部调试容器。为此,您可以使用RUN
命令下载二进制文件,但我鼓励您使用busybox
作为基础镜像,它也很轻量但非空,因此可以使用 exec 命令(例如)从内部调试容器docker exec -ti container-name sh
。