Docker 的多阶段构建
需求
我们 Build 一个应用的时候,将我们的源代码也构建进去的,这对于类似于 golang 这样的编译型语言肯定是不行的,因为实际运行的时候我只需要把最终构建的二进制包给你就行,把源码也一起打包在镜像中,需要承担很多风险,即使是脚本语言,在构建的时候也可能需要使用到一些上线的工具,这样无疑也增大了我们的镜像体积。所以对于golang语言运行于docker之上的时候,只出现二进制文件即可。
比如有如下程序需要在docker中运行:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
router.GET("/ping", func(c *gin.Context) {
c.String(http.StatusOK, "PONG")
})
router.Run(":8080")
}
第一步:原始方式构建镜像
编写dockerfile文件:
FROM golang:1.14-alpine
ENV CGO_ENABLED=0
ENV GOPROXY="http://10.11.100.127/repository/goproxy/"
RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories \
&& apk add --update --no-cache ca-certificates curl make git gcc libtool musl-dev
RUN mkdir /app \
&& mkdir -p /app/static
COPY . /app
WORKDIR /app
RUN go mod vendor && go build -o main
CMD ["/app/main"]
构建镜像:
docker build -t demo-test:old .
查看镜像:
可以看到,镜像文件有570多M。
第二步:取二进制文件构建镜像
其实我们只需要他的二进制文件,所以需要拿去二进制文件即可:
docker create --name myapp demo-test:old
docker cp myapp:/app/app-server ./app-server
docker rm -f extract
获取二进制文件后,继续编写第二个dockerfile文件: cat Dockerfile.old
FROM alpine:latest
RUN apk add -U tzdata
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
WORKDIR /root/
COPY app-server .
CMD ["./app-server"]
查看镜像:
此时可以看到镜像文件只有24.1MB了!
第三步:多阶段构建
Docker 17.05版本以后,官方就提供了一个新的特性:Multi-stage builds
(多阶段构建)。 使用多阶段构建,你可以在一个 Dockerfile
中使用多个 FROM 语句。每个 FROM 指令都可以使用不同的基础镜像,并表示开始一个新的构建阶段。你可以很方便的将一个阶段的文件复制到另外一个阶段,在最终的镜像中保留下你需要的内容即可。
我们可以调整前面一节的 Dockerfile
来使用多阶段构建:(保存为Dockerfile)
FROM golang:1.14-alpine as build-env
ENV CGO_ENABLED=0
ENV GOPROXY="http://10.11.100.127/repository/goproxy/"
RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories \
&& apk add --update --no-cache ca-certificates curl make git gcc libtool musl-dev
RUN mkdir /app \
&& mkdir -p /app/static
COPY . /app
WORKDIR /app
RUN go mod vendor && go build -o /app/main
FROM alpine:latest
RUN apk add -U tzdata
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY --from=build-env /app/main /usr/local/bin/app-server
EXPOSE 8080
CMD ["app-server"]
注意:COPY中的--from=build-env可以直接使用第一阶段生成的文件,相当于接管了第一阶段的上下文。
构建镜像:
docker build -t multi-state-demo:new .
查看镜像:
可以看到,多阶段构建和之前分为两步构建,效果一样!