内容摘要
- 容器挂载主机目录
- 容器挂载主机文件
应用程序往往会使用数据库或者文件系统保存数据.比如web应用,需要保存静态网页和用户数据。对容器而言,里面运行的应用程序同样有持久化数据的需要,容器启动时需要加载数据,销毁时需要保留数据。本节带大家深入探讨容器如何使用存储。
容器挂载主机目录
容器可以直接挂载主机上的目录。
准备容器环境,在根目录下创建test文件夹,在其下面创建index.html文件,内容如下:
this is docker volume!
使用 httpd:2.4 容器,将主机test目录挂载到容器目录,运行容器,命令如下:
docker run -d -p 80:80 -v /root/test:/usr/local/apache2/htdocs http:2.4
参数 -p 80:80 :建立容器80端口和主机80端口映射,网络部分会在后面深入分析,这里只简单提一下。
-v:表示卷映射,用法是:-v 主机目录:容器目录。
容器起来后,使用如下命令访问httpd:
可以看到 index.html 文件中的内容。
进入容器中的挂载目录看看该文件是否在容器可以访问:
可以看到在容器中可以访问index.html文件。
如果我们在test文件夹再增加文件 welcome.html ,这样test下就有两个文件了,welcome.html文件内容如下:
welcome to docker volume!
运行容器,并使用curl访问html文件,命令如下:
docker run -d -p 80:80 -v /root/test:/usr/local/apache2/htdocs http:2.4curl 127.0.0.1:80curl 127.0.0.1:80/welcome.html
访问成功,如果不指定具体 html 文件,curl默认访问 index.html 文件。
进入容器中,也可以看到 html 文件存在挂载目录下;
如果在主机修改 index.html 文件,那么容器中的文件会相应修改吗?
修改index.html文件内容如下:
this is docker volume! hello docker volume!
使用curl访问,并进入容器查看文件,如下图:
可以看到,容器中的index.html文件内容也更改了。
现在反过来,我们在容器中修改index.html文件,然后在主机中观察:
我们将index.html内容改为:
updated index.
第1步:进入容器
第2步:修改index.html文件
第3步:使用exit离开容器
第4步:在主机上查看index.html文件发现内容已经变更。
在上面的操作中,我们可以在容器中修改index.html文件是因为我们有读写该文件的权限。
容器在挂载存储的时候可以指定读写权限,默认可读可写,也可以指定为只读。权限控制能提高数据的安全性。
注意:该权限只是约束在容器中对文件的操作,没有约束主机的操作。
下面我们重新运行上面的容器,并设置存储读写权限为只读,命令为:
docker run -d -p 80:80 -v /root/test:/usr/local/apache2/htdocs:ro http:2.4
在 -v 参数目录后面新加了 :ro,表示只读。
进入容器中,修改index.html文件:
可以看到修改失败,提示:Read-only file system。
在主机中修改:
先离开容器,之后修改文件,查看,文件已经修改了。
结论:只能控制容器修改文件的权限,不能控制主机修改文件的权限。
使用 docker inspect 观察容器:
上图截取了Mounts部分,可以看到这里记录了存储映射信息。
dockers也提供了一个命令查询容器存储卷,命令为:docker volume ls
查询数据为空,该命令没有查到数据。
可见该命令有缺陷,说明这种挂载方式,无法使用该命令查询。
我们测试下删除操作,分别在主机上删除和在容器中删除index.html。
在主机上删除index.html文件后,使用curl访问,出现404 Not Found错误。
进入容器查看文件是否存在:
可以看到index.html不存在;
在容器中删除文件的情景是一样的,大家可以自行测试下。
问题:如果主机目录和容器挂载目录下有同名的文件,那么会不会覆盖呢?
其实,在httpd容器中,/usr/local/apache2/htdocs目录下存在一个index.html文件,我们主机test目录下也有index.html文件,使用curl访问返回信息却是我们主机的文件内容,可见这里出现了文件覆盖,即主机的文件覆盖了容器的同名文件。
我们先不挂载主机目录,运行httpd容器,使用命令:
docker run -d -p 80:80 httpd:2.4
可以看到在容器中存在index.html文件,输出的内容是 It works!
下面我们重新运行容器,并挂载存储,命令参考上面
可以看到,index.html文件的内容发生了变化,可见原先的文件已经被覆盖了。
容器挂载主机文件
如果我们不想原先的index.html文件被覆盖,该如何做呢?
前面我们在挂载的时候,使用了目录挂载,实际上可以文件挂载,这样就能避免文件被覆盖。
运行容器,命令如下:
docker run -d -p 80:80 -v /root/test/index.html:/usr/local/apache2/htdocs/myindex.html httpd:2.4
运行容器时指定了主机的文件为index.html,也指定了容器的文件路径以及文件名myindex.html,该文件在容器中不存在。使用curl访问,结果都能访问得到。
进入该容器中:
容器中相关目录下出现了两个文件,其中myindex.html和主机上的index.html文件内容一样。
通过上面实验,可以知道:如果我们不需要覆盖容器中的文件,只需要增加新的文件,可以使用文件挂载。
问题:前面挂载的时候都是主机目录对容器目录,主机文件对容器文件,那么是否可以主机文件对容器目录呢?
测试如下:
运行容器,命令如下:
docker run -d -p 80:80 -v /root/test/index.html:/usr/local/apache2/htdocs httpd:2.4
容器运行失败,从错误信息可以看出主机的文件不满足要求。
至于主机目录对容器文件是否能否挂载等情景,大家可以自行测试。
总结
容器挂载主机目录
优点:
使用比较直观;可以用于测试,直接将源代码放在主机上,在主机上修改代码既能看到实际效果。
缺点:
由于数据需要保存在主机特定的目录或者文件中,不便于容器迁移到其他主机。
至此,容器挂载主机就讲解完了,大家按照上面的顺序依次实验以加深理解。
实验
运行容器,挂载主机目录
运行容器,挂载主机文件
常用命令
sudo docker rm -f $(sudo docker ps -a | awk 'NR == 1 {next} {print $1}')
sudo docker rmi -f $(sudo docker images | awk 'NR == 1 {next} {print $3}')
docker rmi httpd