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 .

  

查看镜像:

 

 可以看到,多阶段构建和之前分为两步构建,效果一样!

 

 

posted @ 2021-09-03 15:49  skyflask  阅读(441)  评论(0编辑  收藏  举报