多阶段构建后,Docker镜像大小只有原来的1/6

简介

在构建 Docker 镜像时,常遇到以下问题:

  1. 每一次执行 RUN 命令会让镜像新增一层 layer,导致镜像变大,虽然通过 && 连接多个命令能缓解此问题,但如果命令之间用到 Docker 指令例如 COPYWORKDIR 等,依然会导致多个layer。

  2. 有些工具在构建过程中会用到,但是最终的镜像是不需要的(例如本案里中编译 GreatSQL 需要安装 cmake, gcc 等组件),这要求在构建完后还要额外清理这些工具,清理的过程又可能导致新的layer。

  3. 不分构建过程甚至部分源码不想被看到。

为了解决上述问题,从 Docker 17.05 版本开始,在构建镜像时增加了新特性:多阶段构建(multi-stage builds),将构建过程分为多个阶段,每个阶段都可以指定一个基础镜像,这样在一个 Dockerfile 就能将多个镜像的特性同时用到。

这种方法在不牺牲构建过程的复杂度和灵活性的前提下,可以显著减小最终镜像的大小,提高安全性,并且易于维护。

相关文档地址:https://docs.docker.com/develop/develop-images/multistage-build/。

分阶段构建是一种强大的 Docker 构建策略,它可以帮助你创建更加精简、安全和易于维护的镜像。通过将构建过程分解为多个独立的阶段,你可以在不影响最终镜像质量的前提下,充分利用 Docker 的构建缓存机制,加速构建流程。

举例

先用一个非常简单的案例来说明如何进行多阶段构建。

下面是一份精简的 Dockerfile:

# 第一阶段
FROM oraclelinux:8-slim as builder

# 在第一阶段进行构建
RUN touch /tmp/GreatSQL-8.0.32-26-Linux-glibc2.28-x86_64.tar.xz && echo $RANDOM > /tmp/GreatSQL-8.0.32-26-Linux-glibc2.28-x86_64.tar.xz

# 第二阶段
FROM oraclelinux:8-slim

# 从第一阶段构建的结果中将文件拷贝过来
COPY --from=builder /tmp/GreatSQL-8.0.32-26-Linux-glibc2.28-x86_64.tar.xz /tmp

CMD ["sh"]

结合备注内容,上述案例应该还是非常好理解的,就不赘述了。

GreatSQL-Build 镜像优化

上述这些问题,在 GreatSQL-Build 镜像中都存在。该镜像的尺寸高达 1.18GB,构建过程也非常慢,是时候对其进行优化了。

优化后的 Dockerfile 主要内容如下:

FROM oraclelinux:8-slim as builder

WORKDIR /

LABEL maintainer="greatsql.cn" \
email="greatsql@greatdb.com" \
forum="https://greatsql.cn/forum.php" \
gitee="https://gitee.com/GreatSQL/GreatSQL-Docker"

ARG TARGETARCH \
OPT_DIR=/opt \
MYSQL_UID=3306 \
MYSQL_USER=mysql \
GREATSQL_BUILD_DOWNLOAD_URL="https://gitee.com/GreatSQL/GreatSQL-Docker/raw/greatsql-8.0.32-26/GreatSQL-Build" \
GREATSQL_ENV="greatsql-setenv.sh" \
ENTRYPOINT="docker-entrypoint.sh" \
DEPS="autoconf automake binutils bison cmake cyrus-sasl-devel cyrus-sasl-scram gcc-c++ \
gcc-toolset-11 gcc-toolset-11-annobin-plugin-gcc jemalloc jemalloc-devel krb5-devel libaio-devel \
libcurl-devel libtirpc-devel libudev-devel m4 make ncurses-devel numactl-devel openldap-devel \
openssl openssl-devel pam-devel readline-devel zlib-devel xz util-linux findutils"

RUN echo '[main]' > /etc/dnf/dnf.conf && \
microdnf install -y oracle-epel-release-el8 && \
microdnf install -y ${DEPS} && \
microdnf update -y && \
microdnf clean all && \
source /opt/rh/gcc-toolset-11/enable && \
echo 'source /opt/rh/gcc-toolset-11/enable' >> /root/.bash_profile; \
/usr/sbin/groupadd -g ${MYSQL_UID} ${MYSQL_USER} && \
/usr/sbin/useradd -u ${MYSQL_UID} -g ${MYSQL_UID} -s /sbin/nologin ${MYSQL_USER} && \
curl -o ${OPT_DIR}/${GREATSQL_ENV} ${GREATSQL_BUILD_DOWNLOAD_URL}/${GREATSQL_ENV} && \
curl -o /${ENTRYPOINT} ${GREATSQL_BUILD_DOWNLOAD_URL}/${ENTRYPOINT} && \
chmod +x /*sh ${OPT_DIR}/*sh && \
sh /docker-entrypoint.sh


FROM oraclelinux:8-slim as greatsql_build

LABEL maintainer="greatsql.cn" \
email="greatsql@greatdb.com" \
forum="https://greatsql.cn/forum.php" \
gitee="https://gitee.com/GreatSQL/GreatSQL-Docker"

ARG TARGETARCH \
OPT_DIR=/opt

# copy GreatSQL tarball to /opt
COPY --from=builder ${OPT_DIR}/GreatSQL*.tar.xz ${OPT_DIR}

CMD ["sh"]

这份文件也已经同步到gitee上:https://gitee.com/GreatSQL/GreatSQL-Docker/blob/master/GreatSQL-Build/Dockerfile。

还是同样的思路,在第一阶段完成环境初始化及 GreatSQL 源码编译,第二阶段只需把编译后的二进制包拷贝过来就行。

经过优化后,新的 GreatSQL-Build 镜像尺寸仅为 200MB,只有原来的 1/6,效果显著。

$ docker images
...
# 阿里云ACR上的旧镜像,还没更新
registry.cn-beijing.aliyuncs.com/greatsql/greatsql_build   latest            a8a4dcaa1ce1   9 days ago     1.18GB

# 腾讯云TCR上的新镜像,已更新
ccr.ccs.tencentyun.com/greatsql/greatsql_build             latest            1b53cc0906cc   15 hours ago   200MB

以上。

Enjoy GreatSQL :)


文章推荐:

想看更多技术好文,点个“在看”

outside_default.png题图由阿里通义万相生成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值