Docker学习笔记(2)-镜像,容器数据卷与DockerFile
Docker镜像
简介
Docker Image镜像是一种轻量级的、可执行的独立软件包,它包含了运行某个软件所需要的所有内容。应用程序和配置依赖被打包好形成一个可交付的运行环境,这个打包好的运行环境就是Image镜像文件,通过Image镜像文件才能生成Docker容器实例。
Docker镜像是分层构建的,其中使用了UnionFS(联合文件系统)。UnionFS是一种分层、轻量级、高性能的文件系统。它将对文件系统的修改看作一次次的提交,最终的状态则是一层层叠加之后的结果。同时UnionFS支持将不同目录挂载到同一个虚拟文件系统下。UnionFS是Docker Image的基础,Image可以通过分层来进行继承,基于基础镜像,可以制作各种具体的应用镜像。Image分层的一个最大好处就是能够做到共享资源,方便复用和迁移。
Docker镜像是分层的文件系统,其中最底层是启动层BootFS(Boot File System),其中主要包含了BootLoader以及Kernel,BootLoader主要用于引导加载文件系统,该层与典型的Unix系统是一致的。当加载完成之后,整个Kernel就都存放在内存当中了。此时内存的使用权就会从BootFS转交给Kernel,系统也会卸载BootFS。
而在BootFS之上是RootFS层,包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
在Docker的分层结构当中,又可以分为镜像层和容器层,这两种类型最大的区别就是镜像层是只读的,而容器层是可写的。当从一个镜像中启动出容器之后,一个新的可写的容器层就会被加载到现有分层结构的最顶层,之后所有的针对容器的修改都会记录到该层中。而在容器层之下的其他所有层次,则都属于镜像层,都是只读的。
commit & push
前面提到容器层可以进行修改,我们可以将修改后的容器重新打包成为一个镜像,这就需要使用到commit命令。下面的命令可以将contianer_id对应的容器提交成为一个新的镜像,新的镜像为target_image:tag。
1 |
|
生成的新镜像目前只在本地存在,可以通过push命令将本地镜像推送到Docker仓库中。当然还可以部署私有仓库,此时需要借助Docker Registry镜像,相关操作可以参考官方文档Deploy a registry server | docker docs,或者相关博客A Guide to Docker Private Registry | Baeldung。
虚悬镜像,danling image,指的是仓库名,标签都是
<none>
的镜像。
1
2
3
4
5
# 查看虚悬镜像
docker image ls -f dangling=true
# 删除虚悬镜像
docker image prune
容器数据卷
使用
一个容器如果被删除了,那么容器内部的数据也都被删除了。但是在一些场景下,我们希望容器内部的数据能够被保存下来,这就需要使用到容器数据卷,起到一个数据备份的效果。
容器数据卷的挂载在容器启动的时候完成,通过-v
属性。下面的命令可以挂载一个容器数据卷:
1 |
|
--privileged=true表示扩大容器的权限,否则可能出现无法操作对应目录的情况。
该命令完成的功能是在启动容器的时候完成数据卷挂载,如果不使用数据卷,则容器内的目录是虚拟出来的,与宿主机是隔离的;如果使用了数据卷,那么容器内的对应目录直接映射到了宿主机的对应目录,能够达到一个类似双向绑定的效果。容器内目录改动能够传到宿主机中,反之亦然。并且此时如果我们删除了容器,相关数据仍然能够在宿主机中查看到。
如果挂载了数据卷,我们可以通过docker inspect
命令在详细信息中查看到。
在挂载数据卷的时候,可以通过相关属性来配置容器对应该目录的读写权限,默认是读写权限都具备,当然也可以配置成只读。
1 |
|
另外,容器数据卷可以在容器之间进行继承,通过--volumes-from
属性完成。此时启动的容器与父容器除了具有相同的数据卷规则之外没有任何联系,一方的删除并不会导致另一方数据卷规则失效。
1 |
|
卷挂载
在使用数据卷的时候,我们也可以只提供容器内的路径,而不提供宿主机的路径,这种挂载方式被称为卷挂载Volume Mount。
1 |
|
卷挂载只提供容器内路径,但是可以传入一个name来代替之前的宿主机路径。如果没有name,则属于匿名挂载;如果提供了name,则属于具名挂载。
虽然卷挂载不提供宿主机目录,但是实际上还是有这个概念的。在卷挂载的情况下,对应的宿主机目录都是/var/lib/docker/volumes/xxx
。如果是匿名挂载,后面的名字就是一串哈希值;如果是具名挂载,后面的名字就是指定的name。
DockerFile
简介
想要获取一个Image镜像,可以通过从仓库中拉取,也可以通过DockerFile来进行构建。DockerFile就是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的参数构成的脚本。首先编写一个DockerFile文件,之后可以通过docker build
命令来构建镜像。
保留字介绍
命令的详细介绍可以参考官方文档Dockerfile reference
首先有一些基础知识:
- 每条保留字指令都是大写字母,并且后面至少跟随一个参数
- 指令按照从上到下的顺序执行
#
表示注释
下面介绍常用的相关保留字:
FROM
:指定基础镜像。指定一个已经存在的镜像作为模板,每个Dockerfile的第一条必须是FROM。
MANINTAINER
:指定镜像维护者的姓名和邮箱地址。
RUN
:在容器构建过程中需要运行的命令,命令可以用两种形式进行书写。
1 |
|
EXPOSE
:指定当前容器向外暴露的端口。
WORKDIR
:指定在创建容器之后,终端默认登陆进来的工作目录。
USER
:指定该镜像该以哪个用户去执行,一般不指定,默认为root用户。
ENV
:用来在镜像构建过程中设置环境变量。在该命令后面的其他指令可以直接使用已经定义了的环境变量。
ADD
:将宿主机目录下的文件拷贝到镜像中,会自动处理URL以及解压tar压缩包。
COPY
:类似ADD,但是不会进行解压处理,只是单纯的拷贝。
VOLUME
:指定容器数据卷,用于数据保存和持久化的工作。
CMD
:指定容器启动之后需要运行的命令。需要注意的是,Dockerfile中可以有多个CMD指令,但是只有最后一个生效,并且CMD会被docker
run之后的参数替换。
ENTRYPOINT
:同样是指定容器之后需要运行的命令。不过与CMD不同的是,ENTRYPOINT并不会被docker
run后面的命令覆盖,并且传入的命令行参数会被当作提供给ENTRYPOINT对应命令的参数。当然在Dockerfile中同样可以有多个ENTRYPOINT指令,也只有最后一个生效。
CMD如果单独使用,则表示是运行的命令,同时可以被docker run参数覆盖。CMD如果和ENTRYPOINT一起使用,则CMD相当于在给ENTRYPOINT传参,此时CMD仍然可以被docker run参数覆盖。
因此,我们可以利用CMD来达到可变参数的目的:
假设有如下的Dockerfile,然后利用该Dockerfile构建出镜像,假设名为nginx:test
。
1 |
|
于是在利用docker run运行镜像的时候,可以通过是否提供命令行参数来达到控制参数的目的:
1 |
|
案例
下面的案例Dockerfile完成了从centos基础镜像出发,设置好java8的环境。
1 |
|
之后运行docker build命令进行镜像构建:
1 |
|