就是数据持久化,因为容器中数据随着容器的删除,数据就没了,而且容器间数据不共享。
解决的办法就是,挂载和卷。
- Docker镜像由多个只读层叠加而成,启动容器时,Docker会加载只读镜像层并在镜像栈顶部添加一个读写层
- 如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的浅副本所隐藏,此即“写时复制机制”
先模拟docker容器内部数据丢失的例子。
这说明啥?说明在容器内的改动了,不会随着它的启动或停止而消失,但是要是再把它删了,在启动一个新的容器,之前容器数据就丢失了。我觉得这是理所当然的,没什么好奇怪的,但是还要BB下。
# 1.首先创建了容器
docker run -d --name nginx-test nginx
# 2.在容器里打开个终端
docker exec -t nginx-test bash
# 3.为nginx的default.conf创建个副本作为新的config
cd /etc/nginx/conf.d
cp default.conf nginx-test.conf
# 4.此处不会修改nginx-test.conf的内容,现在停止该容器
docker stop nginx-test
# 5.再次启动该容器
docker start ngnix-test
# 6.在容器内打开个终端
docekr exec -it nginx-test bash
# 7看看变更是否存在
cd /etc/nginx/conf.d
ls
default.conf nginx-test.conf
# 8.由于该容器之前仅仅是被停止了,所以数据还存留着。再来停止删除容器
docker stop ngnix-test
docker rm nginx-test
# 9.启动个容器, 启动的是新容器
docker -d --name nginx-test nginx
# 10.再次运行终端
docker exec -it nginx-test bash
# 11.检查nginx conf.d 目录的内容
cd /etc/ngnix.conf.d
ls
default.conf
绑定挂载
写在前面:
个人的理解,绑定挂载,就是给宿主机的目录起一个别名,然后在给这个别名放到容器中。
宿主机文件 <==> 容器文件, 宿主机和容器公用一个文件,不管谁修改文件,修改对对方都是可见的
在绑定挂在中,宿主机上的文件/目录会被挂载到容器中。
接下来,将会把Docker宿主机的主目录挂载到容器中一个名为host-home的目录。
这些输出表名,该挂载是绑定类型,其源是Docker宿主机目录,就是/User/xxx,而其挂载的目标是/host-hom。
docekr run -it --name mount-test type=bind, source="$HOME",target=/host-home ubuntu bash
或
docker run -it --nmae mount-test -v &HONE:/host-home ubuntu bash
然后查看刚才创建的容器
docekr inspect mount-test | jq .[0].Mounts
[
{
"Type": "bind",
"Source": "/Users/xxx",
"Destination":"/host-home"
}
]
然后进入容器终端,执行操作
# 查看挂载是否正常
cd /host-home
ls
cd /host-home
echo "This is a file created from container having kernrl `uname -r`" > host-home-file.txt
这个文件是从位于该容器的/host-home目录中一个拥有linuxkit-aufs内核的容器创建的。由于这是Docker宿主机目录的绑定挂载,所以也应该在Docker宿主机主目录创建这个文件。
进入宿主机
cd ~
ls -lah host-home-file.txt -h是显示更为易读的容量
会显示文件
这些信息表明,在容器中创建的文件的确可供容器外部使用。
然后可以停止容器,删除容器,再访问家目录,发现host-home-file.txt依然是存在的。
而且,要注意,绑定挂载的数据流是双向流动的,任何破坏性的操作,也都会对Docker宿主机造成负面影响。
所以说如果一段错误的脚本rm-rf 就可能造成Docker宿主机全面宕机。为避免这个问题,我们可以创建一个具有只读的选项的绑定挂载。
下面是只读挂载
docker run -it --name mount-test --mount type=bind,source="$HOME",target=/host-home,readonly ubuntu bash
或
docker run -it --name mount-test -v $HOME:/host-home:ro ubuntu bash
# 宿主机目录:容器目录
docker inspect mount-test | jq .[0].Mounts
# 发现变成ro,只读了。
[
{
...
"Mode":"ro",
}
]
然后可以测试下只读挂载
echo "This is a file created from container having kernel `uname -r`" > host-home-file.txt
# 会返回失败,说文件是只读的。
rm host-home-file.txt
# 也会返回失败,
卷
使用卷时,会在Docker宿主机的Docker存储目录中创建一个新目录,并且目录的内容时由Docker来管理的。
Docekr卷时目前最为推荐的将容器中存储的数据持久化的方法。卷完全是由Docker托管的,并且相对于绑定挂载而言,卷有很多优势
- 卷比绑定挂载更易于备份和转移
- 卷同时适用于Linux和Windows容器
- 可以顺利地跨多个容器共享卷
下面是关于Docker卷的几条命令
- docker volume create
- docker volume inspect
- docker volume ls
- docker volume prune
- docker volume rm
创建卷
docker volume create --name=<name of the volume> --label=<any extra metadata>
docekr volume create --name=nginx-volume
# 创建一个叫ngixn-volume 的卷
查看详情
docker volume inspect nginx-volume
docker volume inspect nginx-volume
[
{
...
"Mountpoint": "/var/lib/docker/volumes/nginx-volume/_data"
...
}
]
Mountpoint 属性列出了docker宿主机上的位置,该位置保存了包含卷数据的文件
列出卷信息
显示了宿主机上存在的所有卷
docker volume ls
精简卷
会移除本地未使用的本地卷,就是自动删除没使用的卷,不能指定要删哪个
docker volume prune <--force>
如果没有一个容器在使用卷,那么Docker就会认为这个卷是未使用的。 --force 是命令运行时将不会要求用户确认。
移除卷
docker 不会移除使用中的卷,并返回一条错误信息。
docker volume rm <name>
docker volume rm nginx-volume
下面是重点
在启动容器时使用卷
# 先创建个卷
docker volume create volume-test
docker run -it --name volume-test --mount source=volume-test,target=/data-volume ubuntu bash
或者
docker run -it --name volume-test -v volume:/data/volume ubuntu bash
# 卷的名:关联容器里的路径
# 在容器终端输入
echo "This is a file created from container having kernel `uname -r`" > docker_kernel_info.txt
# 然后删除停止容器
docker stop volume-test
docker rm volume-testa
# 重启启动个容器,再绑定上卷
docker run -it --name volume-test -v volume-test:data-volume ubuntu bash
cd /data-volume/
ls
docker-kernel-info.txt
cat docker -kernel-info.txt
使用卷就是为了让Docker将数据存储在由Docker自身管理的卷文件中。在启动新容器时,与run命令一起提供卷名称就会将这个卷附加到容器了,从而让之前保存的数据可提供新启动容器使用。
自己的理解:
和前面的挂载有啥子区别?感觉不一样,但又说不出,还在现在都用卷,也就不用花费我的精力去想用哪种方法了。
就是先创建个卷,然后启动容器时,加上这个卷,然后还要制定容器的哪个目录和这个卷关联。容器在这个指定目录存得数据,不会随着容器的删除而消失,再启动个容器,-v 指定这个卷和这个容器要关联的目录,在这个容器的目录里就可以直接访问上个容器存得数据了。说的自己都有些乱,但是我觉得自己时理解了,原理,