k8s|Dockerfile镜像优化方案指引

前言 镜像的优化注意几条:

  • 选择最精简的基础镜像
  • 减少镜像的层数
  • 清理镜像构建的中间产物
  • 注意优化网络请求
  • 尽量去用构建缓存
  • 使用多阶段构建镜像
接下来,我们以rhel7镜像 构建容器,并在容器中安装nginx的源码包。以此容器构建新的镜像并做优化
1.软件准备
[root@server1 docker]# pwd /tmp/docker [root@server1 docker]# ls nginx-1.15.9.tar.gz rhel7.tar

2.导入rhel7镜像
[root@server1 ~]# docker load -i rhel7.tar

3.编写Dockerfile
[root@server1 docker]# pwd /tmp/docker [root@server1 docker]# vim Dockerfile FROM rhel7 COPY yum.repo /etc/yum.repos.d/yum.repo RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make ADD nginx-1.15.9.tar.gz /mnt##ADD比COPY更强大,如果文件时可识别的压缩文件,会帮忙解压 WORKDIR /mnt/nginx-1.15.9 RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc##关闭debug日志 RUN ./configure --prefix=/usr/local/nginx RUN make RUN make install EXPOSE 80 VOLUME ["/usr/local/nginx/html"] CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off; "]

4.构建镜像
[root@server1 docker]# docker build -t nginx:v1 .

5.创建容器,并测试是否能正常访问
[root@server1 docker]# docker run -d --name nginx nginx:v1 096c2d2020638963e877e07a850589ff30e5f5af45278e33f8a859fed35dc81d [root@server1 docker]# [root@server1 docker]# docker inspect nginx "Source": "/var/lib/docker/volumes/7a9f496f3b9d16fa9725ca107c39fa8b9d782c18f0dd3f8d04ea17022b72905a/_data", "IPAddress": "172.17.0.2",[root@server1 docker]# cd /var/lib/docker/volumes/7a9f496f3b9d16fa9725ca107c39fa8b9d782c18f0dd3f8d04ea17022b72905a/_data [root@server1 _data]# ls 50x.htmlindex.html [root@server1 _data]# echo"hello world" > index.html [root@server1 _data]# [root@server1 _data]# cat index.html hello world [root@server1 _data]# [root@server1 _data]# curl 172.17.0.2 hello world

k8s|Dockerfile镜像优化方案指引
文章图片

6.查看镜像大小,优化前大小为276M
[root@server1 ~]# docker images REPOSITORYTAGIMAGE IDCREATEDSIZE nginxv1c3370bb3788a6 minutes ago276MB rhel7latest0a3eb3fde7fd5 years ago140MB

第一次优化 优化思路:将不想看到的输出都导入到垃圾箱,例如刚刚封装时编译过程,如下图
k8s|Dockerfile镜像优化方案指引
文章图片

1.重新编写Dockerfile
[root@server1 docker]# pwd /tmp/docker [root@server1 docker]# vim Dockerfile FROM rhel7 COPY yum.repo /etc/yum.repos.d/yum.repo RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make &> /dev/null && yum clean all ADD nginx-1.15.9.tar.gz /mnt WORKDIR /mnt/nginx-1.15.9 RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc RUN ./configure --prefix=/usr/local/nginx &> /dev/null##将输出导入垃圾箱 RUN make &> /dev/null##将输出导入垃圾箱 RUN make install &> /dev/null##将输出导入垃圾箱 RUN rm -fr /mnt/nginx-1.15.9 EXPOSE 80 VOLUME ["/usr/local/nginx/html"] CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off; "]

2.重新封装镜像
[root@server1 docker]# pwd /tmp/docker [root@server1 docker]# docker build -t nginx:v2 .

k8s|Dockerfile镜像优化方案指引
文章图片

3.再次查看镜像大小,与之前做比较,仅仅少了4M,效果不佳
[root@server1 docker]# docker images REPOSITORYTAGIMAGE IDCREATEDSIZE nginxv2e47941468af7About a minute ago252MB nginxv1c3370bb3788a16 minutes ago276MB rhel7latest0a3eb3fde7fd5 years ago140MB

第二次优化: 优化思路:将RUN都放在一行,减少镜像层数
1.Dockerfile如下:
FROM rhel7 COPY yum.repo /etc/yum.repos.d/yum.repo ADD nginx-1.15.9.tar.gz /mnt WORKDIR /mnt/nginx-1.15.9 RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make &> /dev/null && yum clean all && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx &> /dev/null && make &> /dev/null &&make install &> /dev/null && rm -fr /mnt/nginx-1.15.9 EXPOSE 80 VOLUME ["/usr/local/nginx/html"] CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off; "]

k8s|Dockerfile镜像优化方案指引
文章图片

2.构建镜像并查看镜像大小
[root@server1 docker]# docker build -t nginx:v3 .

k8s|Dockerfile镜像优化方案指引
文章图片

