docker镜像相关原理,镜像构建,Dockerfile常用命令

Posted Leo Han

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了docker镜像相关原理,镜像构建,Dockerfile常用命令相关的知识,希望对你有一定的参考价值。

我们知道,传统的开发部署流程是,开发将程序开发完成之后,编写相关的部署文档,然后将程序部署包和部署文档交给运维,运维根据部署文档在生产环境部署程序,但是经常会出现的问题是,程序在开发的环境能够正常运行但是在生产的环境却运行不了,给运维带来了极大的难度。这个问题主要的原因是在于二者的运行环境导致。
而docker的出现带来了便利,docker中的交付不在是一个部署程序,而是部署程序和其对应的环境,交付的是一个镜像。

docker镜像实际上一层一层的文件系统组成,称为unionFS(联合文件系统)。
一般我们常见的linux系统中有如下两个文件系统很重要:bootfs 和 rootfs。
bootfs主要包含bootloader和kernel,bootloader加载kernel,Linux系统启动的时候会加载bootfs文件系统,docker镜像的最底层就是bootfs。这一层与我们典型的Linux系统是一样的,包含boot加载器和内核,当boot加载完之后,整个内核都在内存中了,此时内存的使用权由bootfs转交给内核,系统也会在此时卸载bootfs。
rootfs,在bootfs之上,包含典型的linux系统中的/dev,/proc,/bin,/etc等标准目录和文件,rootfs就是各种不同发型版本的linux,如unbantu,centos
一个精简的系统,rootfs可以很小,只需要最基本的命令、工具和程序库即可,底层可以直接用宿主机的kernel,只需要提供rootfs,因此,不同的linux发行版本,boofs基本一致的,rootfs会有差别,不同发行版本可以公用bootfs

在这里插入图片描述

在这里插入图片描述

docker底层使用的是宿主机的bootfs,因此加载速度会特别快,秒级
docker在bootfs上使用自己的rootfs,称为base image,即所谓的基础镜像,然后在上面可以叠加其他镜像。
我们一般安装centos系统都需要几个G大小,但是docker下载的centos镜像却只需要几百兆,这就是这个原因,docker的centos镜像只需要rootfs,不需要bootfs。

docker中采用分层镜像,能够最大程度的共享资源。如果有多个镜像都从相同的基础镜像构建而来,那么在宿主机上只需要保留一份基础镜像,同时内存中也只需要加载一份基础镜像,就可以为所有的容器服务,而且镜像的每一层都可以被共享。
docker中镜像都是可读的,当docker容器启动的时候,一个新的可写层被加载到镜像的顶部,这层通常称为容器层,容器层之下的都称为镜像层
一般我们构建docker镜像大部分使用Dockerfile构建,构建流程大致如下:
docker执行Dockerfile的大致流程:

  1. docker从基础镜像上运行一个容器
  2. 执行一条指令并对容器做出修改
  3. 执行类似docker commit的操作命令提交一个镜像
  4. docker在基于上述提交的镜像运行一个新的容器
  5. 执行Dockerfile中的下一条指令重复上述过程知道所有的命令都执行完成

Dockerfile构建过程中常用命令如下:

  • FROM 指定基础镜像,如:
FROM ubuntu:18.04
  • MAINTAINER 镜像维护者信息
FROM alpine:3.8
MAINTAINER LeoHan
  • RUN 构建时运行的命令
FROM alpine:3.8
MAINTAINER LeoHan
RUN echo "start build"
RUN mkdir /usr/local/jdk8
  • ENV 在镜像构建过程中设置环境变量
FROM alpine:3.8
MAINTAINER LeoHan
RUN echo "start build"
RUN mkdir /usr/local/jdk8
ENV JDK_VERSION 1.8
ENV JDK_LOCAL /root/1.8 
ENV JDK_HOME /usr/local/jdk8
  • ADD、COPY 拷贝宿主机上的文件到镜像中,但是ADD会自动处理URL和解压tar包
