Docker学习笔记(二):Docker镜像原理、Docker数据卷(挂载)作用和使用

2023-11-18

Docker镜像详解

1、镜像是什么

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。

所有应用打包成docker镜像,就可以直接跑起来

2、UnionFS(联合文件系统)

UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

3、Docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统就是UnionFS。

bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。

这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。

在这里插入图片描述

平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才200M??

在这里插入图片描述

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

4、镜像分层

以我们的pull命令为例,在下载的过程中我们可以看到docker的镜像好像是在一层一层的在下载 。

img

以tomcat举例,平时使用中的tomcat只有一百兆左右,但是docker镜像文件有四百多兆,因为它会进行多层封装,导致如此。

镜像分层tomcat

docker为什么要采用镜像分层?

最大的好处就是共享资源。例如:有多个镜像都从相同的base镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像,同时内存中也只需加载一份base镜像,就可以为所有容器服务了。而镜像的每一层都可以被共享。

Docker分层的特点:

Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称为“容器层”,“容器层”之下的都叫“镜像层”。

5、Commit镜像

命令:

docker commit -m="提交描述信息" -a="作者" 容器ID 镜像名[:TAG]

测试:

docker运行默认tomcat容器中,webapps下面默认没有任何项目文件,所以访问会404。而自带的项目文件都在webapps.dist文件下面。

我们需要做的时将webapps.dist下面的项目文件拷贝到webapps下面,然后将容器打包成镜像发布出去。

#查看正在运行的tomcat的容器ID
[root@Eva ~]# docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                               NAMES
c3dd6ff5f8a4        tomcat               "catalina.sh run"        8 weeks ago         Up 3 seconds        0.0.0.0:8080->8080/tcp              tomcat8080
#进入容器内部
[root@Eva ~]# docker exec -it c3dd6ff5f8a4 /bin/bash
#看到有webapps和webapps.dist两个文件夹
root@c3dd6ff5f8a4:/usr/local/tomcat# ls
BUILDING.txt	 LICENSE  README.md	 RUNNING.txt  conf     lib   native-jni-lib  webapps	   work
CONTRIBUTING.md  NOTICE   RELEASE-NOTES  bin	      include  logs  temp	     webapps.dist
#进入webapps目录下
root@c3dd6ff5f8a4:/usr/local/tomcat# cd webapps
#可以看到没有默认的项目文件
root@c3dd6ff5f8a4:/usr/local/tomcat/webapps# ls
#退回到上层目录
root@c3dd6ff5f8a4:/usr/local/tomcat/webapps# cd ..
#将webapps.dist中的项目目录拷贝到webapps下面
root@c3dd6ff5f8a4:/usr/local/tomcat# cp -r webapps.dist/* webapps
#再次进入webapps可以看到默认的一些项目文件
root@c3dd6ff5f8a4:/usr/local/tomcat# cd webapps
root@c3dd6ff5f8a4:/usr/local/tomcat/webapps# ls
ROOT  docs examples  host-manager  manager

#退出到主机后使用commit将容器提交为一个新的镜像
[root@Eva ~]# docker commit -a="Miracle42" -m="add webapps default app" f3b47f4d17b8 tomcat42:1.0
sha256:092676e6974e6ade292edee30d6c0debc3d5aaf4cd3d5fb29c0c957356d20242
#查看新生成的镜像
[root@Eva ~]# docker images 
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
tomcat42             1.0                 092676e6974e        17 seconds ago      550MB

Docker容器数据卷

1、什么是容器数据卷

从docker理念来讲:

  • docker将运用与运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对数据的要求希望是持久化的。
  • 容器之间希望可能共享数据。

Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也没有了。

所以为了能够保存数据,自然出现了docker容器数据卷。

简而言之:Docker容器数据卷就是做数据持久化,保存容器数据,同时也可以做到容器间的数据共享

2、容器数据卷的作用

卷就是目录或者文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持久化存储或共享数据的特性。

卷的设计目的就是数据的持久化,完全独立于容器的生命周期,因此Docker不会再容器删除时删除其挂载的数据卷。

其特点:

  • 数据卷可在容器之间共享或重用数据。
  • 卷中的更改可以直接生效。
  • 数据卷中的更改不会包含在镜像的更新中。
  • 数据卷的生命周期一直持续到没有容器使用它为止。

3、容器数据卷的使用

1)直接使用命令(-v)进行挂载

输入以下指令,将实现卷挂载,如果文件夹不存在,将重新创建。
docker run -v /宿主机绝对路径目录:/容器内目录 镜像名

#命令
docker run -v /主机目录:/容器目录 镜像ID

#运行centos镜像,并进行挂载
[root@Eva ~]# docker run -it -v /root/home:/home centos /bin/bash
#进行容器内部对挂载的目录进行操作
[root@0e6ece00287a /]# cd /home
[root@0e6ece00287a home]# ls
[root@0e6ece00287a home]# mkdir testv
[root@0e6ece00287a home]# exit
exit
#可以看到操作同步到了主机目录,
[root@Eva ~]# ls /root/home
testv

#例子2:挂载mysql配置文件和数据文件到本地
docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql

验证挂载是否成功,输入docker inspect查看详细信息,若有如下信息则表示挂载成功:

在这里插入图片描述

挂载成功后,容器与宿主操作文件都会相互同步,即使容器exit退出后,重连即可恢复连接。

2)具名和匿名挂载

