目录
传送门
从安装redis说起
什么是容器卷挂载
操作系统的挂载
日志文件一般是"首恶元凶"
挂载命令
容器卷挂载
卷挂载命令
启动时挂载
查看挂载卷信息
容器卷管理
查看卷列表
创建容器卷
具名挂载与匿名挂载
具名挂载
传送门
docker系列1:docker安装
docker系列2:阿里云镜像加速器
docker系列3:docker镜像基本命令
docker系列4:docker容器基本命令
docker系列5:docker安装nginx
docker系列6:docker安装redis
docker系列7:docker安装ES
从安装redis说起
在前面几节通过docker安装过了nginx、redis和ES,会发现通过docker安装运行软件的过程都差不多。但是在redis章节时,有一点区别:在使用Docker容器管理时,有时候需要对Redis进行配置,但是Docker镜像中并没有默认的redis.conf,需要手动设置redis.conf文件。
当时的解决方案是在启动命令中加入了一个配置:
docker run --name test_redis -p 6379:6379 -v /root/redis/redis.conf:/usr/local/etc/redis/redis.conf -d redis
其中的-v /root/redis/redis.conf:/usr/local/etc/redis/redis.conf就是容器卷挂载!
什么是容器卷挂载
在具体解释上面这条命令参数之前,先使用docker run --help看下官方的解释:
-v, --volume list Bind mount a volume 绑定挂载一个卷;可以指定多个为一个列表--volume-driver string Optional volume driver for the container 指定容器卷驱动--volumes-from list Mount volumes from the specified container(s)
光看上面这个解释第一次接触的可能还是比较模糊,要说清楚这个问题,可以先从传统操作操作系统的的挂载讲起
操作系统的挂载
日志文件一般是"首恶元凶"
不知道你有没有过这种经历:在linux上面搭建的应用系统服务,跑了一段时间之后会发生磁盘被占满了,甚至连登录服务器都登录不上,而且一般是客户上报的错误,开发很慌啊~~。
最后各种排查,发现在是日志过大(比如nacos默认的系统日志,XXL-job的触发日志)导致磁盘容量不够,这时可能就会让"运维背锅":
- 每隔一段时间手动去服务器删除日志文件(相关文件)
- 或者写个cron任务,自动删除日志文件
这种比较暴力的处理方式,在不那么"草台班子"的公司可能不会出现,这时运维能力强的公司一般会要求日志必须保留多久或者做备份:
- 对服务器各项指标做监控,并配置对应的自动化运维手段对日志备份
- 提前对日志容量做评估,配置对应的磁盘容量水位做预留
- 要求开发将日志输出到指定挂载盘上,空间足够大
对于传统自建的服务器,可以在购买物理机的时候选用磁盘容量比较大的机器,这个时候如果硬盘不量不够可以挂载单独的外设硬盘。随着云计算的发展,很多公司上云之后都会购买云主机(虚拟机)来搭建应用服务,这样扩容很方便且在一定规模下降低成本(这个命题最近非常火,此处不过多讨论持保留很意见)?这样就出现了NFS还有OSS等网络存储设备。不管是物理机还是虚拟机的挂载都可以统一称为磁盘挂载(用来区分前面提到的docker容器卷挂载)。下图是实际项目使用的一种解决方案:
挂载命令
对于挂载命令不是这里的重点,可以自行搜索或者查看
容器卷挂载
而容器的卷挂载跟磁盘挂载其实原理相似,不过容器卷挂载的初衷更多的是由于容器内的存储是易失的不能持久化,虽然容器容量也是其中很重要的一个原因。对此看下官方的解释:
By default all files created inside a container are stored on a writable container layer. This means that:
The data doesn't persist when that container no longer exists, and it can be difficult to get the data out of the container if another process needs it.
A container's writable layer is tightly coupled to the host machine where the container is running. You can't easily move the data somewhere else.
Writing into a container's writable layer requires a storage driver to manage the filesystem. The storage driver provides a union filesystem, using the Linux kernel. This extra abstraction reduces performance as compared to using data volumes, which write directly to the host filesystem.
Docker has two options for containers to store files on the host machine, so that the files are persisted even after the container stops: volumes, and bind mounts.
---------------------------------------------- 以下为机译 -----------------------------------------------------
默认情况下,在容器内创建的所有文件都存储在可写容器层上。这意味着:
当容器不存在时,数据不会持久存在,如果另一个进程需要,则很难将数据从容器中取出。
容器的可写层与运行容器的主机紧密耦合。你不能轻易地将数据移动到其他地方。
写入容器的可写层需要一个存储驱动程序来管理文件系统。存储驱动程序使用Linux内核提供了一个联合文件系统。与使用直接写入主机文件系统的数据卷相比,这种额外的抽象降低了性能。
Docker为容器在主机上存储文件提供了两个选项,这样即使在容器停止后文件也会被持久化:卷和绑定装载。
以上面的redis为例,docker运行redis镜像时不一定要强行增加-v才行:
- 在宿主机放置一分redis.conf文件
- 将上面的redis.conf文件拷贝到容器中
- 修改容器中的redis.conf文件达到修改redis配置的目的
现在来启动一个redis容器:docker run -it -d --name myredis redis
将宿主机的redis.conf文件拷贝到容器中:docker cp /root/redis/redis.conf myredis:/usr/local/etc/redis-conf/redis.conf
进入容器查看redis.conf文件: docker exec -it myredis /bin/bash
后面就可以指定redis.conf文件启动服务了,注意这里的redis.conf文件需要跟redis的版本一致,不然可能会启动失败
卷挂载命令
虽然上述方式可以达到跟卷挂载一样的效果,但是还是不如挂载来的方便,先看一下挂载命令!
启动时挂载
前面的redis运行时,通过-v命令称作启动时自动挂载:
docker run --name test_redis -p 6379:6379 -v /root/redis/redis.conf:/usr/local/etc/redis/redis.conf -d redis
- -v,表明进行卷挂载
- 后面接着路径:宿主机路径:容器内路径,比如/root/redis/redis.conf表示宿主机上面的redis.conf路径;/usr/local/etc/redis/redis.conf表示容器内的路径
既然是路径,除了上面挂载文件之外,肯定也可以挂载目录的。比如在刚才的命令中增加一个数据目录:-v /root/redis/data:/usr/local/etc/redis/data
然后分别查看宿主机与容器内的目录:
对于这一点,官网的解释:
If you start a container with a volume that doesn't yet exist, Docker creates the volume for you
从上面磁盘挂载特性,在容器内操作文件就跟操作本地一样。比如在容器内创建一个测试文件test.txt,然后在宿主机观察一下:
从这说明容器的挂载成功了!
查看挂载卷信息
如果要查看刚才redis挂载的卷信息,可以通过如下docker命令:docker inspect 容器名
在显示的容器里面查找到挂载卷信息:
容器卷管理
查看卷列表
如果要查看刚才redis挂载的卷信息,除了可以通过如下docker命令:docker inspect 容器名之外,还有专门的卷查看命令:docker volume ls
但是这个卷名字VOLUME NAME怎么这么奇怪? 因为这个是卷挂载自动生成的挂载卷名称,也称为"匿名挂载"。仔细看的话,前面的inspect里面有一项里面的Name也是类似:9287eb2555a9b48bb1f91c69489dd806e777aca0b22448d0d718e0c1c4bb7640
{"Type": "volume","Name": "9287eb2555a9b48bb1f91c69489dd806e777aca0b22448d0d718e0c1c4bb7640","Source": "/var/lib/docker/volumes/9287eb2555a9b48bb1f91c69489dd806e777aca0b22448d0d718e0c1c4bb7640/_data","Destination": "/data","Driver": "local","Mode": "","RW": true,"Propagation": ""}
而这一项就对应docker volume ls里面的一个卷:
如果查看此挂载卷信息:
会发现的确是刚才创建的,而匿名卷会默认跟宿主机的/var/lib/docker/volumes/VOLUME NAME/_data关联起来!
现在再测试一下,启动一个新的容器:
docker run --name test_redis3 -p 6379:6379 -v -v /root/redis/data2:/usr/local/etc/redis/data2 -d redis
运行之后,查看容器卷信息:
"Mounts": [{"Type": "bind","Source": "/root/redis/data2","Destination": "/usr/local/etc/redis/data2","Mode": "","RW": true,"Propagation": "rprivate"},{"Type": "volume","Name": "109806e8fe95be922b8cb8b6a54bcc7bc664edaaca0cc2803dbb9c41bfce206c","Source": "/var/lib/docker/volumes/109806e8fe95be922b8cb8b6a54bcc7bc664edaaca0cc2803dbb9c41bfce206c/_data","Destination": "/data","Driver": "local","Mode": "","RW": true,"Propagation": ""}]
创建容器卷
除了前面介绍的启动时自动挂载,还可以手动创建容器卷:
# my-vol为卷名称
docker volume create my-vol
执行一下上面的命令,并查看对应的卷列表:
具名挂载与匿名挂载
但是你会发现这种指定卷名称的创建方式,卷的名称不再是一种"看不懂"的字符串了。这种方式也叫作"具名挂载" !不过此时需要挂载的卷的宿主机路径都默认放到docker指定的目录下面了。而"匿名挂载"可以动态指定宿主机路径挂载的目录
具名挂载
有了手动创建的卷,那现在也可以通过启动时挂载具体的卷:
docker run --name test_redis -p 6379:6379 -v my-vol:/usr/local/etc/redis/data -d redis