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

Docker镜像构建的四种优化方式

程序员文章站 2022-03-30 07:52:47
...

镜像构建的优化

###删除之间的所有的test:v*镜像和容器(参考上一篇Docker容器的安装配置,以及 Dockerfile 的使用方法)###

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

构建nginx镜像

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

[aaa@qq.com ~]# docker load -i rhel7.tar 
e1f5733f050b: Loading layer [==================================================>]  147.1MB/147.1MB
[aaa@qq.com ~]# cd docker/
[aaa@qq.com docker]# vim Dockerfile 

FROM rhel7			# 镜像来自rhel7
EXPOSE 80			# 开放80端口
MAINTAINER aaa@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

[aaa@qq.com docker]# cp /etc/yum.repos.d/westos.repo ./dvd.repo      # 建立yum源
[aaa@qq.com docker]# ls
Dockerfile  dvd.repo  nginx-1.18.0.tar.gz  testfile
[aaa@qq.com docker]# docker build -t nginx:v1 .				进行构建
## 这里我们可以看到dockerfie里面的各个步骤
Step 1/12 : FROM rhel7
 ---> 0a3eb3fde7fd
Step 2/12 : EXPOSE 80
 ---> Using cache
 ---> d08b343a793d
Step 3/12 : MAINTAINER aaa@qq.com
 ---> Using cache
 ---> 017f4b147a32
Step 4/12 : COPY dvd.repo /etc/yum.repos.d/
 ---> Using cache
 ---> f5d2b9218060
Step 5/12 : RUN rpmdb --rebuilddb
 ---> Running in 163a4532bf45
Removing intermediate container 163a4532bf45
 ---> c0387a3e3e69
Step 6/12 : RUN yum install -y gcc make pcre-devel zlib-devel
 ---> Running in e2d387cdc0b9
Step 7/12 : ADD nginx-1.18.0.tar.gz /mnt/
 ---> 000ce03c7c4e
Step 8/12 : WORKDIR /mnt/nginx-1.18.0
 ---> Running in e539b8ed9a67
Removing intermediate container e539b8ed9a67
 ---> 9ea9d4c3ff3f
Step 9/12 : RUN ./configure --prefix=/usr/local/nginx
 ---> Running in 261812c201ce
Step 10/12 : RUN make
Step 11/12 : RUN make install
Step 12/12 : ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-g","dameon off;"]
 ---> Running in 873edc7d9d94
Removing intermediate container 873edc7d9d94
 ---> 9b7f0c89bf98
Successfully built 9b7f0c89bf98
Successfully tagged nginx:v1

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

