Docker04:Docker镜像和什么是数据卷

本文详细介绍了Docker镜像的原理,包括什么是Docker镜像、UnionFS联合文件系统、镜像加载原理、分层结构及其优势。还探讨了Docker容器数据卷的使用,包括数据卷的概念、作用、使用方法,以及数据卷在容器间的共享和持久化。最后,通过案例演示了如何创建和使用数据卷,以及数据卷在容器重启或删除后的行为。
摘要由CSDN通过智能技术生成

一、Docker镜像

1、什么是Docker镜像?
  • 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的有内容,包括代码、运行时、库、环境变量和配置文件。
2、UnionFS(联合文件系统)
  • Union文件系统(UnionFS)是一一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一 次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。
  • 镜像可以通过分层来进行继承,基于基础镜像(没有父镜像)可以制作各种具体的应用镜像。

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

3、镜像加载原理
  • Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统是UnionFS联合文件系统。

bootfs

主要包含bootloaderkernelbootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权己由bootfs转交给内核,此时系统也会卸载bootfs。

rootfs :

在bootfs之上。 包含的就是典型Linux系统中的**/dev, /proc, /bin, /etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu**,Centos等等。

image-20210830093635449

平时安装的虚拟机的Centos都是好几个G ,但是docker这里才要200M

  • 对于一个精简的OS, rootfs可 以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Hostkernel,自只需要提供rootfs就行了。
  • 由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs
  • 所以虚拟机启动是分钟级的,容器是秒级的!!!
4、分层的镜像
#查看镜像分层命令
docker image inspect

image-20210830094559330

重点:所有的Docker镜像都起始于一个基础镜像层,当需要进行修改或者增加新的内容的时候,就会在当前镜像层之上,创建新的镜像层

示例

  • 假如基于Ubuntu 16.04 创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。如下图所示:

image-20210830095242012

  • 在添加额外的镜像层的同时,镜像始终保持当前所有镜像的组合,例如每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。

image-20210830095815387

  • 下图中在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版。

image-20210830083058189

  • 上图可以看出上层镜像层中的文件覆盖了底层镜像层中的文件,这样就使得文件的更新版作为一个新镜像层添加到镜像当中。Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。如下图所示:

image-20210830083126982

5、为什么使用分层结构?

最大好处就是资源共享

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

特点

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

image-20210830084220754

6、commit镜像
docker commit 提交容器副本使之称为一个新的镜像

docker commit -m=“提交的描述信息”  -a="作者" 容器id 目标镜像名:[TAG] 
案例演示:

由于默认的Tomcat镜像的webapps文件夹中没有任何内容,需要从webapps.dist中拷贝文件到webapps文件夹。

下面自行制作镜像:就是从webapps.dist中拷贝文件到webapps文件夹下,并提交该镜像作为一个新的镜像。使得该镜像默认的webapps文件夹下就有文件。具体命令如下:

#1、启动Tomcat容器
[root@hcz666 ~]# docker run -it tomcat /bin/bash
root@b5d0f2414eba:/usr/local/tomcat# cd webapps
root@b5d0f2414eba:/usr/local/tomcat/webapps# ls
root@b5d0f2414eba:/usr/local/tomcat/webapps# cd ../
#2、将webapps.dist中拷贝文件到webapps下
root@b5d0f2414eba:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@b5d0f2414eba:/usr/local/tomcat# cd webapps
root@b5d0f2414eba:/usr/local/tomcat/webapps# ls
ROOT  docs  examples  host-manager  manager
#ctrl+P+Q
root@b5d0f2414eba:/usr/local/tomcat/webapps# [root@hcz666 ~]# 
[root@hcz666 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED              STATUS              PORTS      NAMES
b5d0f2414eba   tomcat    "/bin/bash"   About a minute ago   Up About a minute   8080/tcp   stoic_ramanujan
[root@hcz666 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS      NAMES
b5d0f2414eba   tomcat    "/bin/bash"   9 minutes ago   Up 8 minutes   8080/tcp   stoic_ramanujan
[root@hcz666 ~]# docker exec -it b5d0f2414eba /bin/bash
root@b5d0f2414eba:/usr/local/tomcat# cd webapps
root@b5d0f2414eba:/usr/local/tomcat/webapps# ls
ROOT  docs  examples  host-manager  manager
root@b5d0f2414eba:/usr/local/tomcat/webapps# cd ../
#ctrl+P+Q
root@b5d0f2414eba:/usr/local/tomcat# read escape sequence
[root@hcz666 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS          PORTS      NAMES
b5d0f2414eba   tomcat    "/bin/bash"   20 minutes ago   Up 20 minutes   8080/tcp   stoic_ramanujan
#3、提交镜像作为一个新的镜像
[root@hcz666 ~]# docker commit -m="add webapps" -a="hcz" b5d0f2414eba mytomcat:1.0
sha256:924ea2a2ebdfd7e1d96e5b0ef038177dff0d3ed0ebb36f9711c0b061757ca511
[root@hcz666 ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
mytomcat              1.0       924ea2a2ebdf   15 seconds ago   673MB
tomcat                latest    266d1269bb29   11 days ago      668MB
nginx                 latest    dd34e67e3371   12 days ago      133MB
mysql                 8.0       5a4e492065c7   12 days ago      514MB
mysql                 latest    5a4e492065c7   12 days ago      514MB
portainer/portainer   latest    580c0e4e98b0   5 months ago     79.1MB
hello-world           latest    d1165f221234   5 months ago     13.3kB
centos                latest    300e315adb2f   8 months ago     209MB
#4、运行新的容器
[root@hcz666 ~]# docker run -it mytomcat:1.0 /bin/bash
root@eb6d0213cc42:/usr/local/tomcat# cd webapps
root@eb6d0213cc42:/usr/local/tomcat/webapps# ls
ROOT  docs  examples  host-manager  manager
root@eb6d0213cc42:/usr/local/tomcat/webapps# [root@hcz666 ~]# 
[root@hcz666 ~]# docker ps
CONTAINER ID   IMAGE          COMMAND       CREATED          STATUS          PORTS      NAMES
eb6d0213cc42   mytomcat:1.0   "/bin/bash"   17 seconds ago   Up 15 seconds   8080/tcp   condescending_mirzakhani
b5d0f2414eba   tomcat         "/bin/bash"   23 minutes ago   Up 23 minutes   8080/tcp   stoic_ramanujan

image-20210830101258354

二、Docker容器数据卷

1、数据卷

(1)数据卷是什么?

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

Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了。为了能保存数据在docker中我们使用卷。|

image-20210830103531552

(2)数据卷能干嘛?

概述

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

特点

  • 数据卷可在容器之间共享或重用数据

  • 卷中的更改可以直接生效

  • 数据卷中的更改不会包含在镜像的更新中

  • 数据卷的生命周期一直持续到没有容器使用它为止

总结

  • 容器的持久化

  • 容器间继承+共享数据

(3)数据卷怎么样使用?
方式一:直接使用命令添加(-v)
#添加命令
docker run -it -v /主机目录:/容器内目录 镜像名
#挂载命令
docker inspect 容器id
示例:

1、使用命令进行添加

#在第一个会话中
#使主机上的/home/demo目录和容器的/home目录进行挂载
[root@hcz666 ~]# docker run -it -v /home/demo:/home centos /bin/bash
[root@c3e071951e83 /]# cd /home
[root@c3e071951e83 home]# ls
[root@c3e071951e83 home]#  

2、查看数据卷是否挂载成功

#在第二个会话中
[root@hcz666 ~]# cd /home  #进入主机的/home目录下
[root@hcz666 home]# ls     #发现demo文件夹已经挂载过来了
demo  demo.java  hcz  hcz1.txt  hcz666  hcz.txt  hilde  lighthouse  test2  www  zsx
[root@hcz666 home]# docker ps
CONTAINER ID   IMAGE          COMMAND             CREATED         STATUS         PORTS                                       NAMES
c3e071951e83   centos         "/bin/bash"         2 minutes ago   Up 2 minutes                                               dazzling_blackwell
eb6d0213cc42   mytomcat:1.0   "/bin/bash"         22 hours ago    Up 22 hours    8080/tcp                                    condescending_mirzakhani
b5d0f2414eba   tomcat         "/bin/bash"         23 hours ago    Up 23 hours    8080/tcp                                    stoic_ramanujan
3a5b0d6c5f23   tomcat         "catalina.sh run"   42 hours ago    Up 22 hours    0.0.0.0:6656->8080/tcp, :::6656->8080/tcp   tomcat01
#查看挂载是否成功
[root@hcz666 home]# docker inspect c3e071951e83
[
    {
        "Id": "c3e071951e83a6c192a36e15d1ea4a1a669c7e15247972bf330c1ea9bbb0c6e2",
        "Created": "2021-08-30T23:33:28.235392277Z",
        "Path": "/bin/bash",
        "Args": [],

image-20210831074313288

3、容器和宿主机之间数据共享

  • 向容器的/home目录下创建一个文件,主机的/home/demo文件夹自动同步

image-20210831075204418

4、容器停止退出后,主机修改后的数据自动同步

image-20210831080232806

实战:Mysql数据持久化

1、使用命令进行添加

#创建容器命令
[root@hcz666 home]# docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql --name mysql03 mysql:8.0

-----------------------------------------
#命令说明:
-p(端口映射) 12345:3306:将主机的3307端口映射到docker容器的3306端口。
--name(容器名字) mysq:运行服务名字
-v(数据卷) /home/mysql/conf:/etc/mysql/conf.d :将主机/home/mysql录下的conf挂载到容器的/etc/mysql/conf.d
	/home/mysql/data:/var/lib/mysql :将主机/home/mysql目录下的data目录挂载到容器的/var/lib/mysql 
-e(环境配置) MYSQL_ ROOT_ PASSWORD=123456: 初始化root用户的密码。
-d(后台运行) mysql:8.0:后台程序运行mysql8.0 

2、查看数据卷是否挂载成功

image-20210831084608357

3、连接本地Navicat进行测试

具体可以看:[Docker03:Docker常用安装实例_hcz666的博客-CSDN博客]

image-20210831085312373

4、在本地连接创建一个test数据库,查看一下主机中是否有同步

image-20210831085356988

image-20210831085455365

5、删除容器,挂载在本地的数据卷依旧没有丢失

image-20210831085710691

image-20210831085817038

拓展:具名挂载和匿名挂载

匿名挂载

#匿名挂载:就只是写了容器内的路径,没有写宿主机的路径
-v 容器内路径

[root@hcz666 home]# docker run -d -P --name nginx03 -v /etc/nginx nginx
61072689ca5ad9625cf16a05b253b54e9afd3dc0a6656a7aed9289fe075d0360
#查看所有的volume的情况
[root@hcz666 home]# docker volume ls
DRIVER    VOLUME NAME
local     117c36fa03f7f9604ed1614b2ac4742dc01fd52411ecf4d1ed80c53fbb934d85
local     b9a3f1325dbcc6b6ef1195b4cec7b3ac5cdabad1812fa59f3cf542817d4a7274
local     c71af64016a451112d65039f46e3dc6feaf735e1e7653dbfe99e4bcff4bf347c
local     e7134e61b7e023a3f2bcebf970459f61f4cc5048d4448322f65377027b8cdb98
local     ee6f64526d36c075c785979e0080d80dec4dc56a876419c2b030e70c5edfa107
[root@hcz666 home]# 

具名挂载

#具名挂载:就只是写了卷名和容器内的路径,同样也没有写宿主机的路径
-v 卷名 容器内路径

[root@hcz666 home]# docker run -d -P --name nginx05 -v juming-ngnix:/etc/nginx nginx
5e19716b3dc56ce655dc2bdf189f7eccc96ad332da2cee1536d2d89bb44f0219
[root@hcz666 home]# docker volume ls
DRIVER    VOLUME NAME
local     0b0093b3473bc17c1349bf713fdca0810e08d11509bae2e73ac0df3cf1413197
local     117c36fa03f7f9604ed1614b2ac4742dc01fd52411ecf4d1ed80c53fbb934d85
local     b9a3f1325dbcc6b6ef1195b4cec7b3ac5cdabad1812fa59f3cf542817d4a7274
local     c71af64016a451112d65039f46e3dc6feaf735e1e7653dbfe99e4bcff4bf347c
local     e7134e61b7e023a3f2bcebf970459f61f4cc5048d4448322f65377027b8cdb98
local     ee6f64526d36c075c785979e0080d80dec4dc56a876419c2b030e70c5edfa107
local     juming-ngnix
#查看这个卷名
[root@hcz666 home]# docker volume inspect juming-ngnix 
[
    {
        "CreatedAt": "2021-08-31T09:25:40+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/juming-ngnix/_data",
        "Name": "juming-ngnix",
        "Options": null,
        "Scope": "local"
    }
]
[root@hcz666 home]# 

image-20210831092816046

所有的docker容器内的卷,如果没有指定宿主机目录的情况下,默认都是在路径下:/var/lib/docker/volumes/juming-ngnix/_data"

image-20210831093056031

区别

#如何确定是具名挂载还是匿名挂载,还是指定路径挂载
-v 容器内路径           #具体挂载
-v 卷名:容器内路径       #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
方式二:DockerFile添加
#可以在DockerFile中使用VOLUME指令来给镜像添加一个或多个数据卷
VOLUME ["volume01","volume02"]  #这里属于匿名挂载

#说明:
- 出于可移植和分享的目的,只用方式一不能够直接在DockerFile中实现
- 由于宿主机目录是依赖于特定宿主机的,并不能够保证所有的宿主机上都存在这样的特定的目录
示例:

1、创建自定义文件夹

[root@hcz666 home]# mkdir docker-test-volume
[root@hcz666 home]# ls
demo       docker-test-volume  hcz1.txt  hcz.txt  lighthouse  test2  zsx
demo.java  hcz                 hcz666    hilde    mysql       www
[root@hcz666 home]# cd docker-test-volume/
[root@hcz666 docker-test-volume]# pwd
/home/docker-test-volume

image-20210831095331557

2、创建一个dockerfile文件,名字随意

#构建脚本
FROM centos

VOLUME ["volume01","volume02"]  #这里属于匿名挂载

CMD echo "--------finished--------"

CMD /bin/bash

image-20210831095141559

3、build后生成镜像

#构建自定义镜像命令
[root@hcz666 docker-test-volume]# docker build -f /home/docker-test-volume/dockerfile -t hcz/centos:1.0 .

image-20210831095838431

4、启动容器

[root@hcz666 docker-test-volume]# docker run -it 45648d270480 /bin/bash

image-20210831100647142

4、查看主机对应默认的地址

[root@hcz666 _data]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                     NAMES
23de7c512bc1   45648d270480   "/bin/bash"              9 minutes ago    Up 9 minutes                                              magical_noyce
[root@hcz666 _data]# docker inspect 23de7c512bc1
……省略……
"Mounts": [
            {
                "Type": "volume",
                "Name": "b0227290658396c919bccf35dca0d3cb58c9c24cb552cd4fedfab617c62ea02d",
                "Source": "/var/lib/docker/volumes/b0227290658396c919bccf35dca0d3cb58c9c24cb552cd4fedfab617c62ea02d/_data",
                "Destination": "volume01",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "volume",
                "Name": "30f4ff1fcc1722912bfc7528dd3e7869d88033de31a236301538b21f393a3c8e",
                "Source": "/var/lib/docker/volumes/30f4ff1fcc1722912bfc7528dd3e7869d88033de31a236301538b21f393a3c8e/_data",
                "Destination": "volume02",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

……省略……

image-20210831101945857

5、测试数据同步

image-20210831102328230

image-20210831102458159

2、数据卷容器

(1)什么是数据卷容器

image-20210831103517557

(2)容器间传递共享(–volumes -from)
1、先启动一个父容器docker01
[root@hcz666 ~]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
hcz/centos            1.0       45648d270480   43 minutes ago   209MB
[root@hcz666 ~]# docker run -it --name docker01 hcz/centos:1.0
[root@d93a04629b62 /]# ls -l
total 56
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root  360 Aug 31 02:44 dev
drwxr-xr-x   1 root root 4096 Aug 31 02:44 etc
drwxr-xr-x   2 root root 4096 Nov  3  2020 home
lrwxrwxrwx   1 root root    7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root 4096 Dec  4  2020 lost+found
drwxr-xr-x   2 root root 4096 Nov  3  2020 media
drwxr-xr-x   2 root root 4096 Nov  3  2020 mnt
drwxr-xr-x   2 root root 4096 Nov  3  2020 opt
dr-xr-xr-x 131 root root    0 Aug 31 02:44 proc
dr-xr-x---   2 root root 4096 Dec  4  2020 root
drwxr-xr-x  11 root root 4096 Dec  4  2020 run
lrwxrwxrwx   1 root root    8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Nov  3  2020 srv
dr-xr-xr-x  13 root root    0 Aug 31 02:05 sys
drwxrwxrwt   7 root root 4096 Dec  4  2020 tmp
drwxr-xr-x  12 root root 4096 Dec  4  2020 usr
drwxr-xr-x  20 root root 4096 Dec  4  2020 var
drwxr-xr-x   2 root root 4096 Aug 31 02:44 volume01
drwxr-xr-x   2 root root 4096 Aug 31 02:44 volume02

image-20210831104537164

  • 启动后在volume01目录下新增一个文件

image-20210831110457904

2、继续启动docker02和docker03容器并继承docker01

image-20210831111057701

3、返回docker01查看数据

image-20210831111232464

4、删除docker01、docker02修改后docker03是否能访问

image-20210831111601511

5、删除docker02后docker03是否能访问

image-20210831111808287

6、新建docker04继承docker03,然后删除docker03

image-20210831112204448

(3)实战

多个MySQL实现数据共享

#第一个数据库
[root@hcz666 home]# docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /etc/mysql/conf.d -v /var/lib/mysql --name mysql01 mysql:8.0

#第二个数据库
[root@hcz666 home]# docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /etc/mysql/conf.d -v /var/lib/mysql --name mysql02 --volumes -from mysql01 mysql:8.0

#第三个数据库
[root@hcz666 home]# docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /etc/mysql/conf.d -v /var/lib/mysql --name mysql03 --volumes -from mysql01 mysql:8.0
(4)结论

容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止;但是一旦持久化到了本地,这个时候,本地的数据是不会删除的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@烟雨倾城ゝ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值