[root@server1 docker]# docker images REPOSITORYTAGIMAGE IDCREATEDSIZE nginxv3cbda333c4f7d30 seconds ago250MB nginxv2e47941468af714 minutes ago252MB nginxv1c3370bb3788a29 minutes ago276MB rhel7latest0a3eb3fde7fd5 years ago140MB

优化后镜像减少了2M,效果仍然不佳
k8s|Dockerfile镜像优化方案指引
文章图片

第三次优化: 优化思路:使用多阶段构建
1.Dockerfile如下:
FROM rhel7 as build COPY yum.repo /etc/yum.repos.d/yum.repo ADD nginx-1.15.9.tar.gz /mnt WORKDIR /mnt/nginx-1.15.9 RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make &> /dev/null && yum clean all && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx &> /dev/null && make &> /dev/null &&make install &> /dev/null && rm -fr /mnt/nginx-1.15.9FROM rhel7 COPY --from=build /usr/local/nginx /usr/local/nginx EXPOSE 80 CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off; "]

【k8s|Dockerfile镜像优化方案指引】k8s|Dockerfile镜像优化方案指引
文章图片

2.构建镜像并查看镜像大小
[root@server1 docker]# docker build -t nginx:v4 . [root@server1 docker]# docker images REPOSITORYTAGIMAGE IDCREATEDSIZE nginxv451d0075d748623 seconds ago141MB nginxv3cbda333c4f7d4 minutes ago250MB nginxv2e47941468af718 minutes ago252MB nginxv1c3370bb3788a33 minutes ago276MB rhel7latest0a3eb3fde7fd5 years ago140MB

优化后效果明显镜像减小到150M
第四次优化:究极优化 优化思路:从底层优化
1.首先我们需要导入一个distroless和nginx镜像
distroless" 镜像只包含应用程序及其运行时依赖项,不包含程序包管理器、shell以及标准Linux发行版中可以找到的任何其他程序。
用distroless去除容器中所有不必要的东西
[root@server1 docker]# docker load -i distroless.tar 668afdbd4462: Loading layer [==================================================>]18.39MB/18.39MB Loaded image: gcr.io/distroless/base:latest[root@server1 docker]# docker load -i nginx.tar 014cf8bfcb2d: Loading layer [==================================================>]58.46MB/58.46MB 832a3ae4ac84: Loading layer [==================================================>]53.91MB/53.91MB e89b70d28795: Loading layer [==================================================>]3.584kB/3.584kB Loaded image: nginx:latest

2.Dockerfile如下
FROM nginx as base # https://en.wikipedia.org/wiki/List_of_tz_database_time_zones ARGS Asia/ShanghaiRUN mkdir -p /opt/var/cache/nginx && \ cp -a --parents /usr/lib/nginx /opt && \ cp -a --parents /usr/share/nginx /opt && \ cp -a --parents /var/log/nginx /opt && \ cp -aL --parents /var/run /opt && \ cp -a --parents /etc/nginx /opt && \ cp -a --parents /etc/passwd /opt && \ cp -a --parents /etc/group /opt && \ cp -a --parents /usr/sbin/nginx /opt && \ cp -a --parents /lib/x86_64-linux-gnu/libpcre.so.* /opt && \ cp -a --parents /lib/x86_64-linux-gnu/libz.so.* /opt && \ cp -a --parents /lib/x86_64-linux-gnu/libc.so.* /opt && \ cp -a --parents /lib/x86_64-linux-gnu/libdl.so.* /opt && \ cp -a --parents /lib/x86_64-linux-gnu/libpthread.so.* /opt && \ cp -a --parents /lib/x86_64-linux-gnu/libcrypt.so.* /opt && \ cp -a --parents /usr/lib/x86_64-linux-gnu/libssl.so.* /opt && \ cp -a --parents /usr/lib/x86_64-linux-gnu/libcrypto.so.* /opt && \ cp /usr/share/zoneinfo/${TIME_ZONE:-ROC} /opt/etc/localtimeFROM gcr.io/distroless/baseCOPY --from=base /opt /EXPOSE 80ENTRYPOINT ["nginx", "-g", "daemon off; "]

2.构建镜像并查看镜像大小
显而易见,镜像大大减小为23.2M,效果明显
[root@server1 docker]# docker build -t nginx:v5 . [root@server1 docker]# docker images REPOSITORYTAGIMAGE IDCREATEDSIZE nginxv5ea590f5d522fAbout a minute ago23.2MB nginxv451d0075d748620 minutes ago141MB nginxv3cbda333c4f7d25 minutes ago250MB nginxv2e47941468af739 minutes ago252MB nginxv1c3370bb3788aAbout an hour ago276MB

3.构建容器并测试
[root@server1 docker]# docker run -d --name vm1 nginx:v5 50a7f5cf1617d57df98659a99424e327ee529dab1e8b16f2ba222014b64e457a

查看IP
[root@server1 docker]# docker inspect vm1

k8s|Dockerfile镜像优化方案指引
文章图片

[root@server1 docker]# curl172.17.0.3

能正常访问到Nginx默认发布页,证明容器镜像可以正常使用
k8s|Dockerfile镜像优化方案指引
文章图片

    推荐阅读