玩轉Docker----- 第二部 (docker鏡像優化----四種優化方式)
1.鏡像的優化
- 選擇最精簡的基礎鏡像
- 減少鏡像的層數
- 清理鏡像構建的中間產物
- 注意優化網絡請求
- 儘量去用構建緩存
- 使用多階段構建鏡像
2.使用Dockerfile編譯安裝nginx
做此實驗之前,刪除之前的所有的test:v*鏡像和容器
[root@server1 docker]# docker rmi -f test:v3
Untagged: test:v3 ## 刪除鏡像用rmi,刪除容器用rm
[root@server1 docker]# docker rm -f vm1
已經刪除乾淨!!!!!!!!!!!!!!!!!!
由於busybox滿足不了nginx的構建需求,所以我們下載rehl7的鏡像:
第一步:在當前的docker目錄下配置yum源
注意這裏的yum源不能爲本地yum源
第二步:編輯Dockerfile,把要做的過程都寫進去:
[root@server1 docker]# ls
Dockerfile nginx-1.18.0.tar.gz testfile westos.repo
[root@server1 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
1.清理緩存,清理中間產物
我們可以看見它有303M, 是比較大的,並且我們再yum安裝的時候,在 /var/cache/yum/裏面會產生緩存,還有解壓後的目錄 nginx-1.18.0,安裝完之後也是多餘的。
所以,我們就可以從這裏進行優化,清理中間產物。
[root@server1 docker]# vim Dockerfile
我們清理緩存,清理中間產物後的v2確實比v1小了!!!!!!!!
2.減少鏡像構建層數
由於鏡像構建的層數越少,我們的鏡像越小。我們當前有12層,我們可以把能放在一起的放在一層去執行。
[root@server1 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 提前。
我們發現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;"]
這樣就只剩下了141M了。而且我們的nginx是以rhel7爲基礎鏡像的,所以說nginx只有1M的大小。
4.使用更加精簡的基礎鏡像
我們要構建nginx的新鏡像,我們就只需要和nginx運行相關的文件,而在我們上面的例子中,rhel7這個基礎鏡像還是比較大的,它裏面的東西有很多我們是用不上的,所以我們應該在基礎鏡像比較小的上面運行。
比如:我們在運行apache的時候,就只需要apache的主程序和這些文件就足夠了,同理,nginx也是這樣。
我們導入兩個精簡的基礎鏡像:
[root@server1 ~]# cd rpms/
[root@server1 rpms]# docker load -i distroless.tar
668afdbd4462: Loading layer 18.39MB/18.39MB
Loaded image: gcr.io/distroless/base:latest
[root@server1 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
[root@server1 ~]# ls
anaconda-ks.cfg docker rpms
[root@server1 ~]# mkdir distroless
[root@server1 ~]# cd distroless/
[root@server1 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;"]
[root@server1 distroless]# docker build -t nginx:v5 .
此時就只有26.8M了,所以我們儘量使用精簡的基礎鏡像。
運行一下吧:
[root@server1 distroless]# docker run -d --name nginx nginx:v5
af5fc3cafe2edd04f4735c3d003e1a9831f099ca490552998a1d5d4f315d37fb
[root@server1 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
[root@server1 distroless]# docker inspect nginx
訪問一下:
有一個問題,爲什麼我們訪問的IP和宿主機IP不在同一網段還可以訪問呢?
[root@server1 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: veth5a0fcd3@if122: <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
[root@server1 distroless]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242c2db2fbd no veth5a0fcd3
上面我們可以看到,啓動docker之後就會默認的添加一塊docker的網卡設備,我們在訪問時,會先通過docker0, 然後再通過本地的迴環接口
每開啓一個鏡像就會多一個veth的網卡設備,它是橋接工具,它會橋接到我們的docker0設備上。
注意:
此時我們的物理機是訪問不了的,因爲容器和外界是隔離的,我們也沒有做端口映射,所以我們應該將容器的80端口映射到server1的80端口上,這樣我們的物理機才能訪問。
[root@server1 distroless]# docker rm -f c902b9d74141
c902b9d74141
[root@server1 distroless]# docker run -d -p 80:80 --name nginx nginx:v5
80端口打開了