容器镜像的多阶段构建

2023-10-24 17:18:56 浏览数 (2)

上篇讲了流量回放工具 goreplay 的二进制使用方式。想将其打包成一个镜像,在K8s部署的线上生产环境使用。

基于后向兼容性,希望构建的镜像 系统基于ubuntu 18.04,基于最新的Go版本进行编译安装。但同时不希望镜像的体积过大。

以下内容为构建容器镜像的一些方式。

在 Docker 17.05前,构建镜像通常采用两种方式:

1. 全部放入一个 Dockerfile

将所有的构建过程包含在一个 Dockerfile 中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题:

但这样的坏处也显而易见:镜像层次多,镜像体积较大,同时部署时间变长

代码语言:javascript复制
FROM ubuntu:18.04

# Install build dependencies
RUN apt-get update && apt-get install -y 
    build-essential 
    libpcap-dev 
    curl 
    ca-certificates 
    wget

# Install Go
RUN curl -OLs https://go.dev/dl/go1.21.3.linux-amd64.tar.gz 
    && tar -C /usr/local -xzf go1.21.3.linux-amd64.tar.gz 
    && rm go1.21.3.linux-amd64.tar.gz
ENV PATH /usr/local/go/bin:$PATH

# Get goreplay source code
RUN wget -c https://github.com/buger/goreplay/archive/refs/tags/1.3.3.tar.gz && tar -zxvf 1.3.3.tar.gz


RUN export GOPROXY=https://goproxy.cn

# Build goreplay
RUN cd goreplay-1.3.3 && go build -o gor
RUN mv goreplay-1.3.3/gor ./

COPY ./start.sh /app/start.sh

# 用于调试
#CMD sleep 86400

#CMD ["./start.sh"]

针对如上Dockerfile,执行ocker build -t ubuntu-with-gor/20231017 .,

docker image ls 查看编译出的镜像大小,高达1.14G

2. 另外一种方式是分散到多个 Dockerfile,构建多个镜像,前一个镜像为后面的依赖

预先在一个 Dockerfile中 将项目及其依赖库构建好,再将其拷贝到另一个镜像的运行环境中

这种方式需编写两个 Dockerfile ,为了便利及后续可维护性,最好还要通过一个shell脚本能两个编译阶段整合起来。

这种方式构建出的镜像较小,能规避第一种方式的问题。但复杂度稍高。

使用多阶段构建

为解决以上问题,从Docker 17.05开始, 支持多阶段构建 (Multi-stage builds[1])

使用多阶段构建可以很解决前面提到的问题,且只需编写一个 Dockerfile (多个FROM,前面的是后面的基础)

在 /data/tmp/goreplay-lab3 目录下:

代码语言:javascript复制
FROM ubuntu:18.04 AS build-env

# Install build dependencies
RUN apt-get update && apt-get install -y 
    build-essential 
    libpcap-dev 
    curl 
    ca-certificates 
    wget

# Install Go
RUN curl -OLs https://go.dev/dl/go1.21.3.linux-amd64.tar.gz 
    && tar -C /usr/local -xzf go1.21.3.linux-amd64.tar.gz 
    && rm go1.21.3.linux-amd64.tar.gz
ENV PATH /usr/local/go/bin:$PATH

# Get goreplay source code
RUN wget -c https://github.com/buger/goreplay/archive/refs/tags/1.3.3.tar.gz && tar -zxvf 1.3.3.tar.gz

# Build goreplay
RUN cd goreplay-1.3.3 && go build -o gor

RUN mv goreplay-1.3.3/gor ./



FROM ubuntu:18.04

COPY --from=build-env ./gor ./gor

COPY ./start.sh ./start.sh

#CMD sleep 86400

#CMD ["./start.sh"]

如果是Dockerfile,则构建时 docker build -t xxx . 即可。其中 . 是指将当前目录作为构建上下文(可能需要copy什么东西之类的)

如果不叫Dockerfile,则需要 docker build -t xxx -f 文件名称如Dockerfile.new .

执行

docker build -t ubuntu-with-gor/20231017multistage .

运行

