一、Multi-stage概述
Multi-stage是Docker自17.05版本引入的新特性。它允许在一个Dockerfile中定义多个镜像构建阶段,并针对当前阶段选择不同的基础镜像,从而减小镜像大小,提高构建效率。
Multi-stage的实现依赖于Docker buildkit,可以通过设置DOCKER_BUILDKIT环境变量来启用。另外需要注意的是,Multi-stage对镜像的命名并无强制要求,可以根据需求任意命名。
二、基础用法
Multi-stage最基础的用法就是使用多个FROM语句定义多个阶段,比如以下例子:
FROM golang:1.15 AS builder WORKDIR /app COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine COPY --from=builder /app/app . CMD ["./app"]
这个Dockerfile定义了两个阶段,第一个阶段使用golang:1.15镜像作为基础镜像,将当前目录下的所有文件复制到/app目录下,然后使用go build构建应用程序。第二个阶段使用alpine镜像作为基础镜像,只包含Glibc运行库和基础命令,将第一个阶段构建的应用程序复制到当前目录,并设置启动命令为"./app"。
三、多阶段链式调用
Multi-stage还可以链式调用,将一个阶段的输出作为下一个阶段的输入,从而实现更复杂的构建过程。下面是一个简单的例子:
FROM golang:1.15 AS builder WORKDIR /app COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM scratch COPY --from=builder /app/app . ENTRYPOINT ["/app"]
这个Dockerfile定义了两个阶段,第一个阶段与之前的例子相同,第二个阶段使用scratch空镜像作为基础镜像,意味着只包含一个空白文件系统。将第一个阶段构建的应用程序复制到当前目录下,设置启动命令为"/app"。
四、减少镜像大小
Multi-stage可以帮助我们减小镜像大小,在构建应用程序的时候只保留必要的文件和运行时依赖库,避免不必要的文件和依赖导致镜像体积过大。
以Node.js应用为例,我们可以只保留应用程序和运行所需的依赖库,而不包含npm包管理器和应用的开发依赖库。下面是一个示例Dockerfile:
FROM node:14.16 AS build-stage WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build FROM node:14.16-alpine WORKDIR /app COPY --from=build-stage /app/dist ./dist COPY package*.json ./ RUN npm install --production CMD ["npm", "run", "start"]
这个Dockerfile定义了两个阶段,第一个阶段使用node:14.16镜像作为基础镜像,安装应用程序的开发依赖库,构建应用程序。第二个阶段使用node:14.16-alpine镜像作为基础镜像,只包含Node.js运行时依赖库和基础命令,将第一个阶段构建的应用程序复制到当前目录下的dist目录,并安装生产依赖库,设置启动命令为"npm run start"。
五、交叉编译
Multi-stage还可以用于交叉编译应用程序,比如将应用程序编译为不同平台的二进制文件。下面是一个简单的例子:
FROM golang:1.15 AS builder WORKDIR /app COPY . . RUN GOOS=linux GOARCH=amd64 go build -o app-linux-amd64 . RUN GOOS=windows GOARCH=amd64 go build -o app-windows-amd64.exe . FROM scratch COPY --from=builder /app/app-linux-amd64 . ENTRYPOINT ["/app-linux-amd64"]
这个Dockerfile定义了两个阶段,第一个阶段使用golang:1.15镜像作为基础镜像,将当前目录下的所有文件复制到/app目录下,分别使用GOOS和GOARCH环境变量交叉编译应用程序为Linux和Windows平台,输出两个二进制文件。
六、小结
Multi-stage是Docker非常实用的一个特性,可以帮助我们优化Docker镜像构建过程、减小镜像大小、提高构建效率。通过本文介绍的几个例子,相信大家已经掌握了Multi-stage的基础用法及更多高级用法,希望可以对大家的Docker实践有所帮助。