[aaa@qq.com docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               v1                  9b7f0c89bf98        3 minutes ago       303MB
## 他现在有303M 是比较大的
因为我们再yum安装的时候会产生缓存,再 /var/cache/yum/里,
还有解压后的目录 nginx-1.18.0

那我们就可以从这里进行优化。
清理中间产物。

[aaa@qq.com docker]# vim Dockerfile 

RUN yum install -y gcc make pcre-devel zlib-devel && yum clean all			清理缓存
RUN rm -fr /mnt/nginx-1.18.0		删除中间产物

[aaa@qq.com docker]# docker build -t nginx:v2 .
[aaa@qq.com docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               v2                  aa029b13d29a        12 seconds ago      277MB
nginx               v1                  9b7f0c89bf98        11 minutes ago      303MB
变小了。

2.减少镜像构建层数

[aaa@qq.com docker]# docker history nginx:v2 
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
aa029b13d29a        2 minutes ago       /bin/sh -c #(nop)  ENTRYPOINT ["/usr/local/n…   0B                  
168fc81963e5        2 minutes ago       /bin/sh -c rm -fr /mnt/nginx-1.18.0             0B                  
32531153adcf        2 minutes ago       /bin/sh -c make install                         3.88MB              
afa9d1979fe6        2 minutes ago       /bin/sh -c make                                 12.4MB              
d7fb616f785c        3 minutes ago       /bin/sh -c ./configure --prefix=/usr/local/n…   71.7kB              
1c8cc01a2f4b        3 minutes ago       /bin/sh -c #(nop) WORKDIR /mnt/nginx-1.18.0     0B                  
e7cabc8289c4        3 minutes ago       /bin/sh -c #(nop) ADD file:46b14d1c307d23f50…   6.25MB              
551102a70245        3 minutes ago       /bin/sh -c yum install -y gcc make pcre-deve…   107MB               
c0387a3e3e69        15 minutes ago      /bin/sh -c rpmdb --rebuilddb                    6.64MB              
f5d2b9218060        18 minutes ago      /bin/sh -c #(nop) COPY file:2b3dce3b05892ae2…   76B                 
017f4b147a32        18 minutes ago      /bin/sh -c #(nop)  MAINTAINER aaa@qq.com…   0B                  
d08b343a793d        18 minutes ago      /bin/sh -c #(nop)  EXPOSE 80                    0B                  
0a3eb3fde7fd        5 years ago                                                         140MB               Imported from -

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

FROM rhel7
EXPOSE 80
MAINTAINER aaa@qq.com
COPY dvd.repo /etc/yum.repos.d/
ADD nginx-1.18.0.tar.gz /mnt
WORKDIR /mnt/nginx-1.18.0
RUN 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
ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-g","dameon off;"]

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

[aaa@qq.com docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               v3                  db577ca1f8c7        6 seconds ago       258MB
nginx               v2                  aa029b13d29a        15 minutes ago      277MB
nginx               v1                  9b7f0c89bf98        27 minutes ago      303MB

又小了19M.

3.多阶段构建镜像

  • 我们构建nginx的最终目的就是得到 /usr/local/nginx/sbin/nginx 这个二进制程序。
    我们可以再镜像A中完成构建的过程,再把二进制程序拷贝到B镜像中去,就极大的优化了空间。
FROM rhel7 as build         #命名为build
EXPOSE 80
MAINTAINER aaa@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

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

sed -i ‘s/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g/g’ 是关闭debug。也能减小。

Successfully tagged nginx:v4
[aaa@qq.com docker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               v4                  a68855981d36        6 seconds ago       141MB
<none>              <none>              3f21fd924668        8 seconds ago       255MB
nginx               v3                  db577ca1f8c7        20 minutes ago      258MB
nginx               v2                  aa029b13d29a        35 minutes ago      277MB
nginx               v1                  9b7f0c89bf98        About an hour ago   303MB
rhel7               latest              0a3eb3fde7fd        5 years ago         140MB

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

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

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

比如:
Docker镜像构建的四种优化方式
我们运行apache,就只需要apache的主程序和这些文件就足够了,nginx也相同。

我们导入两个精简的基础镜像:

[aaa@qq.com ~]# docker load -i distroless.tar 
668afdbd4462: Loading layer [==================================================>]  18.39MB/18.39MB
Loaded image: gcr.io/distroless/base:latest
[aaa@qq.com ~]# 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 ~]# 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 .
[aaa@qq.com distroless]# docker images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
nginx                    v5                  2e1946a440c2        5 seconds ago       26.8MB
<none>                   <none>              715d6019c6ad        6 seconds ago       119MB
nginx                    v4                  a68855981d36        About an hour ago   141MB
<none>                   <none>              3f21fd924668        About an hour ago   255MB
nginx                    v3                  db577ca1f8c7        About an hour ago   258MB
nginx                    v2                  aa029b13d29a        2 hours ago         277MB
nginx                    v1                  9b7f0c89bf98        2 hours ago         303MB

此时就只有26.8M了,所以我们尽量使用精简的基础镜像。

运行:

[aaa@qq.com distroless]# docker run -d --name nginx nginx:v5
40f023d69a69af8912e45dbb5f651dbf33aea67ccf0686f957449e41752963e9
[aaa@qq.com distroless]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
40f023d69a69        nginx:v5            "nginx -g 'daemon of…"   5 seconds ago       Up 4 seconds        80/tcp, 443/tcp     nginx
[aaa@qq.com distroless]# docker inspect nginx		检查容器
...
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",		# 它的ip地址为这个
...

#访问:
[aaa@qq.com distroless]# curl 172.17.0.2
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
这里为什么和本机不再同一ip还可以访问哪?

[aaa@qq.com distroless]# ip a

2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:e4:9b:44 brd ff:ff:ff:ff:ff:ff
    inet 172.25.254.1/24 brd 172.25.254.255 scope global ens3
       valid_lft forever preferred_lft forever
    inet6 fe80::5054:ff:fee4:9b44/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:26:3d:ce:55 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:26ff:fe3d:ce55/64 scope link 
       valid_lft forever preferred_lft forever
9: aaa@qq.com: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether a2:c8:79:b7:7b:f3 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::a0c8:79ff:feb7:7bf3/64 scope link 
       valid_lft forever preferred_lft forever

启动docker之后就会默认添加docker的设备。访问时先通过docker0 再通过本地的回环接口

每开启一个镜像就会多一个veth的网卡设备。,它会桥接到docker0设备上

[aaa@qq.com distroless]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242263dce55	no		veth0df22f1
看到了吧。

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

[aaa@qq.com distroless]# cd 
[aaa@qq.com ~]# docker run -d -p 80:80 --name nginx nginx:v5
28c25d9ff5b5ecede72238d94fb315471bf00c47b92b4f89b7972fd674e90cbb
[aaa@qq.com ~]# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      2992/sshd           
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      3103/master         
tcp6       0      0 :::80                   :::*                    LISTEN      5414/docker-proxy   
tcp6       0      0 :::22                   :::*                    LISTEN      2992/sshd           
tcp6       0      0 ::1:25                  :::*                    LISTEN      3103/master 

可见80端口打开了,通过docker-proxy
Docker镜像构建的四种优化方式
就可以访问了