写时复制功能

image-20201112233247402

Docker 镜像是由多个只读层叠加而成,启动容器时,Docker 会加载只读镜像层并在镜像栈顶部调价一个读写层。

如果运行中的容器被修改了数据,那么将会在这一层之上新建一个读写层并覆盖,但是该只读文件依旧存在,只是被新建的制度层覆盖了,并不会删除。

删除情况,对上层用户将不再显示,会在这个文件上添加删除的标志,当 Docker 识别到后将不会显示给用户。

修改情况,会让文件中修改的数据重新生成一个文件并覆盖该文件的被修改的数据。

新建情况,会在新的只读层中新建一个文件并显示给用户。

这些情况被统称为 ”写时复制“

云计算的概念

image-20201112235902764

通过让每个主机上的 Container 容器挂载宿主机上的目录,但是主机上的目录挂载的是后台存储上的共享目录,从而达到资源共享,然后让容器可以在不同主机之间可以迁移。

形成容器集群且可以来回切换。

查看容器的存储分层

image-20201119122957269

数据目录分层

  • lowerdir:image 镜像层,即镜像的本身,只读
  • upperdir:容器的上层,可读写,容器变化的数据存放在此处
  • mergeddir:容器的文件系统,使用 Union FS(联合文件系统)将 lowerdir 和 upperdir 合并完成后容器使用,最终呈现给用户的统一视图
  • workdir:容器在宿主机的工作目录,挂载后会被清空,且在使用过程中其内容用户不可见

Volume 卷的概念

容器存在的数据问题

关闭或重启容器,其数据不会受到影响;但是删除 Docker 容器,其更改将会全部丢失。

存储在自己独立的存储空间中,与宿主机共享数据共享不便。

容器之间的共享数据不便。

删除容器后,容器正在运行的数据会丢失。

Volume 卷简介

将宿主机的文件系统挂载到容器中,让容器与宿主机共享存储空间,这样可以让宿主机与容器共享数据。

可以让多个容器同时挂载一个 Volume 卷,这样就可以让不同的容器进行共享数据。

此类目录可以绕过联合文件系统。

volume 于容器初始化之时即会创建,由 base image 提供的卷中的数据会于此期间完成复制。

volume 的初衷是独立于容器的声明周期实现数据的持久化,因此删除容器时即不会删除卷,也不会对哪怕未被引用的卷做垃圾回收。

image-20201113094018691

volume 的运行逻辑

卷为 Docker 提供了独立于容器的数据管理机制

卷实现了程序和数据的分离,以及程序和制作镜像的主机分离,用户制作镜像时无敌徐再考虑镜像运行的容器所在的主机的环境。

image-20201113094538069

当共享存储卷挂载到容器上后,那么当用户写入向容器中的卷写入数据时相当于直接写入到文件中。

当用户直接向容器中的根目录写入数据时会产生一个读写层,提供读写写入。

应用场景

当 docker 运行 httpd 时会将站点目录指定到 volume 卷上,共享主机的卷。其他产生的临时数据放置到容器的读写层中,这样当容器运行完成删除后,一些站点目录还是存在的,但是一些临时产生的数据将会删除。

Volume types 卷的类型

Docker 有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上的位置有所不同。

  • bind mount volume
    • 绑定挂载卷
    • 在宿主机上指定一个特定的路径,在容器中指定一个特定的路径,将两个路径绑定到一起。
  • Docker-managed volume
    • docker 管理卷
    • 只需要在容器中指定一个卷,然后 docker daemon 守护进程在宿主机由容器引擎创建一个空目录,挂载到容器中的指定目录。
    • **优点:**解决了用户建立的耦合关系
    • **缺点:**用户无法指定一个目录进行挂载
    • **应用场景:**通常用于给容器提供一个临时的挂载卷空间,但是如果该容器被删除后,如果要重新创建容器,那么就需要使用绑定挂载,不然 docker 很有可能还会重新创建一个挂载卷目录。
  • Sharing volumes 复制卷
    • 复制一个已经存在于其他容器上的卷,到新建或者是其他容器上,不需要再使用 -v 来指定。

Volume 的使用

创建查看挂载容器卷

- 使用 Docker run 命令使用 -v 选项即可以使用 volume
- Docker-managed volume
  - docker run -it --name b1 -v /data/ busybox 
  - docker inspecct -f {{.Mounts}} b1
- Bind-mount volume
  - docker run -it -v HOSTDIR:VOLUMEDIR --name b2 busybox
  - docker inspect -f {{.Mounts}} b2

删除容器卷

