Docker 数据管理
当我们的某个运行中的Docker Container修改容器内部的数据时,新的数据存在哪里呢?数据文件如何在Container中存储的?我们先看一下下图
通过上图,我们看到容器存储的数据,主要是两总方式,一种是直接写到Container的文件系统中,另一种是是存储到数据卷
1直接写到Container容器内部
Docker镜像是分成设计的,镜像是只读的,通过镜像启动容器时(使用命令docker run
),容器添加了一层可读写的文件系统,用户写入的数据都保存在这一层中。
添加了一层可读写的文件系统
是啥意思?其实本质就是,创建并启动一个容器时,docker先拷贝一份镜像的文件系统,这层文件系统是只读的,不能修改的。然后在创建另外一个独立的目录,这个目录才是保存着修改的文件,这里是可读写的。而我们在使用docker exec -it <containerName> /bin/bash
命令进入容器内部时,会看到另外一个合并的文件系统,即镜像的文件系统目录+那个可读写的文件目录。
那么上面说的这几个文件目录在哪里,都打包在该容器的某个数据库文件中? 其实,这几个目录真的存在,而且有对应的docker主机下的目录。 所谓的包了一层其实是抽象概念,真实的是,他们分别是不同的几个文件夹。那他们在哪里呢?
我们通过docker inspect <containerName|Id>
查看某个容器的详情
docker inspect 2afe764a900a
[
{
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/e19ce17e6eff2d080d61ee5ad0979cd77d559119640b4c7b4d375ef51c79c2ce-init/diff:/var/lib/docker/overlay2/dfd5f693e66868f1a57ee34f20d79900f03e3e5d78cb869fb99c4da5482f91bf/diff:/var/lib/docker/overlay2/4df66261ce4e6c19b9906bc6811ee4f92e05f9909642b52afe0eb207f1f3a746/diff",
"MergedDir": "/var/lib/docker/overlay2/e19ce17e6eff2d080d61ee5ad0979cd77d559119640b4c7b4d375ef51c79c2ce/merged",
"UpperDir": "/var/lib/docker/overlay2/e19ce17e6eff2d080d61ee5ad0979cd77d559119640b4c7b4d375ef51c79c2ce/diff",
"WorkDir": "/var/lib/docker/overlay2/e19ce17e6eff2d080d61ee5ad0979cd77d559119640b4c7b4d375ef51c79c2ce/work"
},
"Name": "overlay2"
}
}
]
通过查看容器详情的GraphDriver.Data
,我们可以知道有下面几个重要目录
- LowerDir:image 镜像层(镜像本身,只读)
- UpperDir:容器的上层(读写)
- MergedDir:容器的文件系统,使用Union FS(联合文件系统)将lowerdir 和upperdir 合并给容器使用
- WorkDir:容器在 宿主机的工作目录
所以,每一个容器运行的分层的文件系统,其实都可以在宿主机中找到对应的(通常在docker安装目录下/var/lib/docker/overlay2
)
更神奇的是,当你在
UpperDir
中修改了任何数据,进入容器内部,也跟着修改,同理在容器的任何修改,都将回写到该目录下(与挂在数据卷后的效果一样的,只是,挂着数据卷才是官方推荐的正道),理解了这一点后很重要,我们对Docker 容器的理解又深入了一点;这也就是为什么Docker运行的效率高。其实Docker本质就是直接使用主机下的资源。
2 写到数据卷中
我们知道容器的设计之初就是用来经常删除创建的,所以直接把数据写到容器内,很容易不小心被删除。所以,一般重要的数据,都会挂着一个数据卷。也就是,把主机上的一个目录,映射或挂载到容器内部。
其实当我们理解了前面的介绍后,就无所谓内部外部了,本质都是操作主机上的某些目录;但是,抽象的思维很重要,必须要顺从docker容器的思维,区分内部与外部。
这里我们需要注意的是,docker提供三种写入到数据卷的类型,如下图
- bind muount #挂载任意目录或文件
- Volumes #固定路径的目录,docker管理
- tmpfs mounts #存放宿主机内存中
详情见docker官方介绍 关于存储数据卷
如何挂在一个数据卷?
docker run -itd --name <newContainerAlias> -v </host/path>:</conatiner/path> <imageName:tag> /bin/bash
# eg docker run -itd --name vUbuntu -v /docker/vUbuntu:/data ubuntu:15.10 /bin/bash
当然,Docker提供了一个更推荐的方式(本质都一样);先声明定义数据卷,在挂在使用数据卷
这样的好处是,该数据卷可被docker监控
# 创建数据卷
dokcer volume create myUbuntuData
# 挂载刚才的创建的数据卷
ocker run -itd --name vUbuntu -v myUbuntuData:/data ubuntu:15.10 /bin/bash
Bind mounts和Volumes行为上的差异
Volumes: 如果你将一个空Volume挂载到一个非空容器目录上,那么这个容器目录中的文件会被复制到Volume中,即容器目录原有文件不会被Volume覆盖。
Bind mounts: 如果你使用Bind mounts将一个宿主机目录挂载到容器目录上,此容器目录中原有的文件会被隐藏,从而只能读取到宿主机目录下的文件。
写到内存 tmpfs mounts
# 使用--tmpfs
docker run -dit --tmpfs /app ubuntu:15.10 /bin/bash
更多volume功能(NFS存储)的推荐一篇https://www.cnblogs.com/elvi/p/8463673.html