docker存储卷

发布于:2023-01-23 ⋅ 阅读:(528) ⋅ 点赞:(0)

1.COW机制

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

如果运行中的容器修改了现有的一个已经存在的文件,那么该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本依然存在,只是已经被读写层中该文件的副本所隐藏,这就是“写时复制(COW)”机制。
在这里插入图片描述

2.存储卷

存储卷就是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上的某一目录建立绑定关系。这就意味着,当我们在容器中的这个目录下写入数据时,容器会将其内容直接写入到宿主机上与此容器建立了绑定关系的目录。
在这里插入图片描述

3. 使用存储卷的好处

  1. 当容器关闭甚至被删除时,只要不删除与此容器绑定的在宿主机上的这个存储目录,我们就不用担心数据丢失了
  2. 通过这种方式管理容器,容器就可以脱离主机的限制,可以在任意一台部署了docker的主机上跑容器,而其数据则可以置于一个共享存储文件系统上,比如nfs。
  3. Docker的存储卷默认情况下是使用其所在的宿主机上的本地文件系统目录的,也就是说宿主机上有一块属于自己的硬盘,这个硬盘并没有共享给其他的Docker主机,而在这台主机上启动的容器所使用的存储卷是关联到此宿主机硬盘上的某个目录之上。
  4. 这就意味着容器在这台主机上停止运行或者被删除了再重建,只要关联到硬盘上的这个目录下,那么其数据还存在。但如果在另一台主机上启动一个新容器,那么数据就没了。而如果在创建容器的时候我们手动的将容器的数据挂载到一台nfs服务器上,那么这个问题就不再是问题了。

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

Docker存在的问题有:

  • 存储于联合挂载文件系统中,不易于宿主机访问
  • 容器间数据共享不便
  • 删除容器其数据会丢失

4. 存储卷管理方式

存储卷(Data Volume)于容器初始化时被自动创建,由base image提供的卷中的数据会于此期间完成复制。

Volume的初衷是独立于容器的生命周期实现数据持久化,因此删除容器之时既不会删除卷,也不会对未被引用的卷做垃圾回收操作。

存储卷为Docker提供了独立于容器的数据管理机制,我们可以把镜像想象成静态文件,例如“程序”,把卷类比为动态内容,例如“数据”。所以镜像可以重用,而卷则可以共享。

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

在这里插入图片描述

5. 存储卷的分类

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

  • 绑定挂载卷
    • 指向主机文件系统上用户指定位置的卷
  • Docker 管理的卷
    • Docker 守护进程在 Docker 拥有的主机文件系统的一部分中创建托管卷

在这里插入图片描述

6.容器数据管理

容器中管理数据主要有两种方式:

  • 数据卷(Data Volumes)
  • 数据卷容器(Data Volumes Containers)
    容器Volume使用语法:
Docker-managed volume
docker run -it --name CONTAINER_NAME -v VOLUMEDIR IMAGE_NAME
[root@localhost ~]# docker run -dit --name b1 -v /data  busybox 
3027832f86c18ff9269235c3cb9219a5cfee4a9a8a532a37a5ad22bf5f9160fd

# 进入容器并在/data下创建一个a.txt的文件 
[root@localhost ~]# docker exec -it b1 /bin/sh
/ # ls
bin   data  dev   etc   home  proc  root  sys   tmp   usr   var
/ # cd data 
/data # echo 'haihaihai' > a.txt
/data # cat a.txt 
haihaihai