使用 docekr volume rm 删除容器卷的使用删除的比较干净。

使用 docker volume prune -f 删除卷不会删除容器卷指定的目录文件。

使用 docker rm -fv 可以在删除容器的同时删除容器卷。

范例 非交互式创建创建 volume 到 backUP_volume

非交互式备份容器上的文件

此时基础容器已经挂载 volume 到 /file 目录

docker run -it --rm --volumes-from container -v /backup:/backup/ ubuntu tar cvf /backup/backup.tar /file

还原数据

docker run -it --rm --volumes-from /file -v /backup:/backup ubuntu tar xvf /backup/backup.tar -C /file

命令格式

#在执行备份命令容器上执行备份方式
docker run -it --rm --volumes-from [container name] -v $(pwd):/backup ubuntu
root@ca5bb2c1f877:/#tar cvf /backup/backup.tar [container data volume]
#说明
[container name]             #表示需要备份的容器
[container data volume]     #表示容器内的需要备份的数据卷对应的目录
#还原方式
docker run -it --rm --volumes-from [container name] -V $(pwd):/backup ubuntu
root@ca5bb2c1f877:/#tar xvf /backup/backup.tar -C [container data volume]

范例 Docker-managed volume Docker 管理卷

  1. 直接指定容器中的挂载目录并运行容器
[root@centos7_10 ~]# docker container run -it --name b1 --rm -v /data/html busyb
  1. 使用命令查看 source 源目录和挂载点目录
[root@centos7_10 ~]# docker inspect af541ed249b5     
        "Mounts": [
            {
                "Type": "volume",
                "Name": "21660efac2b5233db9069b0041c2dff1d0ac4541dfa00908279eb33474c77f15",
                "Source": "/var/lib/docker/volumes/21660efac2b5233db9069b0041c2dff1d0ac4541dfa00908279eb33474c77f15/_data",
                "Destination": "/data/html",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
  1. 查看宿主机是否可以通过共享目录与容器共享资源
创建数据
[root@centos7_10 ~]# echo busybox > /var/lib/docker/volumes/21660efac2b5233db9069b0041c2dff1d0ac4541dfa00908279eb33474c77f15/_data/index.html

查看数据
/ # cat data/html/index.html
busybox

范例 Bind-mount volume 绑定挂载卷

  1. 创建本地目录
[root@centos7_10 ~]# mkdir -p /data/html
[root@centos7_10 ~]# echo busybox > /data/html/index.html
  1. 开启镜像容器,绑定本机的 /data/html 目录
[root@centos7_10 ~]# docker container run -it --name b1 --rm -v /data/html/:/data/ busybox
/ # cat /data/index.html
busybox

范例 实现两个容器共享一个 Volume 卷

  1. 运行第一个容器
[root@centos7_10 ~]# docker container run --name b1 -v /data/html:/data/ -it busybox
  1. 运行第二个容器
[root@centos7_10 ~]# docker container run --name b2 -v /data/html:/data/ -it busybox
  1. 在宿主机修改数据,验证是否可以同步到容器中
[root@centos7_10 ~]# echo busybox:123 > /data/html/index.html
容器一查看
/ # cat /data/index.html
busybox:123

容器二查看
/ # cat /data/index.html
busybox:123

范例 Sharing volumes 复制 Volume –volume-from 参数

使用此方法,可以创建一个数据卷的容器,使用数据卷容器进行挂载该容器上已经有的 volume 卷。

使用 --volumes-from 来指定容器并复制模板容器已经挂载的数据卷。

创建时基础容器有问题

  1. 创建时如果基础容器被删除,则会创建失败
  2. 创建时如果基础容器停止,正常可以创建
  3. 创建时如果基础容器在运行可以正常创建

创建后基础容器有问题

  1. 创建后基础容器停止,不会受到影响
  2. 创建后基础容器被删除,不会受到影响
  3. 创建后基础容器卸载 volume,不会受到影响

实验主体

  1. 创建一个基础容器
[root@centos7_10 ~]# docker container run --name base -it -v /data/html:/dat busybox
  1. 新建一个容器并复制基础容器现有的 Volume
[root@centos7_10 ~]# docker container run --name b1 -it --volumes-from base busybox
[root@centos7_10 ~]# docker container run --name b2 -it --volumes-from base busybox

Docker inspect 命令的调用和使用

如果是字典嵌套可以通过 .key 的方式进行调用,如果是列表可以通过 [key] 的方式进行调用

[root@centos7_10 ~]# docker container inspect -f {{.NetworkSettings.Networks.bridge.IPAddress}} b1