# 三种挂载: 匿名挂载、具名挂载、指定路径挂载
-v 容器内路径			#匿名挂载
-v 卷名:容器内路径		#具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载 docker volume ls 是查看不到的
# 匿名挂载
-v 容器内路径!
docker run -d -P --name nginx01 -v /etc/nginx nginx

# 查看所有的volume的情况
➜  ~ docker volume ls    
DRIVER              VOLUME NAME
local               33ae588fae6d34f511a769948f0d3d123c9d45c442ac7728cb85599c2657e50d        
# 这里发现,这种就是匿名挂载,我们在 -v只写了容器内的路径,没有写容器外的路劲!

# 具名挂载
➜  ~ docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
➜  ~ docker volume ls                  
DRIVER              VOLUME NAME
local               juming-nginx

# 通过 -v 卷名:容器内路径
# 查看一下这个卷

image-20200516113545746

所有的docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes/xxxx/_data
如果指定了目录,docker volume ls 是查看不到的

image-20200516114231435

带权限的挂载

# 通过 -v 容器内路径: ro rw 改变读写权限
ro #readonly 只读
rw #readwrite 可读可写


docker run -d -P --name nginx05 -v juming:/etc/nginx:ro nginx
docker run -d -P --name nginx05 -v juming:/etc/nginx:rw nginx

ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作

3)使用Dockerfile进行挂载

Dockerfile就是用来构建Docker镜像的构建文件,是一个命令脚本,通过这个脚本可以生成一个镜像。

使用vim创建一个名为dockerfile01的Dockerfile文件

#编写一个Dockerfile
FROM centos 	#源于centos

VOLUME ["volume01","volume02"]	#指定两个匿名挂载

cmd echo "-------end---------"
cmd /bin/bash

使用build对Dockerfile构建镜像

#编写Dockerfile文件
[root@Eva docker-test-volume]# vim dockerfile01
[root@Eva docker-test-volume]# cat dockerfile01 
FROM centos

VOLUME ["volume01","volume02"]

cmd echo "-------end---------"
cmd /bin/bash


#使用build根据dockerfile01生成镜像
	-f	#指定dockerfile的文件的位置
	-t	#指定生成镜像的名称不能以/或者大写字母开头
[root@Eva docker-test-volume]# docker build -f dockerfile01 -t miracle42/centos:1.0 .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM centos
 ---> 470671670cac
Step 2/4 : VOLUME ["volume01","volume02"]
 ---> Running in b2173ff97d4e
Removing intermediate container b2173ff97d4e
 ---> db365b613255
Step 3/4 : cmd echo "-------end---------"
 ---> Running in 8975a769bd28
Removing intermediate container 8975a769bd28
 ---> 28ebe5f2f0fa
Step 4/4 : cmd /bin/bash
 ---> Running in 8d394a585647
Removing intermediate container 8d394a585647
 ---> 5800ff4ec9b5
Successfully built 5800ff4ec9b5
Successfully tagged miracle42/centos:1.0
#查看新生成的镜像
[root@Eva docker-test-volume]# docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
miracle42/centos     1.0                 5800ff4ec9b5        28 seconds ago      237MB

下面的命令可以查看当前容器主机挂载地址

[root@Eva home]# docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                               NAMES
7f966869e014        5800ff4ec9b5         "/bin/bash"              5 minutes ago       Up 5 minutes                                            jolly_shannon
[root@Eva home]# docker inspect 7f966869e014

在这里插入图片描述

进入容器内部创建文件,然后在主机的挂在地址查看文件是否同步过来:

#在容器内部的数据卷中创建文件
[root@7f966869e014 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volume01	volume02
[root@7f966869e014 /]# cd volume01
[root@7f966869e014 volume01]# touch container.txt
#在主机中进入上面找到的挂载地址,可以看到里边已经有了刚才在容器中创建的文件
[root@Eva home]# cd /var/lib/docker/volumes/a06277c1c1faf41909e286f3db4bbe1ed7d73b43fbc28459e922360c8c35e5bd/_data
[root@Eva _data]# ls
container.txt

4)容器间挂载同步

在这里插入图片描述

首先启动我们之间创建的miracle42/centos镜像生成名为centos01的容器,可以看到容器内部有volume01,volume02两个挂载目录。

[root@Eva _data]# docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
miracle42/centos     1.0                 5800ff4ec9b5        25 minutes ago      237MB
[root@Eva _data]# docker run -it --name centos01 5800ff4ec9b5 bash
[root@6a943a955478 /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volume01	volume02

接着再次启动一个miracle42/centos镜像命名为centos02,并且使用--volumes-from命令实现与centos01进行挂载同步。可以看到centos02内部同样有volume01,volume02两个挂载目录

[root@Eva _data]# docker run -it --name centos02 --volumes-from centos01 5800ff4ec9b5
[root@ac27409b73fd /]# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volume01	volume02

在centos02容器中的volume01中创建一个文件

[root@ac27409b73fd /]# cd volume01 
[root@ac27409b73fd volume01]# ls
[root@ac27409b73fd volume01]# mkdir centos02.txt
[root@ac27409b73fd volume01]# exit
exit

进入centos01容器中的volume01仍然可以看到此文件

[root@Eva _data]# docker exec -it 6a943a955478 bash
[root@6a943a955478 /]# cd volume01
[root@6a943a955478 volume01]# ls
centos02.txt

删除centos01,centos02依旧可以访问这个文件

容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Docker学习笔记(二):Docker镜像原理、Docker数据卷(挂载)作用和使用 的相关文章

随机推荐