Linux——写一个Dockerfile构建镜像优化

Docker镜像分层(基于AUFS构建)

Dockerfile中的每个指令都会创建一个新的镜像层
镜像层将被缓存和复用
当dockerfile的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效
某一层的镜像缓存失效之后,它之后的镜像缓存都会失效
镜像层是不可变的,如果在某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件

AUFS是一种联合文件系统。它使用同一个Linux
host上的多个目录,逐个堆叠起来,对外呈现出一个统一的文件系统。AUFS使用该特性,实现了Docker镜像的分层.
AUFS特性也是docker镜像分层的原理
在这里插入图片描述
container容器层-读写执行层
add apache image 镜像层:固化了一个标准运行环境包含服务和依赖的组件
centos base image基础镜像层(操作系统环境镜像)
lxc,aufs,bootfs内核层:底层依赖的库,负责与内核交互

docker镜像位于bootfs之上
每一层镜像的下一次成为父镜像
第一层镜像成为baseimage
容器层在最顶层
Docker将readonly的FS层称为image
bootfs(boot file system):主要包含bootloader和kernel
bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs
这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内村的使用权已由bootfs转交给内核,此时系统也会卸载bootfs
rootfs(root file system):在bootfs之上(base images)
包含的就是典型的Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件
rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等

为什么centos的Docker镜像只有200M多一点?
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就行了。由此可见对于不同的Linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs

Dockerfile

Dockerfile是由一组指令组成的文件
Dockerfile结构四部分
基础镜像信息(指定操作系统镜像是什么镜像,什么版本)
维护者信息(可选:谁写的)
镜像操作指令
容器启动时执行指令(启动容器的时候,执行的脚本/命令参数等等)
dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用#开头注释

Dockerfile操作指令

指令 含义
FROM镜像 指定新镜像所基于的镜像,第一条指令必须为FROM指令,每创建一个镜像就需要一条FROM指令
MAINTAINER名字 说明新镜像的维护人信息
RUN命令 在所基于的镜像上执行命令,并提交到新的镜像中
CMD[“要运行的程序”,“参数1”,“参数2”] 指令启动容器时要运行的命令或者脚本,Dockerfile只能有一条CMD命令,如果指定多条则只能最后一条被执行
EXPOSE端口号 指定新镜像加载到Docker时要开启的端口
ENV环境变量 变量值 设置一个环境变量的值,会被后面的RUN使用
ADD 源文件/目录 目标文件/目录 将源文件复制到目标文件,源文件要与Dockerfile位于相同目录中,或者是一个URL
COPY 源文件/目录 目标文件/目录 将本地主机上的文件/目录复制到目标地点,源文件/目录要与Dockerfile在相同的目录中
VOLUME[“目录”] 在容器中创建一个挂载点
USER用户名/UID 指定运行容器时的用户
WORKDIR路径 为后续的RUN、CMD、ENTRYPOINT指定工作目录
ONBUILD命令 指定所生成的镜像作为一个基础镜像时所要运行的命令

dockerfile文件中CMD和EMTRYPOINT的区别?
EMTRYPOINT容器启动后执行的命令,让容器执行表现的像一个可执行程序一样,与CMD的区别是:ENTRYPOINT不会被docker run覆盖,会把docker run后面的参数,如:$name等,当作传递给ENTRYPOINT指令的参数。dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。docker run命令的 -entrypoint参数可以把指定的参数继续传递给ENTRYPOINT

ADD与COPY的区别
COPY:仅用于复制
资源消耗方面 COPY小于ADD

Dockerfile构建镜像的过程

在通过dockerfile构建一个镜像的时候
build过程中会对每一条RUN指令,构建一个镜像开启一个临时容器,来运行这个指令(用于检测有没有问题、缓存)
将以上的环境缓存在下一个readonly image层中
最后到container容器层的时候用有上面执行的所有环境以及更改操作,所以docker run -itd 镜像ID /bin/bash执行的时候就相当与执行容器层

Docker镜像的创建

拷贝nginx-1.12.0源码包到nginx/中
vim Dockerfile

基于基础镜像
FROM centos:7
用户信息(随便编写)
MAINTAINER this is nginx image
添加环境包
RUN yum install -y update
RUN yum install -y pcre-devel zlib-devel gcc gcc-c++ make
RUN useradd -M -s /sbin/nolongin nginx
下载nginx软件包
ADD nginx-1.12.0.tar.gz /usr/local/src
WORKDIR /usr/local/src
指定工作目录
WORKDIR nginx-1.12.0
RUN ./configure
–prefix=/usr/local/nginx
–user=nginx
–group=nginx
–with-http_stub_status_module && make && make install
ENV PATH /usr/local/nginx/sbin:$PATH
指定http和https端口
EXPOSE 80
EXPOSE 443
RUN echo “daemon off;”>>/usr/local/nginx/conf/nginx.conf
添加宿主机中run.sh到容器中
ADD run.sh /run.sh
RUN chmod 755 /run.sh
CMD ["/run.sh"]

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

ROM centos:7 as build
ADD nginx-1.15.9.tar.gz /mnt
WORKDIR /mnt/nginx-1.15.9
RUN yum install -y gcc pcre-devel zlib-devel make &> /dev/null && yum clean all && sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g" /g' auto/cc/gcc && ./configure --prefix=/usr/local/nginx &>/dev/null && make &>/dev/null && make install &>/dev/null && rm -rf /mnt/nginx-1.15.8
FROM centos:7
EXPOSE 80
VOLUME ["/usr/ local/ngihx/html"]
COPY --from=build /usr/local/nginx /usr/local/nginx
CMD ["/usr/local/nginx/sbin/nginx","-g", "daemon off;"]

docker build -t "nginx:v4" .

猜你喜欢

转载自blog.csdn.net/weixin_53496398/article/details/117524232