# 另起一个终端进入b1容器查看刚刚创建的a.txt
[root@localhost ~]# docker inspect b1
"Mounts": [
            {
                "Type": "volume",
                "Name": "838f6b862407a4e2d33cafce7a58f89fa8a9438f4aaece0cacc2643c7bd2c6c4",
                "Source": "/var/lib/docker/volumes/838f6b862407a4e2d33cafce7a58f89fa8a9438f4aaece0cacc2643c7bd2c6c4/_data", // 找到文件存放位置
                "Destination": "/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }

[root@localhost ~]# cd /var/lib/docker/volumes/838f6b862407a4e2d33cafce7a58f89fa8a9438f4aaece0cacc2643c7bd2c6c4/_data
[root@localhost _data]# ls
a.txt
[root@localhost _data]# cat a.txt 
haihaihai

绑定挂载卷

docker run -it --name CONTAINER_NAME -v HOSTDIR:VOLUMEDIR IMAGE_NAME
```cpp
# 加载宿主机的/opt/dtat目录到容器的/data目录 
[root@localhost ~]# docker run -dit --name b2 -v /opt/dtat:/data busybox
ef3e6b22396e9afd117a799ade885a0b5b68b3e0d3a11d90621adaf025bd1ff1
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND              CREATED          STATUS          PORTS     NAMES
ef3e6b22396e   busybox   "sh"                 6 seconds ago    Up 5 seconds              b2
3027832f86c1   busybox   "sh"                 25 minutes ago   Up 25 minutes             b1
b5661ce9d25b   httpd     "httpd-foreground"   16 hours ago     Up 45 minutes   80/tcp    web

# 进入b2容器里面的/data目录下创建一个文件一个目录
[root@localhost ~]# docker exec -it b2 /bin/sh
/ # cd data
/data # touch a
/data # mkdir b
/data # ls
a  b

# 另起一个终端在宿主机上查看刚刚在b2容器里面创建的文件和目录,并在宿主机的/opt/dtat目录下也创建文件
[root@localhost dtat]# ls
a  b
[root@localhost dtat]# touch c d
[root@localhost dtat]# ls
a  b  c  d

# 返回b2容器查看
/data # ls
a  b  c  d

//这里宿主机的/opt/dtat和容器的/data目录可以事先存在也可以不存在

7. 在容器中使用数据卷

  1. 在容器内创建一个数据卷
# 使用httpd镜像创建一个v2容器,并创建一个数据卷挂载到容器的/dtat目录下
[root@localhost ~]# docker run -dit -P --name v2 -v /data httpd
04af3dd4de1cde9d4abf8118abdd92a18c7383670c1515f268b546b52f8e4bcf
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND              CREATED          STATUS             PORTS                                     NAMES
04af3dd4de1c   httpd     "httpd-foreground"   3 seconds ago    Up 1 second        0.0.0.0:49153->80/tcp, :::49153->80/tcp   v2
04ffcc991c83   busybox   "sh"                 55 seconds ago   Up 53 seconds                                                v1
3027832f86c1   busybox   "sh"                 56 minutes ago   Up 56 minutes                                                b1
b5661ce9d25b   httpd     "httpd-foreground"   16 hours ago     Up About an hour   80/tcp                                    web
[root@localhost ~]# ss -antl
State      Recv-Q     Send-Q           Local Address:Port            Peer Address:Port     Process     
LISTEN     0          128                    0.0.0.0:49153                0.0.0.0:*                    
LISTEN     0          128                    0.0.0.0:22                   0.0.0.0:*                    
LISTEN     0          128                       [::]:49153                   [::]:*                    
LISTEN     0          128                          *:2375                       *:*                    
LISTEN     0          128                       [::]:22                      [::]:*           

在这里插入图片描述

挂载一个主机目录作为数据卷

[root@localhost ~]# docker run -dit --name web1 -P -v /opt/web1:/web1 httpd
1ea5f104d4619c8061360db50f82e2c7a14b8e187abeabd72c90a187a7d1a26f
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND              CREATED             STATUS             PORTS                                     NAMES
1ea5f104d461   httpd     "httpd-foreground"   10 seconds ago      Up 10 seconds      0.0.0.0:49154->80/tcp, :::49154->80/tcp   web1

在这里插入图片描述

这个功能在进行测试的时候非常方便,比如用户可以放置一些程序或数据到本地目录中,然后在容器内运行和使用。另外,本地目录的路径必须是绝对路径,如果目录不存在,Docker会自动创建

Docker挂载数据卷的默认权限是读写(rw),用户也可以通过(ro)指定为只读

[root@localhost ~]# docker run -dit --name web1  -v /opt/web1:/usr/local/apache2/htdocs:ro httpd
de030d79824865de84ed0f28a6b6bb29f1038969baf288d07120662d62ef0228
[root@localhost ~]# cd /opt/web1
[root@localhost web1]# echo 'hiahiahia' > index.html
[root@localhost web1]# cat index.html 
hiahiahia

# 进入到容器里
[root@localhost ~]# docker exec -it web1 /bin/bash
root@de030d798248:/usr/local/apache2# cd htdocs/
root@de030d798248:/usr/local/apache2/htdocs# ls
index.html
root@de030d798248:/usr/local/apache2/htdocs# cat index.html 
hiahiahia
root@de030d798248:/usr/local/apache2/htdocs# rm -rf index.html 
rm: cannot remove 'index.html': Read-only file system
//因为设置了只读权限所以容器不可以删除index.html

挂载一个本地主机文件作为数据卷

-v选项也可以从主机挂载单个文件到容器中作为数据卷:
[root@localhost ~]# docker run -dit --name web1 -v ~/.bash_history:/.bash_history httpd
e59f92434ee4108ba24bc3af37dd8c663673da2e0fe7cf915a0e143a802a8026
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND              CREATED          STATUS          PORTS     NAMES
e59f92434ee4   httpd     "httpd-foreground"   23 seconds ago   Up 23 seconds   80/tcp    web1
[root@localhost ~]# cd /opt/web1
[root@localhost web1]# history 
···
····
130  cd /opt/web1
131  history 

如果直接挂载一个文件到容器,使用文件编辑工具,包括vi或者sed去修改文件内容的时候,可能会造成inode的改变,这样将会导致错误。所以推荐的方式是直接挂载文件所在的目录。

8. 数据卷容器

  1. 创建一个数据卷容器aaa,并在其中创建一个数据卷挂载到/aaa
[root@localhost ~]# docker run -it -d --name aaa -v /aaa centos
2826a312be313e6d78dc7a022815894f826ed0be21bc5663f4313e739e8f19d8

  1. 可以多次使用–volumes-from参数来从多个容器挂载多个数据卷。还可以从其他已挂载了容器卷的容器来挂载数据卷例如创建db1和db2两个容器例如创建db1和db2两个容器并从aaa容器挂载数据卷:
[root@localhost ~]#  docker run -dit --name db1 --volumes-from aaa centos
4f00547982855434db0042757a24cb474f29dcf70532b97f8a9a8ac5b5a6d77b
[root@localhost ~]# docker run -dit --name db2 --volumes-from aaa centos
f4265f3685bfb62fbd7f7517cb47df132a7b7d829ce9f6fbe4ec6c2fa9ce3a5b
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS     NAMES
f4265f3685bf   centos    "/bin/bash"   9 seconds ago   Up 6 seconds             db2
4f0054798285   centos    "/bin/bash"   3 minutes ago   Up 3 minutes             db1
2826a312be31   centos    "/bin/bash"   4 minutes ago   Up 4 minutes             aaa

此时,容器db1和db2都挂载同一个数据卷到相同的/dbdata目录。三个容器任何一方在该目录下的写入,其他容器都可以看到。

# 进入容器 在db1容器中创建一个test文件:
[root@localhost ~]# docker exec -it db1 /bin/bash
[root@4f0054798285 /]# ls
aaa  bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@4f0054798285 /]# cd aaa
[root@4f0054798285 aaa]# ls
[root@4f0054798285 aaa]# touch test
[root@4f0054798285 aaa]# ls
test

# 在db2上查看
[root@localhost ~]# docker exec -it db2 /bin/bash
[root@f4265f3685bf /]# ls
aaa  bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@f4265f3685bf /]# cd aaa
[root@f4265f3685bf aaa]# ls
test

可以多次使用–volumes-from参数来从多个容器挂载多个数据卷。还可以从其他已挂载了容器卷的容器来挂载数据卷:

[root@localhost ~]#  docker run -dit --name db3 --volumes-from db1 centos
4c86c29fd7839b7e677a55a5afccee3ac876bc379b7d4804879ad556fcb937e5
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS          PORTS     NAMES
4c86c29fd783   centos    "/bin/bash"   5 seconds ago    Up 3 seconds              db3
f4265f3685bf   centos    "/bin/bash"   12 minutes ago   Up 12 minutes             db2
4f0054798285   centos    "/bin/bash"   16 minutes ago   Up 16 minutes             db1
2826a312be31   centos    "/bin/bash"   16 minutes ago   Up 16 minutes             aaa
[root@localhost ~]# docker exec -it db3 /bin/bash
[root@4c86c29fd783 /]# ls --color
aaa  bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@4c86c29fd783 /]# cd aaa/
[root@4c86c29fd783 aaa]# ls
test

使用–volumes-from参数所挂载数据卷的容器自身并不需要保持在运行状态

如果删除了挂载的容器(包括dbdata、db1和db2),数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时显式使用docker rm -v命令来指定同时删除关联的容器。

9. 利用数据卷容器迁移数据

使用下面的命令来备份aaa数据卷容器内的数据卷:

[root@localhost ~]# docker run --name worker --volumes-from aaa -v $(pwd):/backup centos tar cvf /backup/backup.tar /aaa
tar: Removing leading `/' from member names
/aaa/
/aaa/test
/aaa/qqq/

[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS                      PORTS     NAMES
3810814f67ad   centos    "tar cvf /backup/bac…"   48 seconds ago       Exited (0) 46 seconds ago             worker
7d6f3031cab2   centos    "cvf /backup/backup.…"   About a minute ago   Created                               qqq
4c86c29fd783   centos    "/bin/bash"              6 minutes ago        Up 6 minutes                          db3
f4265f3685bf   centos    "/bin/bash"              19 minutes ago       Up 19 minutes                         db2
4f0054798285   centos    "/bin/bash"              22 minutes ago       Up 22 minutes                         db1
2826a312be31   centos    "/bin/bash"              23 minutes ago       Up 23 minutes                         aaa
baf246b5d823   httpd     "httpd-foreground"       18 hours ago         Exited (0) 18 hours ago               w1
[root@localhost ~]# ls
anaconda-ks.cfg  backup.tar  passwd

首先利用centos镜像创建了一个容器worker。使用–volumes-from dbdata参数来让worker容器挂载aaa容器的数据卷(即aaa数据卷);使用-v $(pwd):/backup参数来挂载本地的当前目录到worker容器的/backup目录。
worker容器启动后,使用了tar cvf /backup/backup.tar /aaa命令来将/aaa下内容备份为容器内的/backup/backup.tar,即宿主主机当前目录下的backup.tar。

10. 恢复

如果要恢复数据到一个容器,可以按照下面的操作。首先创建一个带有数据卷的容器aaa2

[root@localhost ~]# docker run -it --name aaa2 -v /aaa centos /bin/bash
[root@ff3b38ac6b6a /]# 

创建另一个新的容器,挂载aaa2容器,并使用untar解压备份文件到所挂载的容器卷中即可

[root@localhost ~]# docker run --name aaa3 --volumes-from aaa2 -v $(pwd):/backup centos tar xf /backup/backup.tar
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                      PORTS     NAMES
7c4ed4229d48   centos    "tar xf /backup/back…"   18 seconds ago   Exited (0) 15 seconds ago             aaa3
ff3b38ac6b6a   centos    "/bin/bash"              4 minutes ago    Up 4 minutes                          aaa2
3810814f67ad   centos    "tar cvf /backup/bac…"   9 minutes ago    Exited (0) 9 minutes ago              worker
7d6f3031cab2   centos    "cvf /backup/backup.…"   10 minutes ago   Created                               qqq
4c86c29fd783   centos    "/bin/bash"              15 minutes ago   Up 15 minutes                         db3
f4265f3685bf   centos    "/bin/bash"              28 minutes ago   Up 28 minutes                         db2
4f0054798285   centos    "/bin/bash"              31 minutes ago   Up 31 minutes                         db1
2826a312be31   centos    "/bin/bash"              32 minutes ago   Up 32 minutes                         aaa
baf246b5d823   httpd     "httpd-foreground"       18 hours ago     Exited (0) 18 hours ago               w1

到aaa2容器查看/aaa里面的内容

[root@localhost ~]# docker run -it --name aaa2 -v /aaa centos /bin/bash
[root@ff3b38ac6b6a /]# 
[root@ff3b38ac6b6a /]# cd aaa
[root@ff3b38ac6b6a aaa]# ls
qqq  test