镜像化带来的容器重启问题。因为镜像是一体的,哪怕只是有一点点修改,镜像的发布都必须销毁之前的容器,然后按新镜像创建新的容器;精简镜像大小的好处不言而喻,既节省了存储空间,又能节省带宽,加快传输。
Docker的镜像采用分层的结构,最下面的base镜像提供最基本的运行环境,然后像搭积木一样一层一层往上加,所以精简镜像最有效的办法就是:1. 尽量选择最小的base image; 2. 减少镜像的层数;
选择最精简的Base Image
-
通常情况下,常用的Linux镜像一般有ubuntu, centos, debian, 其中debian更轻量,而且够用,对比如下:
REPOSITORY TAG IMAGE ID VIRTUAL SIZE gliderlabs/alpine latest 9cfff538e583 4.803 MB debian latest 19134a8202e7 123.1 MB ubuntu latest 104bec311bcd 129 MB centos latest 67591570dd29 191.8 MB
-
当选择编译的语言能生成静态原生 ELF 文件,比如C/C++,比如 Go,就可以选择下列超小的image, 或者直接是个空镜像
scratch
:scratch: 一个空镜像,只能用于构建镜像,通过 FROM scratch;
busybox: 包含了常用的 UNIX 工具, 非常方便构建小镜像;
docker-alpine: A super small Docker image based on Alpine Linux. The image is only 5 MB and has access to a package repository that is much more complete than other BusyBox based images.
REPOSITORY TAG IMAGE ID VIRTUAL SIZE gliderlabs/alpine latest 9cfff538e583 4.803 MB busybox latest c75bebcdd211 1.11 MB
例如,基于一个空的基础镜像完成一个redis的镜像:
- 使用
ldd
命令查看redis-server
共享的依赖库
ldd redis-3.0.0/src/redis-server linux-vdso.so.1 => (0x00007fffde365****00) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f307d5aa000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f307d38c000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f307cfc6000) /lib64/ld-linux-x86-64.so.2 (0x00007f307d8b9000)
- 打包所有的
.so
动态库
cd / tar zcvf rootfs.tar.gz \ usr/local/bin/redis-server \ lib/x86_64-linux-gnu/libm.so.6 \ lib/x86_64-linux-gnu/libpthread.so.0 \ lib/x86_64-linux-gnu/libc.so.6 \ lib64/ld-linux-x86-64.so.2
- dockerfile构建镜像
FROM scratch ADD rootfs.tar.gz / COPY redis.conf /etc/redis/redis.conf EXPOSE 6379 CMD ["redis-server"]
查看大小,才7.73M
redis latest c76bebcdd211 7.73 MB
使用&&串联Dockerfile
记住:在 Dockerfile 中, 每一条指令都会创建一个镜像层,继而会增加整体镜像的大小。
- 用&&串联指令(一般是RUN指令)
- 安装完软件记得clean
FROM debian:wheezy
RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*