镜像的优化可以减少客户端下载时候的带宽
已经选择了精简的镜像,所以减少镜像的层数,可以把之前的RUN合并在一起。将WORKDIR切换成在RUN底下的cd
之前的Dockerfile:
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY dvd.repo /etc/yum.repos.d/dvd.repo
RUN rpmdb --rebuilddb
RUN yum install -y gcc pcre-devel zlib-devel
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN ./configure --prefix=/usr/local/nginx
RUN yum install make -y
RUN make
RUN make install
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
减少镜像层数后:
[root@docker1 docker]# cat Dockerfile
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY dvd.repo /etc/yum.repos.d/dvd.repo
ADD nginx-1.18.0.tar.gz /mnt
RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel && cd /mnt/nginx-1.18.0 && ./configure --prefix=/usr/local/nginx && yum install make -y && make && make install
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
清理中间产物:/var/cache/yum yum的缓存路径,nginx安装包删掉,编译完了make gcc都可以删掉(安装make这些包时候会安装依赖性,但是删掉时候不删掉依赖性)
[root@docker1 docker]# cat Dockerfile
FROM rhel7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY dvd.repo /etc/yum.repos.d/dvd.repo
ADD nginx-1.18.0.tar.gz /mnt
RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make && cd /mnt/nginx-1.18.0 && ./configure --prefix=/usr/local/nginx && make && make install && rm -fr /mnt/nginx-1.18.0 /var/cache/yum
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
[root@docker1 docker]# docker build -t webserver:v2 .
优化后镜像大小差距:
[root@docker1 docker]# docker images webserver
REPOSITORY TAG IMAGE ID CREATED SIZE
webserver v2 503439033877 24 seconds ago 258MB
webserver v1 bdd2829a42e3 36 minutes ago 346MB
[root@docker1 docker]# docker images rhel7
rhel7 latest 0a3eb3fde7fd 7 years ago 140MB
优化了:346-258,除去基础base镜像140,还是多了
可以看出多的主要在Yum里面111MB,该层主要安装包编译等
[root@docker1 docker]# docker history webserver:v2
IMAGE CREATED CREATED BY SIZE COMMENT
503439033877 6 minutes ago /bin/sh -c #(nop) CMD ["/usr/local/nginx/sb… 0B
c140026256fd 6 minutes ago /bin/sh -c rpmdb --rebuilddb && yum install … 111MB
8b163bc5912e 7 minutes ago /bin/sh -c #(nop) ADD file:a90dc1ecadbd423a5… 6.25MB
b17ef4913f9c 48 minutes ago /bin/sh -c #(nop) COPY file:fe5cdcb63a06bd4c… 67B
82ca7e5c38e6 49 minutes ago /bin/sh -c #(nop) VOLUME [/usr/local/nginx/… 0B
8aa3b0c110c7 49 minutes ago /bin/sh -c #(nop) EXPOSE 80 0B
0a3eb3fde7fd 7 years ago 140MB Imported from -
可以看出v1没有优化的时候,光yum代码。
[root@docker1 docker]# docker history webserver:v1
IMAGE CREATED CREATED BY SIZE COMMENT
bdd2829a42e3 44 minutes ago /bin/sh -c #(nop) CMD ["/usr/local/nginx/sb… 0B
9e03306cbffd 44 minutes ago /bin/sh -c yum install make -y 43.6MB
bf1e3007a03b 49 minutes ago /bin/sh -c yum install -y gcc pcre-devel zli… 133MB
源码编译后,真正只需要编译后的二进制代码
所以,我真正只需要/usr/local/nginx的二进制代码只有5M,其余的(中间产物)不需要,再把debug一关不到1M
可以只把操作系统编译好的源码(二进制代码)给其它操作系统直接使用
分两个部分,先在一个容器编译好二进制代码再拷贝给第二个容器使用
将debug注释掉
[root@docker1 nginx-1.18.0]# vim auto/cc/gcc
[root@docker1 nginx-1.18.0]# sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc
全部替换完成
将该指令添加到Dockerfile中,并且多阶段构建(将上一个容器编译后的nginx的二进制编码拿来使用)
as build是给上面起名build
COPY --from=build /usr/local/nginx /usr/local/nginx 将上一个容器的二进制编码目录(/usr/local/nginx)放在下一个容器的/usr/local/nginx
暴露端口和卷都不是必须的所以删掉了,编一个最精简的Dockerfile
[root@docker1 docker]# cat Dockerfile
FROM rhel7 as build
COPY dvd.repo /etc/yum.repos.d/dvd.repo
ADD nginx-1.18.0.tar.gz /mnt
RUN rpmdb --rebuilddb && yum install -y gcc pcre-devel zlib-devel make && cd /mnt/nginx-1.18.0 && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx && make && make install && rm -fr /mnt/nginx-1.18.0 /var/cache/yum
FROM rhel7
COPY --from=build /usr/local/nginx /usr/local/nginx
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
[root@docker1 docker]# docker build -t webserver:v3 .
除去140MB的基础镜像base,一个nginx 1MB
[root@docker1 docker]# docker images webserver
REPOSITORY TAG IMAGE ID CREATED SIZE
webserver v3 5cd6dd1fdc7f 31 seconds ago 141MB
webserver v2 503439033877 35 minutes ago 258MB
webserver v1 bdd2829a42e3 About an hour ago 346MB
docker 能运行肯定nginx没问题,有问题CMD都报错了
[root@docker1 docker]# docker run -d --name nginx webserver:v3
[root@docker1 docker]# docker container inspect nginx | grep "IPAddress"
"IPAddress": "172.17.0.2",
[root@docker1 docker]# curl 172.17.0.2
<h1>Welcome to nginx!</h1>
再优化都不可能比base镜像小
所以,在优化需要寻找更加精简的base,通过https://hub.docker.com/寻找或www.github.com或www.gitee.com上面寻找
nginx在运行时候,会调用系统的动态库文件
库文件必不缺的,缺了二进制文件就起不来了。
所以在拷贝二进制文件目录的时候把库文件也要考入,同时编译的nginx不同调用的库文件也不同,加了opensll还有lib-opensll库,所以如果换取更小的镜像的话,需要把库文件和二进制文件同时迁移。同时还要考虑这些库文件有无依赖性还要调用其他的库文件。
[root@docker1 docker]# docker run -it --rm webserver:v3 bash
bash-4.2# ldd /usr/local/nginx/sbin/nginx
linux-vdso.so.1 => (0x00007ffc06f6d000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f3560c8a000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f3560a6e000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f3560837000)
libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f35605d6000)
libz.so.1 => /lib64/libz.so.1 (0x00007f35603c0000)
libc.so.6 => /lib64/libc.so.6 (0x00007f355ffff000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3560e8e000)
libfreebl3.so => /lib64/libfreebl3.so (0x00007f355fd80000)
在github上面搜索distroless,这个是谷歌的容器工具。
下载
我用的是debian10,导入镜像。
[root@docker1 docker]# docker load -i base-debian10.tar
这个base镜像小
[root@docker1 docker]# docker images
gcr.io/distroless/base-debian10 latest d48fcdd54946 52 years ago 19.2MB
首先在github搜索distroless nginx,进去
然后查看别人写好的Dockerfile,可以看出用的是官方提供的最小镜像并且是多阶段构建,以及将系统的库文件考入。
编写Dockerfile2
[root@docker1 docker]# cat Dockerfile2
FROM nginx:1.18.0 as base
# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ARG TIME_ZONE
RUN 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 /usr/sbin/nginx-debug /opt && \
cp -a --parents /lib/x86_64-linux-gnu/ld-* /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* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libdl* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libpthread* /opt && \
cp -a --parents /lib/x86_64-linux-gnu/libcrypt* /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/localtime
FROM gcr.io/distroless/base-debian10
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx", "-g", "daemon off;"]
构建镜像,-f指定dockerfile2,要不然读取的是默认的Dockerfile
[root@docker1 docker]# docker build -t webserver:v4 -f Dockerfile2 .
效果
[root@docker1 docker]# docker images webserver
REPOSITORY TAG IMAGE ID CREATED SIZE
webserver v4 0fce27d5ac56 15 seconds ago 31.7MB
运行容器,运行成功。
[root@docker1 docker]# docker run -d --name nginx webserver:v4
[root@docker1 docker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
79bc3e329d8f webserver:v4 "nginx -g 'daemon of…" 23 seconds ago Up 22 seconds 80/tcp, 443/tcp nginx
[root@docker1 docker]# docker inspect nginx | grep IP
"IPAddress": "172.17.0.2",
访问成功
[root@docker1 docker]# curl 172.17.0.2
<h1>Welcome to nginx!</h1>