FROM alpine:3.8
MAINTAINER LeoHan
RUN echo "start build"
RUN mkdir /usr/local/jdk8
ENV JDK_VERSION 1.8
ENV JDK_LOCAL /root/1.8 
ENV JDK_HOME /usr/local/jdk8
COPY $JDK_LOCAL/* $JDK_HOME/
  • EXPOSE 当前容器对外暴露的端口,这里只是对docker服务提供这个端口信息,并不会改变任何网络信息,如果需要通过该端口访问,需要在启动容器的时候通过-P参数将端口发布出来
FROM alpine:3.8
MAINTAINER LeoHan
RUN echo "start build"
RUN mkdir /usr/local/jdk8
ENV JDK_VERSION 1.8
ENV JDK_LOCAL /root/1.8 
ENV JDK_HOME /usr/local/jdk8
COPY $JDK_LOCAL/* $JDK_HOME/
EXPOSE 8080
  • WORKDIR 对后续的RUN、CMD、ENTRYPOINT、ADD、COPY指令设置工作目录,可以多次使用,支持相对路径,按上次定义的WORKDIR解析
FROM alpine:3.8
MAINTAINER LeoHan
RUN echo "start build"
RUN mkdir /usr/local/jdk8
ENV JDK_VERSION 1.8
ENV JDK_LOCAL /root/1.8 
ENV JDK_HOME /usr/local/jdk8
COPY $JDK_LOCAL/* $JDK_HOME/
EXPOSE 8080
WORKDIR /data1
WORKDIR /data2
  • VOLUME 向基于该镜像的容器添加数据卷
FROM alpine:3.8
MAINTAINER LeoHan
RUN echo "start build"
RUN mkdir /usr/local/jdk8
ENV JDK_VERSION 1.8
ENV JDK_LOCAL /root/1.8 
ENV JDK_HOME /usr/local/jdk8
COPY $JDK_LOCAL/* $JDK_HOME/
EXPOSE 8080
VOLME ["/data1","/data2"]
  • CMD 指定一个容器要启动的时候运行的命令,类似RUN,但是RUN是在镜像构建的时候运行,而CMD则是容器在启动的时候运行,类似于docker run,多个CMD命令只会使用最后一个
CMD ["/bin/sh"]
#传递参数
CMD [“/usr/local/jdk/bin/java","-version"]
  • ENTRYPOINT 与CMD非常类似,但是CMD命令会被docker run命令行中的命令覆盖,而ENTRYPOINT则不会。另外docker run命令行中指定的任何参数都会被当做参数再次传递给ENTRYPOINT指令中指定的命令
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]

如果将上述命令调整如下:

ENTRYPOINT ["/usr/sbin/nginx"]

然后在docker run中传递参数:

docker run -i -t xxxx -g "daemon off;"

如果同时定义了CMD和ENTRYPOINT,则CMD会被当成ENTRYPOINT参数

ENTRYPOINT ["/usr/local/jdk/bin/java"]
CMD ["-version"]
  • ONBUILD 当一个镜像被用作其他镜像的基础镜像的时候会触发执行
  • LABEL 为镜像添加元数据,键值对形式, key=value
LABEL version="1.0.1" name="test"

而后通过docker inspect 能够查看到元数据信息

  • ARG 定义可以在docker build命令时传递给构建运行时的变量,通过 --build-arg标志即可,用户只能在构建时指定在Dockerfile中定义过的参数
ARG version
#设置默认值
ARG name=test

然后可以如下传递:

docker build --build-arg version=1.0.1

Dockerfile常用命令总结:

命令名称作用说明
FROM指定基础镜像如:FROM alpine:3.8
MAINTAINER开发维护者相关信息MAINTAINER LeoHan
RUN构建时运行的命令RUN echo “hello world”
ENV在镜像构建过程中设置环境变量ENV version 1.0.1
EXPOSE当前容器对外暴露的端口,这里只是对docker服务提供这个端口信息,并不会改变任何网络信息,如果需要通过该端口访问,需要在启动容器的时候通过-P参数将端口发布出来EXPOSE 8080
ADD、COPY拷贝宿主机上的文件到镜像中,但是ADD会自动处理URL和解压tar包
WORKDIR对后续的RUN、CMD、ENTRYPOINT、ADD、COPY指令设置工作目录,可以多次使用,支持相对路径,按上次定义的WORKDIR解析,可以理解为相当于切换了工作目录,CMDENTRYPOINT都在改目录下工作
VOLUME向基于该镜像的容器添加数据卷VOLUME ["/data1","/data2"]
CMD指定一个容器要启动的时候运行的命令,类似RUN,但是RUN是在镜像构建的时候运行,而CMD则是容器在启动的时候运行,类似于docker run,多个CMD命令只会使用最后一个
ENTRYPOINT与CMD非常类似,但是CMD命令会被docker run命令行中的命令覆盖,而ENTRYPOINT则不会。另外docker run命令行中指定的任何参数都会被当做参数再次传递给ENTRYPOINT指令中指定的命令
ONBUILD当一个镜像被用作其他镜像的基础镜像的时候会触发执行
LABEL为镜像添加元数据,键值对形式, key=value
ARG定义可以在docker build命令时传递给构建运行时的变量,通过 --build-arg标志即可,用户只能在构建时指定在Dockerfile中定义过的参数

以上是关于docker镜像相关原理,镜像构建,Dockerfile常用命令的主要内容,如果未能解决你的问题,请参考以下文章

DockerFile详解以及测试案例

Docker Compose 入门(V3)

docker数据管理和镜像创建dockerfile部署

docker数据管理和镜像创建dockerfile部署

sqler sql 转rest api 的docker 镜像构建(续)使用源码编译

docker 镜像分层原理