欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

玩转Docker----- 第二部 (docker镜像优化----四种优化方式)

程序员文章站 2024-01-28 21:45:10
...

玩转Docker----- 第二部 (docker镜像优化----四种优化方式)

1.镜像的优化

  1. 选择最精简的基础镜像
  2. 减少镜像的层数
  3. 清理镜像构建的中间产物
  4. 注意优化网络请求
  5. 尽量去用构建缓存
  6. 使用多阶段构建镜像

2.使用Dockerfile编译安装nginx

做此实验之前,删除之前的所有的test:v*镜像和容器

[aaa@qq.com docker]# docker rmi -f test:v3
Untagged: test:v3				## 删除镜像用rmi,删除容器用rm
[aaa@qq.com docker]# docker rm -f vm1

玩转Docker----- 第二部 (docker镜像优化----四种优化方式)
已经删除干净!!!!!!!!!!!!!!!!!!

由于busybox满足不了nginx的构建需求,所以我们下载rehl7的镜像:

第一步:在当前的docker目录下配置yum源
    注意这里的yum源不能为本地yum源
第二步:编辑Dockerfile,把要做的过程都写进去:
[aaa@qq.com docker]# ls
Dockerfile  nginx-1.18.0.tar.gz  testfile  westos.repo
[aaa@qq.com docker]# vim Dockerfile 
FROM rhel7										# 镜像来自rhel7
EXPOSE 80										# 开放80端口
MAINTAINER 413026125@qq.com						# 维护联系人
COPY dvd.repo /etc/yum.repos.d/					# 配置yum源
RUN rpmdb --rebuilddb							# 重新构建rpm数据库,不然会报错
RUN yum install -y gcc make pcre-devel zlib-devel		# 安装依赖性
ADD nginx-1.18.0.tar.gz /mnt/							# 复制nginx到/mnt并解压
WORKDIR /mnt/nginx-1.18.0								# 进入到/mnt/nginx-1.18.0
RUN ./configure --prefix=/usr/local/nginx				# 预安装
RUN make			
RUN make install										# 编译安装
ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-g","dameon off;"]		# 开启nginx

玩转Docker----- 第二部 (docker镜像优化----四种优化方式)
玩转Docker----- 第二部 (docker镜像优化----四种优化方式)

1.清理缓存,清理中间产物

我们可以看见它有303M, 是比较大的,并且我们再yum安装的时候,在 /var/cache/yum/里面会产生缓存,还有解压后的目录 nginx-1.18.0,安装完之后也是多余的。
所以,我们就可以从这里进行优化,清理中间产物。

[aaa@qq.com docker]# vim Dockerfile 

玩转Docker----- 第二部 (docker镜像优化----四种优化方式)
玩转Docker----- 第二部 (docker镜像优化----四种优化方式)
我们清理缓存,清理中间产物后的v2确实比v1小了!!!!!!!!

2.减少镜像构建层数

由于镜像构建的层数越少,我们的镜像越小。我们当前有12层,我们可以把能放在一起的放在一层去执行。

[aaa@qq.com docker]# docker history nginx:v2
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
2511596b68fd        5 minutes ago       /bin/sh -c #(nop)  ENTRYPOINT ["/usr/local/n…   0B                  
6fafaa218183        5 minutes ago       /bin/sh -c rm -fr /mnt/nginx-1.18.0             0B                  
1d549e105bc7        5 minutes ago       /bin/sh -c make install                         3.88MB              
c263338ff8ef        5 minutes ago       /bin/sh -c make                                 12.4MB              
aae9ee30ffb7        6 minutes ago       /bin/sh -c ./configure --prefix=/usr/local/n…   71.7kB              
15431c1cfa33        6 minutes ago       /bin/sh -c #(nop) WORKDIR /mnt/nginx-1.18.0     0B                  
dfa8e00568a8        6 minutes ago       /bin/sh -c #(nop) ADD file:a90dc1ecadbd423a5…   6.25MB              
47291dc254b3        6 minutes ago       /bin/sh -c yum install -y gcc make pcre-deve…   107MB               
fe9aba5372f9        2 hours ago         /bin/sh -c rpmdb --rebuilddb                    6.64MB              
cfc31b40a0ca        2 hours ago         /bin/sh -c #(nop) COPY file:49ed1264160053e7…   77B                 
90db0f276384        4 hours ago         /bin/sh -c #(nop)  MAINTAINER 823800635@qq.c…   0B                  
3621239158f2        4 hours ago         /bin/sh -c #(nop)  EXPOSE 80                    0B                  
0a3eb3fde7fd        5 years ago                                                         140MB               Imported from -

我们将所有的RUN 都放在了一起,然后将 COPY 和ADD 提前。

玩转Docker----- 第二部 (docker镜像优化----四种优化方式)
玩转Docker----- 第二部 (docker镜像优化----四种优化方式)
我们发现v3又小了!!!!!!!!

3.多阶段构建镜像

因为我们构建nginx的最终目的就是得到 /usr/local/nginx/sbin/nginx 这个二进制程序。
我们可以在镜像A中完成构建的过程,再把二进制程序拷贝到B镜像中去,就极大的优化了空间。

