关于docker的数据管理
直接在容器里面写入数据是不好的习惯,但是可以通过数据卷和数据卷容器的方式来写入。
1、数据卷
数据卷的使用和Linux挂载文件目录是很相似的。简单的说,数据卷就是一个可以供容器使用的特殊目录。
它提供了很多特性:
-
可以在容器之间共享和重用,使得数据在容器间进行传递变得高效和方便。
-
对数据卷内数据的修改马上生效。
-
对数据卷的更新不会影响镜像,将应用和数据分割。
-
卷会一直存在,直到没有容器使用
-
创建一个数据卷(run命令加参数-v)
1 | docker volume create -d local test |
此时我们在/var/lib/docker/volumes路径下,会发现所创建的数据卷:
- 删除一个数据卷
数据卷是用来持久化数据的,所以数据卷的生命周期独立于容器。因此在容器结束后数据卷并不会被删除,如果需要删除数据卷,可以在docker rm删除容器的时候加上-v参数。
此外,如果删除挂载某个数据卷的容器没有使用-v参数清理,那么以后会很难清理。
- 挂载一个主机目录到容器
1 | docker run -ti --name volume2 -v /home/zsc/Music/:/myShare ubuntu:16.04 bash |
以上指令会把宿主主机的目录 /home/zsc/Music 挂载到容器的 myShare 目录下,然后你可以发现我们容器内的 myShare 目录就会包含宿主主机对应目录下的文件。
直接挂载宿主主机目录作为数据卷到容器内的方式在测试的时候很有用,你可以在本地目录放置一些程序,用来测试容器工作是否正确。当然,Docker 也可以挂载宿主主机的一个文件到容器,但是这会出现很多问题,所以不推荐这样做。如果你要挂载某个文件,最简单的办法就是挂载它的父目录。
2、数据卷容器
所谓数据卷容器,其实就是一个普通的容器,只不过这个容器专门作为数据卷供其它容器挂载。
首先,在运行 docker run 指令的时候使用 -v 参数创建一个数据卷容器:
1 | sudo docker run -ti -d -v /dataVolume --name v0 ubuntu:16.04 |
然后,创建一个新的容器挂载刚才创建的数据卷容器中的数据卷:使用 --volumes-from 参数
1 | sudo docker run -ti --volumes-from v0 --name v1 ubuntu:16.04 bash |
注意:
1、数据卷容器被挂载的时候不必保持运行!
2、如果删除了容器 v0 和 v1,数据卷并不会被删除。如果想要删除数据卷,执行 docker rm 命令的时候使用 -v 参数。
迁移数据
可以利用数据卷容器对其中的数据卷进行备份、恢复以实现数据的迁移。
1、备份
1 | docker run --volumes-from dbdata -v $(pwd):/backup --name worker ubuntu tar cvf /backup/backup.tar /dbdata |
这条命名是先利用Ubuntu镜像创建一个worker容器使用–volumes-from dbdata 来让worker容器挂载数据卷容器的数据,然后使用-v $(pwd):/backup 来挂载本地的当前目录到容器的backup目录下,然后当容器启动后使用tar命令进行备份,最后同步到本地。
2、恢复
如果要恢复数据到一个容器,首先创建一个带有数据卷的容器
1 | docker run -v /dbdata --name dbdata2 ubuntu /bin/bash |
然后创建另一个新的容器,挂载dbdata2的容器,并使用untar解压备份文件到所挂载的容器中
1 | docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar |
关于docker底层的一些东东
1、联合文件系统
docker将我们物理机的一些文件是以挂载的方式挂载在容器中,此时我们进行mount时使用只读模式,来降低恶意进程的攻击;其次,实现写入时复制,所有的容器可以先共享一个基本文件系统镜像,一旦需要向文件系统写入数据,就引导它写到与该容器相关的另一个特定文件系统中去。docker的存储文件系统是采用联合文件系统,其中它采用overlay和overlay2(现在默认是这个)存储文件驱动。overlayFS是一个类似于AUFS的现代联合文件系统,是内核提供的文件系统。
- overlay原理:
overlayFS将单个Linux主机上的两个目录合并成一个目录,这些目录被称为层,这一过程被称为联合挂载。OverlayFS底层目录称为lowerdir,高层目录称为upperdir。合并统一视图称为merged。当需要修改一个文件时,使用CoW将文件从只读的lower复制到可写的upper进行修改,结果也保存在upper层。在docker中,底下的只读层就是image,可写层就是container。
- overlay镜像结构
在/var/lib/docker/overlay/下(如果docker此时是overlay的话),每一个镜像都有一个对应的目录,包含了各层镜像的内容。而每一个镜像目录中包含的有:lower(用来记录下层镜像层,upper包含了容器层的内容,创建容器时将lower-id指向的镜像层目录以及upper目录联合挂载到merged目录。work用来完成如copy-on_write的操作)
-
对文件操作
-
读操作:
- 如果文件在容器层中不存在,则从lowerdir中读取
- 只在容器层存在,则直接从容器中读取该文件
- 文件存在容器和镜像层,容器层upperdir会覆盖lowerdir中的文件
-
写操作:
- 首次写入: 在upperdir中不存在,overlay和overlay2执行copy_up操作,把文件从lowdir拷贝到upperdir,由于overlayfs是文件级别的(即使文件只有很少的一点修改,也会产生的copy_up的行为),copy_up操作只发生在文件首次写入,以后都是只修改副本 ,overlayfs只适用两层,因此性能很好,查找搜索都更快
- 删除文件和目录: 当文件在容器被删除时,在容器层(upperdir)创建whiteout文件,镜像层的文件是不会被删除的,因为他们是只读的,但whiteout文件会阻止他们展现,当目录在容器内被删除时,在容器层(upperdir)一个不透明的目录,这个和上面whiteout原理一样,阻止用户继续访问,即便镜像层仍然存在
-
-
性能
- 页缓存:overlay支持页缓存共享,也就是说如果多个容器访问同一个文件,可以共享同一个页缓存,高效利用了内存
- copy_up:aufs和overlayfs,由于第一次写入都会导致copy_up,尤其是大文件,会导致写延迟,以后的写入不会有问题。由于overlayfs层级 比aufs的多,所以ovelayfs的拷贝高于aufs
- inode限制:使用overlay存储驱动可能导致inode过度消耗,特别是当容器和镜像很多的情况下,所以建议使用overlay2。
-
关于overlay2
overlay2的镜像结构,在/var/lib/docker/overlay2下有每一层的镜像,另外与overlay相比多了一个l/ 的目录,里面包含了很多软链接,使用短名称指向了其它层。
- overlay2的容器结构
启动一个容器,也是在/var/lib/docker/overlay2目录下生成一层容器层,目录包括diff,link,lower,merged,work,其中:diff记录了每一层自己内容的数据,link记录了该层链接目录,merged是挂载点
- 两个的区别:
本质区别是镜像层之间共享数据的方法不同:
overlay共享数据库是通过硬链接,只挂载一层,其它层通过最高层通过硬链接形式共享(增加了iNode的负担),而overlay2则是通过每层的lower文件。
2、namespace
对于PID命名空间,docker会将全部没有运行在当前开发容器中的进程隐藏起来,让恶意程序看不见,如果终止Pid为1的进程命名空间,容器里面所有的进程都会被终止;对于网络命令空间,管理员通过路由规则和iptable来构建容器的网络环境,这样的话容器内部的进程只能使用管理员许可的特定网络。
3、cgroup机制(control group)
通过cgroup机制来防止恶意的进程通过占有系统全部的资源来进行攻击(这是一种资源控制机制),它保证所有在一个控制组内的进程组成一个私密、隔离的空间,各进程拥有自己的进程号,并且无法访问组外部的其他进程,这样就形成了若干个相互隔离的区域。
4、docker的缓存大致介绍
我们在通过dockerfile构建镜像的时候,docker会按照指定的顺序去执行相应的指令,这个过程中,他会先查看是否有可用的重复的子镜像。并且它不是通过查看容器内文件来确定缓存的匹配,而是通过查看某一命令字符串是否与之前的一致来判断是否匹配,如果一致,则说明是由相同的命令来创建的子镜像,一旦没有,则生成新的。
5、关于docker的分层存储
docker镜像是一个特殊的文件系统。镜像提供了容器运行时所需的程序、库、资源、配置等资源,还包含了一些为运行时准备的一些配置参数。镜像是一个静态的概念。docker的设计者充分利用unions FS技术,把docker设计为分层存储的结构。也就是说,镜像是分层构建的,每一层是上面一层的基础,每一层在构建完成之后都不会在发生变化。这就说明了,构建镜像的时候我们要保证每一层都只包含我们的应用所需要的东西,不要包含不需要的文件,因为每一层在构建之后不再变化。分层存储还使得不同的镜像可以共享某些层,便于镜像的复用。
其中最底层是bootfs:包括引导系统的文件系统,包括bootloader和kernel,容器启动完成后会被卸载以节约内存资源。然后是rootfs:是docker的根文件系统,传统模式中,系统启动的时候,内核挂载rootfs时会首先将其挂载为“只读模式”,自检完成后重新挂载为读写模式,docker中,通过联合挂载技术为其额外挂载一个“可写层”。
最直观的就是我们在pull和commit的时候,镜像是分层处理的。