最近遇到了 Docker 镜像体积过大的问题,对于部署、移交相当麻烦和慢。于是就抽点时间研究下了怎么减小 Docker 镜像的体积。
下面我以手动编译 nginx 镜像作为例子来减小镜像体积,nginx 的版本是 1.10.2,并且下载到了当前目录。
下图是各种 Dockerfile 制作出镜像的效果
FROM centos:7.2.1511
COPY . /tmp/
RUN yum install -y make \
gcc \
openssl-devel \
zlib-devel \
perl-devel \
pcre-devel && \
cd /tmp/ && tar zxf nginx-1.10.2.tar.gz && \
cd /tmp/nginx-1.10.2 && \
./configure --with-http_gzip_static_module --with-http_ssl_module && \
make && make install && \
rm -rf /tmp/* && \
ln -sf /dev/stdout /usr/local/nginx/logs/access.log && \
ln -sf /dev/stderr /usr/local/nginx/logs/error.log
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
上述就是一个最基本的 nginx 镜像了,通过 docker build
后,镜像大小是 535.2MB。nginx 的源代码才 890KB,这种镜像,完全是浪费空间。
FROM alpine:3.4
COPY . /tmp/
RUN apk update && \
apk add gcc make openssl-dev zlib-dev perl-dev pcre-dev libc-dev && \
cd /tmp/ && tar zxf nginx-1.10.2.tar.gz && \
cd /tmp/nginx-1.10.2 && \
./configure --with-http_gzip_static_module --with-http_ssl_module && \
make && make install && \
rm -rf /tmp/* && \
ln -sf /dev/stdout /usr/local/nginx/logs/access.log && \
ln -sf /dev/stderr /usr/local/nginx/logs/error.log
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
通过上述的 Dockerfile docker build
出来的镜像大小是 155.8MB,体积已经缩小到了 3 倍以上了,对于 nginx 的运行来说,centos 和 Alpine 完全是一样的效果,所以对于基础镜像,首选应该是 Alpine 这之类的精简版系统,而且在官方 hub 上的官方镜像,大多有提供 Alpine 版的版本。
COPY . /tmp/
RUN yum install -y make
gcc
openssl-devel
zlib-devel
perl-devel
pcre-devel &&
cd /tmp/ && tar zxf nginx-1.10.2.tar.gz &&
cd /tmp/nginx-1.10.2 &&
./configure --with-http_gzip_static_module --with-http_ssl_module &&
make && make install &&
yum remove -y gcc openssl-devel zlib-devel perl-devel pcre-devel make &&
yum clean all &&
rm -rf /tmp/* &&
ln -sf /dev/stdout /usr/local/nginx/logs/access.log &&
ln -sf /dev/stderr /usr/local/nginx/logs/error.log
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
上面的 `yum remove -y gcc openssl-devel zlib-devel perl-devel pcre-devel make` 和 `yum clean all` 就是移除不需要的文件,从而进一步减小体积,加上两条命令后,执行 `docker build` 后的镜像的体积为 413.8MB,相对上述的 535.2MB 减小了 121.4 MB。
<div id="build-dependence-file-alpine"></div>
## Alpine 基础镜像的依赖
上述 centos 的移除依赖的后体积变化可能看着没有啥感觉,因为本身就很大,下面是 Alpine 的 Dockerfile
```Dockerfile
FROM alpine:3.4
COPY . /tmp/
RUN apk update && \
apk add gcc make openssl-dev zlib-dev perl-dev pcre-dev libc-dev && \
cd /tmp/ && tar zxf nginx-1.10.2.tar.gz && \
cd /tmp/nginx-1.10.2 && \
./configure --with-http_gzip_static_module --with-http_ssl_module && \
make && make install && \
apk del gcc make openssl-dev zlib-dev perl-dev pcre-dev libc-dev && \
rm -rf /var/cache/* && \
rm -rf /tmp/* && \
ln -sf /dev/stdout /usr/local/nginx/logs/access.log && \
ln -sf /dev/stderr /usr/local/nginx/logs/error.log
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
这次 docker build
出来的镜像的体积为 11.74MB,直接从 155.8MB 减小了 144.04 MB,达到了数量级的变化。并且这个 11.74MB 的镜像也是可以正常运行的。
那么对于一些需要通过 COPY 命令的方式拷贝到镜像里面的文件,可以使用 wget 的方式,下载到镜像里,然后使用完之后就删掉。
## centos ```Dockerfile FROM centos:7.2.1511RUN yum install -y make
gcc
openssl-devel
zlib-devel
perl-devel
pcre-devel
wget &&
wget --no-check-certificate -O /tmp/nginx-1.10.2.tar.gz http://nginx.org/download/nginx-1.10.2.tar.gz &&
cd /tmp/ && tar zxf nginx-1.10.2.tar.gz &&
cd /tmp/nginx-1.10.2 &&
./configure --with-http_gzip_static_module --with-http_ssl_module &&
make && make install &&
rm -rf /tmp/* &&
ln -sf /dev/stdout /usr/local/nginx/logs/access.log &&
ln -sf /dev/stderr /usr/local/nginx/logs/error.log
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
上述通过 wget 的下载方式将 nginx 的源代码下载到了镜像里面,然后使用完之后,再删除掉,这样对于镜像来说,将不会存在 nginx 的源代码。通过此方法 `docker build` 出来的镜像是 534.8MB,相对于最原始的 535.2MB,少了一丢丢,这种方式随着文件的大小增大,效果显著。
<div id="level-alpine"></div>
## Alpine
```Dockerfile
FROM alpine:3.4
RUN apk update && \
apk add gcc make openssl-dev zlib-dev perl-dev pcre-dev libc-dev wget && \
wget --no-check-certificate -O /tmp/nginx-1.10.2.tar.gz http://nginx.org/download/nginx-1.10.2.tar.gz && \
cd /tmp/ && tar zxf nginx-1.10.2.tar.gz && \
cd /tmp/nginx-1.10.2 && \
./configure --with-http_gzip_static_module --with-http_ssl_module && \
make && make install && \
rm -rf /tmp/* && \
ln -sf /dev/stdout /usr/local/nginx/logs/access.log && \
ln -sf /dev/stderr /usr/local/nginx/logs/error.log
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
通过 docker build
后,镜像大小为 155.4MB,因为 Alpine 的体积本身很小,所以效果不明显。
COPY . /code
RUN rm -rf /code
CMD ["tail", "-f", "/etc/hosts"]
基础镜像采用的是 Alpine,对于 2.3GB 来说,基础的镜像的体积可以忽略。`docker build` 出来的镜像体积是 2.463GB,可以看到,虽然通过 `rm -rf /code` 将文件删除了,但是由于 docker 镜像是分层的原因,所以镜像的依旧包含了 COPY 进去的文件的体积,虽然文件在 `docker run` 时是看不到的。
<div id="bigfile-by-wget"></div>
### 通过 wget
```Dockerfile
FROM alpine:3.4
RUN apk update && apk add wget && \
mkdir /code && \
wget --no-check-certificate -O /code/test.dbf http://172.24.4.188:8000/test.dbf && \
apk del wget && \
rm -rf /var/cache/* && \
rm -rf /code
CMD ["tail", "-f", "/etc/hosts"]
通过此方法 docker build
出来的镜像体积为 4.817MB,相对于 Alpine 的基础镜像 4.799MB,只增加了 0.018MB。相对于上述的 COPY 完全是质的变化。
通过 find / -name "*.py[co]" -exec rm '{}' ';'
就可以全都移除掉