FROM rhel7 as build     #命名为build
EXPOSE 80
MAINTAINER 823800635@qq.com
COPY dvd.repo /etc/yum.repos.d/
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g/g' auto/cc/gcc  && rpmdb --rebuilddb && yum install -y gcc make pcre-devel zlib-devel && yum clean all && ./configure --prefix=/usr/local/nginx && make && make install && rm -fr /mnt/nginx-1.18.0

#######sed -i ‘s/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g/g’ 是关闭debug#######

FROM rhel7
EXPOSE 80
MAINTAINER 823800635@qq.com
VOLUME ["/usr/local/nginx/html"]     #数据卷,这样我们在宿主机上配置发布页面。
COPY --from=build /usr/local/nginx /usr/local/nginx     # 把上面镜像的目录拷贝到这个镜像的目录中
ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-g","dameon off;"]


玩转Docker----- 第二部 (docker镜像优化----四种优化方式)

这样就只剩下了141M了。而且我们的nginx是以rhel7为基础镜像的,所以说nginx只有1M的大小。

4.使用更加精简的基础镜像

我们要构建nginx的新镜像,我们就只需要和nginx运行相关的文件,而在我们上面的例子中,rhel7这个基础镜像还是比较大的,它里面的东西有很多我们是用不上的,所以我们应该在基础镜像比较小的上面运行。

比如:我们在运行apache的时候,就只需要apache的主程序和这些文件就足够了,同理,nginx也是这样。
玩转Docker----- 第二部 (docker镜像优化----四种优化方式)
我们导入两个精简的基础镜像:

[aaa@qq.com ~]# cd rpms/
[aaa@qq.com rpms]# docker load -i distroless.tar
668afdbd4462: Loading layer  18.39MB/18.39MB
Loaded image: gcr.io/distroless/base:latest
[aaa@qq.com rpms]# 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

[aaa@qq.com ~]# ls
anaconda-ks.cfg  docker  rpms
[aaa@qq.com ~]# mkdir distroless
[aaa@qq.com ~]# cd distroless/

[aaa@qq.com distroless]# vim Dockerfile
FROM nginx as base
ARG Asia/Shanghai
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
COPY --from=base /opt /
EXPOSE 80 443
ENTRYPOINT ["nginx","-g","daemon off;"]

[aaa@qq.com distroless]# docker build -t nginx:v5 .

玩转Docker----- 第二部 (docker镜像优化----四种优化方式)
此时就只有26.8M了,所以我们尽量使用精简的基础镜像。

运行一下吧:

[aaa@qq.com distroless]# docker run -d --name nginx nginx:v5
af5fc3cafe2edd04f4735c3d003e1a9831f099ca490552998a1d5d4f315d37fb
[aaa@qq.com distroless]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
af5fc3cafe2e        nginx:v5            "nginx -g 'daemon of…"   18 seconds ago      Up 17 seconds       80/tcp, 443/tcp     nginx
[aaa@qq.com distroless]# docker inspect nginx

玩转Docker----- 第二部 (docker镜像优化----四种优化方式)
访问一下:

玩转Docker----- 第二部 (docker镜像优化----四种优化方式)

有一个问题,为什么我们访问的IP和宿主机IP不在同一网段还可以访问呢?

[aaa@qq.com distroless]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:a5:b1:7f brd ff:ff:ff:ff:ff:ff
    inet 192.168.43.71/24 brd 192.168.43.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
    inet6 2409:8a70:f8a0:af90:20c:29ff:fea5:b17f/64 scope global mngtmpaddr dynamic 
       valid_lft 258761sec preferred_lft 172361sec
    inet6 2409:8a70:fdc2:2e30:20c:29ff:fea5:b17f/64 scope global deprecated mngtmpaddr dynamic 
       valid_lft 867sec preferred_lft 0sec
    inet6 fe80::20c:29ff:fea5:b17f/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:c2:db:2f:bd brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:c2ff:fedb:2fbd/64 scope link 
       valid_lft forever preferred_lft forever
123: aaa@qq.com: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 1a:48:4f:3f:f8:3a brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::1848:4fff:fe3f:f83a/64 scope link 
       valid_lft forever preferred_lft forever

[aaa@qq.com distroless]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242c2db2fbd	no		veth5a0fcd3

上面我们可以看到,启动docker之后就会默认的添加一块docker的网卡设备,我们在访问时,会先通过docker0, 然后再通过本地的回环接口
每开启一个镜像就会多一个veth的网卡设备,它是桥接工具,它会桥接到我们的docker0设备上。

注意:

此时我们的物理机是访问不了的,因为容器和外界是隔离的,我们也没有做端口映射,所以我们应该将容器的80端口映射到server1的80端口上,这样我们的物理机才能访问。

[aaa@qq.com distroless]# docker rm -f c902b9d74141
c902b9d74141
[aaa@qq.com distroless]# docker run -d -p 80:80 --name nginx nginx:v5

玩转Docker----- 第二部 (docker镜像优化----四种优化方式)
80端口打开了
玩转Docker----- 第二部 (docker镜像优化----四种优化方式)

相关标签: 企业实战