08. Dockerfile多阶段创建
2025-02-17
简介
多阶段构建(Multi-stage builds)是 Docker 17.05 引入的新特性,它允许在一个 Dockerfile 中使用多个 FROM 语句。这种方式可以:
- 大幅减少最终镜像的体积
- 避免在构建过程中引入不必要的依赖
- 简化构建流程
1. 传统构建方式的问题
在多阶段构建出现之前,通常采用两种方式构建镜像:
- 全部放入一个 Dockerfile
- 分散到多个 Dockerfile
1.1 单一 Dockerfile 方式
存在的问题:
- 镜像层次多,镜像体积较大,部署时间变长
- 源代码存在泄露的风险
示例:构建 Go 应用
创建 app.go 文件:
package main import "fmt" func main(){ fmt.Printf("Hello World!"); }编写 Dockerfile.one:
FROM golang:1.9-alpine RUN apk --no-cache add git ca-certificates WORKDIR /go/src/github.com/go/helloworld COPY app.go . RUN go get -d -v github.com/go-sql-driver/mysql \ && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . \ && cp /go/src/github.com/go/helloworld/app /root WORKDIR /root/ CMD ["./app"]构建镜像:
docker build -t go/helloword:1 -f Dockerfile.one .
1.2 多 Dockerfile 方式
基本思路:
- 第一个 Dockerfile 用于编译构建
- 第二个 Dockerfile 用于生成运行环境
- 使用脚本将两个阶段连接起来
示例:
编写 Dockerfile.build(构建阶段):
FROM golang:1.9-alpine RUN apk --no-cache add git WORKDIR /go/src/github.com/go/helloworld COPY app.go . RUN go get -d -v github.com/go-sql-driver/mysql \ && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .编写 Dockerfile.copy(运行阶段):
FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY app . CMD ["./app"]创建构建脚本 build.sh:
#!/bin/sh echo Building go/helloworld:build docker build -t go/helloworld:build . -f Dockerfile.build docker create --name extract go/helloworld:build docker cp extract:/go/src/github.com/go/helloworld/app ./app docker rm -f extract echo Building go/helloworld:2 docker build --no-cache -t go/helloworld:2 . -f Dockerfile.copy rm ./app执行构建:
chmod +x build.sh ./build.sh
镜像大小对比:
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB
go/helloworld 1 f55d3e16affc 2 minutes ago 295MB注意: 虽然第二种方式可以得到更小的镜像,但构建过程较为复杂。
2. 多阶段构建
2.1 基本用法
使用多阶段构建,只需要一个 Dockerfile 就可以实现上述功能:
FROM golang:1.9-alpine as builder
RUN apk --no-cache add git
WORKDIR /go/src/github.com/go/helloworld/
RUN go get -d -v github.com/go-sql-driver/mysql
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
FROM alpine:latest as prod
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/go/helloworld/app .
CMD ["./app"]2.2 构建镜像
docker build -t go/helloworld:3 .2.3 高级特性
构建特定阶段
使用 --target 参数可以指定构建到某个阶段:
# 只构建 builder 阶段
docker build --target builder -t username/imagename:tag .从其他镜像复制文件
COPY 指令支持从其他阶段或外部镜像复制文件:
# 从上一阶段复制
COPY --from=builder /go/src/app .
# 从指定镜像复制
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf3. 最佳实践
- 将构建阶段放在前面,运行阶段放在后面
- 使用
as为每个阶段命名,提高可读性 - 只复制必要的文件,减少镜像体积
- 合理使用缓存,提高构建效率