docker run -it ubuntu-with-gor/20231017multistage /gor --input-raw :8000 --output-stdout

根据报错,libpcap这个依赖,没法打包到gor二进制文件中,还是要以动态链接的形式引用

调整Dockerfile:

代码语言:javascript复制
FROM ubuntu:18.04 AS build-env

RUN apt-get update && apt-get install -y 
    build-essential 
    libpcap-dev 
    curl 
    ca-certificates 
    wget

# Install Go
RUN curl -OLs https://go.dev/dl/go1.21.3.linux-amd64.tar.gz 
    && tar -C /usr/local -xzf go1.21.3.linux-amd64.tar.gz 
    && rm go1.21.3.linux-amd64.tar.gz
ENV PATH /usr/local/go/bin:$PATH

# Get goreplay source code
RUN wget -c https://github.com/buger/goreplay/archive/refs/tags/1.3.3.tar.gz && tar -zxvf 1.3.3.tar.gz

# Build goreplay
RUN cd goreplay-1.3.3 && go build -o gor

RUN mv goreplay-1.3.3/gor ./



FROM ubuntu:18.04

# Install dependencies (还是需要libpcap,不然gor无法运行...)
RUN apt-get update && apt-get install -y libpcap-dev


COPY --from=build-env ./gor ./gor



COPY ./start.sh ./start.sh

#CMD sleep 86400

#CMD ["./start.sh"]

再次构建,可以正常运行。

最后对比两种构建方式,镜像的体积差异:

可见针对于这个case,使用了多阶段构建,省了将近1G的空间..

另: 如何查看docker镜像每一层的大小?

可以使用以下命令:

代码语言:javascript复制
docker history <镜像名称>

执行此命令后,将显示有关镜像每一层的详细信息,包括大小、创建时间和所用命令。

如果只想查看镜像的总大小而不需要每一层的详细信息,可以使用以下命令,将列出所有镜像及其大小。

代码语言:javascript复制
docker images --format "{{.Repository}}:{{.Tag}}t{{.Size}}"
代码语言:javascript复制
[root@xxxxxx goreplay-lab3]# docker history ubuntu-with-gor/20231017multistage 
IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
ef445692c1c3   4 minutes ago   /bin/sh -c #(nop) COPY file:3477a1d7e70cfddc…   124B      
2a1beab897af   4 minutes ago   /bin/sh -c #(nop) COPY file:e2d87186c89499c8…   17MB      
684a5fa4113a   4 minutes ago   /bin/sh -c apt-get update && apt-get install…   71.2MB    
71eaf13299f4   11 months ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B        
<missing>      11 months ago   /bin/sh -c #(nop) ADD file:fc5d658c47ede5882…   63.1MB    



[root@xxxxxx goreplay-lab3]# docker history ubuntu-with-gor/20231017v3
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
cf6bf1961c5f   48 minutes ago   /bin/sh -c #(nop) COPY file:3477a1d7e70cfddc…   124B      
64e2cd095db3   48 minutes ago   /bin/sh -c mv goreplay-1.3.3/gor ./             17MB      
21c9b5bdda07   48 minutes ago   /bin/sh -c cd goreplay-1.3.3 && go build -o …   580MB     
fb02ab4a0ca5   50 minutes ago   /bin/sh -c export GOPROXY=https://goproxy.cn    0B        
81848581b4b1   50 minutes ago   /bin/sh -c wget -c https://github.com/buger/…   768kB     
f7fe340b3104   2 hours ago      /bin/sh -c #(nop)  ENV PATH=/usr/local/go/bi…   0B        
cae91c2acab5   2 hours ago      /bin/sh -c curl -OLs https://go.dev/dl/go1.2…   214MB     
1d45d6924b67   2 hours ago      /bin/sh -c apt-get update && apt-get install…   267MB     
71eaf13299f4   11 months ago    /bin/sh -c #(nop)  CMD ["bash"]                 0B        
<missing>      11 months ago    /bin/sh -c #(nop) ADD file:fc5d658c47ede5882…   63.1MB   

参考资料

[1]

Multi-stage builds: https://docs.docker.com/build/building/multi-stage/

0 人点赞