目录
一、思考问题
1、手抄版
1.1 原版问题
57/58: 分别有一个web程序;
57---) 58
58---) 58
58-X-) 57
57-X-》57
- 57上面的服务没有启动
咋回事,咋解决;防火墙关了,能ping通,实在不知道咋办了,怎么确定57上面的服务有问题;
- 确认服务端口: netstat -ano | findstr :port -->没端口-->尝试重启服务-->观察服务日志--> 确保服务正常启动,并且日志无异常,再次确认服务端口(配置文件内的服务端口)进行访问 测试;
- 确认服务端口:netstat-ano | findstr :port --->有端口-->尝试重启服务-->观察服务日志--> 确认服务是否可以正常启动-->无异常正常启动进行访问测试;
- 测试可以访问-->梳理前置日志-->确认服务是否之前出现过宕机或者抛出异常,如果可以 确认时服务的问题非机器,中间件程序的问题,将问题给研发让研发协助解决;
- 怎么排除掉不是机器或者中间件程序的问题?
- 测试可以访问-->梳理前置日志-->确认服务是否之前出现过宕机或者抛出异常,如果可以 确认时服务的问题非机器,中间件程序的问题,将问题给研发让研发协助解决;
1.2 纸质版
略
2、电子版
2.1 问题描述
一个月前在两台操作系统均为 Windows 的内网服务器 A 和 B 上各部署了一套 Web 的项目,开放的服务端口都为 8080,两台服务器的防火墙规则都已配好。部署完项目后,测试也都能正常访问。一个月后,无法访问服务器A。具体为:服务器 A 能访问服务器 B的页面,服务器 B 也能访问自己的页面,但是服务器 B 访问不了服务器A的页面,服务器 A 自己也不能访问自己的页面。可能出现的问题是什么?怎么解决?
2.2 可能出现的问题
- 服务故障或:
- 服务器 A 上的 Web 服务可能出现故障,如服务进程崩溃、内存泄漏导致服务异常终止等情况。这会导致无法响应来自本地或其他服务器的访问请求。
- 也有可能服务器异常重启了,服务没有配置开机自启策略,忘记启动 Web 服务了
- 端口被占用或监听异常:
- 虽然之前配置好了防火墙规则,但可能有其他程序在服务器 A 上占用了 8080 端口,导致 Web 服务无法正常监听该端口。或者 Web 服务自身的监听配置出现问题,不再正确监听 8080 端口。
- 网络配置变更:
- 服务器 A 的网络配置可能在这一个月内发生了改变。例如,IP 地址发生变化(尽管在内部网络中这种情况相对较少)、子网掩码设置错误、网关配置问题等,导致其他服务器无法正确找到服务器 A 的服务。
- 防火墙规则动态变更:
- 尽管之前防火墙规则已配置好,但可能由于系统更新、安全策略调整或者其他软件的安装等原因,导致防火墙规则发生了动态变化,阻止了对服务器 A 的 8080 端口的访问。
- 配置文件可能出现的问题
- 监听地址变更
- 服务的配置文件中可能将监听地址设置错误。例如,原本应该监听所有可用 IP 地址(通常表示为0.0.0.0),但可能由于误操作或者配置更新,被设置为了一个特定的、无法访问的 IP 地址。这样就会导致只有在这个特定 IP 地址范围内的请求才能被接收,从而出现访问受限的情况。
- 虚拟主机配置问题
- 如果 Web 项目使用了虚拟主机配置,可能在配置文件中出现了错误。比如,在区分不同域名或子域名的访问时,相关的规则设置错误。可能错误地将服务器 A 对应的虚拟主机配置项删除或者修改,导致服务器 A 无法正确响应请求。
- 上下文路径或资源路径修改
- 配置文件中关于 Web 项目的上下文路径(例如,原本访问路径是/webapp,现在被修改为/newwebapp)或者资源路径的设置可能发生了变化。这会使得之前可以正常访问的链接现在无法访问,因为请求的资源位置与实际服务提供的位置不匹配。
- 安全配置增强
- 为了提高安全性,可能在配置文件中添加了新的安全限制。例如,设置了 IP 访问白名单或黑名单,而服务器 A 的 IP 地址或者服务器 B 的 IP 地址可能不小心被添加到了黑名单中,或者从白名单中移除,从而导致访问问题。
- 监听地址变更
2.3 解决方法
- 检查服务状态:
- 在服务器 A 上,通过命令行工具(如在 Windows 下使用 tasklist 命令查找 Web 服务对应的进程,或者使用 netstat -ano | findstr 8080 查看有无端口)查看 Web 服务进程是否正在运行。如果没有运行,可以尝试手动启动服务,查看是否有错误提示。对于基于 Java 的 Web 服务,可以查看相关的日志文件(如catalina.out等)来确定服务终止的原因。
- 检查配置文件
- 定位配置文件位置
- 首先要确定 Web 服务的配置文件位置。对于不同的 Web 技术,配置文件位置不同。例如,对于 Tomcat 服务器,主要的配置文件是server.xml,通常位于Tomcat安装目录/conf下。
- 检查监听设置
- 在配置文件中查找与服务监听相关的部分。对于 Java Web 服务,查看<Connector>标签(在server.xml中)下的address和port属性。确保address属性设置为0.0.0.0(表示监听所有 IP 地址)或正确的内部网络 IP 地址,port属性设置为8080。
- 审查虚拟主机和资源路径配置
- 如果有虚拟主机配置,检查每个虚拟主机的DocumentRoot(对于基于 Apache 的服务器)或<Context>标签(对于 Tomcat 等服务器)下的docBase属性,确保它们指向正确的 Web 项目目录。同时,检查虚拟主机对应的域名或访问路径(如ServerName或path属性)是否正确设置。
- 检查安全配置
- 查看配置文件中是否有新添加的安全相关配置,如 IP 访问控制部分。如果发现有 IP 白名单或黑名单设置,确认服务器 A 和服务器 B 的 IP 地址是否在正确的列表中。如果有访问认证(如 HTTP 基本认证或基于表单的认证)相关配置,检查认证的配置参数是否正确,例如用户名和密码是否正确设置等。
- 定位配置文件位置
- 检查端口监听情况:
- 使用网络端口监听工具(如 Windows 下的netstat -ano命令)检查 8080 端口是否被正确监听。如果被其他程序占用,可以根据占用程序的 PID(进程标识符),通过taskkill命令终止该程序,然后重新启动 Web 服务。如果 Web 服务没有正确监听,可以检查服务的配置文件,确保监听端口设置正确。
- 检查网络配置:
- 在服务器 A 上,检查网络连接的详细信息,包括 IP 地址、子网掩码、网关等设置是否正确。可以通过ipconfig /all命令查看这些信息,并与服务器 B 的网络配置进行对比。如果发现 IP 地址等信息有误,可以通过修改网络适配器设置来更正。
- 检查防火墙规则:
- 仔细检查服务器 A 的防火墙规则。可以暂时关闭防火墙(在测试环境下),看是否能够恢复访问。如果可以恢复访问,那么说明防火墙规则存在问题。可以通过查看防火墙的日志文件来确定是哪些规则阻止了访问,然后对规则进行调整,允许对 8080 端口的访问。
- 网络连接层面
- 检查网络链路和交换机:
- 有可能是服务器 A 与服务器 B 之间的网络链路出现故障,或者连接服务器 A 的交换机端口出现问题。可以通过检查交换机端口的状态指示灯来初步判断端口是否正常工作。同时,使用网络测试工具(如ping命令)从服务器 A 向服务器 B 以及其他网络设备(如网关)发送 ICMP 数据包,检查网络连通性。如果ping不通,可能需要联系网络管理员检查网络布线、交换机配置等方面的问题。
- 检查 VLAN 配置(如果适用):
- 若网络环境中使用了 VLAN(虚拟局域网),确认服务器 A 和服务器 B 是否在同一个 VLAN 中。如果服务器 A 所在的 VLAN 配置发生变化,导致与服务器 B 不在同一 VLAN,那么即使防火墙规则和服务都正常,也可能无法访问。需要检查 VLAN 配置信息,确保服务器 A 和服务器 B 能够在同一 VLAN 内通信。
- 检查网络链路和交换机:
- 应用层协议和代理问题
- 检查 HTTP 协议设置:
- 虽然服务端口是 8080,但可能 HTTP 协议相关的设置出现问题。例如,服务端可能对 HTTP 请求头(如User - Agent、Referer等)进行了限制,而服务器 B 的请求头不符合服务器 A 的要求,导致请求被拒绝。可以通过使用网络抓包工具(如 Wireshark)在服务器 A 和服务器 B 上分别进行抓包,分析 HTTP 请求和响应的详细信息,查看是否存在不符合协议要求的情况。
- 检查代理服务器设置(如果有):
- 如果网络环境中存在代理服务器,检查代理服务器的配置。可能是代理服务器的规则发生变化,导致对服务器 A 的访问被拦截。可以尝试在服务器 B 上绕过代理服务器直接访问服务器 A(如果允许这样操作),或者检查代理服务器的访问规则和缓存设置,看是否存在影响访问服务器 A 的因素。
- 检查 HTTP 协议设置:
- 操作系统和软件更新的影响
- 检查系统更新和补丁:
- 操作系统在这一个月内可能进行了自动更新,某些更新可能会影响 Web 服务的运行。例如,更新后的安全补丁可能改变了系统的网络栈或者安全策略,导致服务无法正常访问。可以查看操作系统的更新日志,检查是否有与网络服务或安全相关的更新,尝试卸载最近安装的可能有影响的更新来恢复访问。
- 检查 Web 服务软件更新和兼容性:
- 同样,Web 服务软件本身可能进行了自动更新,新的版本可能与现有配置或者其他软件存在兼容性问题。可以回滚 Web 服务软件到之前正常运行的版本,或者检查 Web 服务软件的官方文档,查找是否有关于新版本中可能导致访问问题的已知问题及解决方案。
- 检查系统更新和补丁:
如果上面的步骤执行后还是无法解决,在排除服务问题而非服务器或中间件程序的问题后,将问题给研发组,让其协助解决。
2.4 梳理故障报告
以下是一份关于此次服务器 A 访问故障的故障报告示例:
《关于服务器 A Web 项目访问故障报告》
一、故障概述
在两台 Windows 内网服务器 A 和 B 上于 [具体部署日期] 部署了相同的 Web 项目,服务端口均为 8080,部署后测试访问正常。但在一个月后,服务器 A 出现无法被访问的情况,即服务器 A 自身无法访问自身页面,服务器 B 也无法访问服务器 A 的页面,然而服务器 A 能访问服务器 B 的页面且服务器 B 可正常访问自身页面。
二、故障排查过程
- 服务状态检查
- 在服务器 A 上使用tasklist命令查看 Web 服务进程,发现进程 [具体进程名] 已停止运行。检查相关日志文件(如[Web 服务日志文件名]),发现由于内存泄漏导致服务在 [具体时间] 异常终止。
- 端口监听检查
- 运用netstat -ano命令检查服务器 A 的 8080 端口,未发现该端口被其他程序占用。但在检查 Web 服务配置文件([配置文件路径及名称])时,发现监听地址被错误设置为[错误的 IP 地址],而非原本应设置的0.0.0.0,导致无法正常接收来自其他服务器的请求。
- 网络配置检查
- 通过ipconfig /all命令检查服务器 A 的网络配置,确认其 IP 地址、子网掩码、网关等设置均正确,且与服务器 B 在同一内网网段,排除网络配置错误导致的故障。
- 防火墙规则检查
- 仔细审查服务器 A 的防火墙规则,未发现有规则阻止对 8080 端口的访问。同时,暂时关闭防火墙后进行测试,故障依旧存在,确定不是防火墙规则变动引发的问题。
- 网络连接深入检查
- 使用ping命令从服务器 A 向服务器 B 及网关发送数据包,均能正常收到响应,表明网络链路基本正常。检查连接服务器 A 的交换机端口状态指示灯,显示正常工作状态。进一步检查 VLAN 配置信息,确认服务器 A 和服务器 B 处于同一 VLAN,排除网络连接层面的硬件和基础网络配置问题。
- 应用层协议和代理检查
- 利用 Wireshark 在服务器 A 和服务器 B 上进行抓包分析,未发现 HTTP 请求头存在不符合要求的情况,排除因 HTTP 协议设置导致的访问问题。经确认,网络环境中不存在代理服务器,无需进行代理服务器相关的故障排查。
- 操作系统和软件更新检查
- 查看操作系统的更新日志,未发现有影响 Web 服务运行的安全补丁或更新。检查 Web 服务软件的更新记录,发现其在 [更新日期] 自动更新到了新版本[新版本号]。经查阅官方文档,该新版本存在一个已知的兼容性问题,可能导致服务监听地址设置异常,与本次故障现象相符。
三、故障解决措施
- 针对内存泄漏导致的服务异常终止问题,优化了 Web 服务的代码,修复了内存泄漏的漏洞,并重新启动了 Web 服务进程。
- 将 Web 服务配置文件中的监听地址修正为0.0.0.0,使服务能够正确监听来自所有 IP 地址的请求。
- 由于 Web 服务软件新版本的兼容性问题,暂时回滚 Web 服务软件到之前正常运行的版本[旧版本号],待与软件供应商沟通确定解决方案后,再考虑升级到兼容的新版本。
四、预防措施建议
- 建立定期的服务器性能监控机制,及时发现并预警内存泄漏等可能导致服务异常的情况,以便提前采取措施修复。
- 在对服务器进行任何配置更改(包括软件更新)前,进行充分的测试和备份工作,确保更改不会影响现有服务的正常运行。
- 制定详细的服务器配置文档,包括网络配置、防火墙规则、服务配置等信息,并定期进行核对和更新,以便在出现故障时能够快速准确地进行排查。
五、总结
本次故障主要是由于 Web 服务内存泄漏导致进程异常终止以及软件更新后的兼容性问题引发服务监听地址设置错误,通过修复内存泄漏、修正配置文件和回滚软件版本等措施,成功恢复了服务器 A 的 Web 项目访问。在今后的服务器管理工作中,将加强监控、测试和文档管理等方面的工作,以降低类似故障发生的概率并提高故障处理效率。
[报告撰写人姓名]
[报告撰写日期]
你可以根据实际的故障排查和解决情况对上述报告内容进行修改和完善,使其更符合真实场景。
二、验证Docker的持久化
1、数据卷持久化介绍
1.1 数据卷(Volumes)
- 概念:
- 数据卷是 Docker 用于数据持久化的一种机制。它是一个可供一个或多个容器使用的特殊目录,数据卷的生命周期独立于容器。即使容器被删除,数据卷中的数据依然存在。
- 创建和使用方式:
- 命令行方式:可以使用docker volume create命令创建一个数据卷,例如docker volume create mydata。在运行容器时,通过-v或--mount参数来挂载这个数据卷。如docker run -d -v mydata:/app/data myimage,这里将名为mydata的数据卷挂载到容器内/app/data目录,容器内的应用程序可以在/app/data目录读写数据,这些数据会被持久化到数据卷中。
- Docker Compose 方式:在docker-compose.yml文件中,可以使用volumes关键字来定义数据卷并挂载。例如:
version: "3"
services:
myservice:
image: myimage
volumes:
- mydata:/app/data
volumes:
mydata:
这种方式可以方便地在多容器环境下进行数据卷的管理和挂载。
- 优点:
- 数据卷的内容可以在容器之间共享。例如,可以创建一个包含数据库数据的数据卷,然后让多个数据库容器挂载这个数据卷,方便数据的共享和备份。
- 数据卷可以在不同的宿主机之间迁移,只要数据卷的驱动支持(如在云环境中)。
- 数据卷的性能较好,因为它直接使用宿主机的文件系统,没有额外的中间层。
1.2 绑定挂载(Bind Mounts)
- 概念:
- 绑定挂载是将宿主机上的一个目录或文件挂载到容器内的指定目录。这使得容器可以直接访问宿主机的文件系统,实现数据的持久化和共享。
- 创建和使用方式:
- 命令行方式:使用docker run命令的-v参数,格式为宿主机目录:容器内目录。例如docker run -d -v /home/user/data:/app/data myimage,这样宿主机上/home/user/data目录中的内容就会挂载到容器内/app/data目录,容器内的应用程序可以读写这些数据,对容器内/app/data目录的修改也会直接反映到宿主机目录中。
- 注意事项:在使用绑定挂载时,要注意宿主机目录的权限问题。如果容器内的应用程序以特定用户身份运行,可能需要调整宿主机目录的权限,以确保应用程序能够正常读写。
- 优点:
- 方便在宿主机和容器之间共享数据,例如在开发环境中,可以将代码目录挂载到容器内,方便在宿主机上修改代码并在容器内运行测试。
- 可以利用宿主机现有的目录结构和数据,无需额外创建数据卷。
1.3 tmpfs 挂载(适用于临时数据)
- 概念:
- tmpfs挂载是将数据存储在内存中,而不是磁盘上。这对于存储一些不需要持久化的临时数据很有用,如缓存数据等。
- 创建和使用方式:
- 命令行方式:通过docker run命令的-v参数,格式为type=tmpfs,destination=/app/cache。例如docker run -d -v type=tmpfs,destination=/app/cache myimage,这样就会在容器内/app/cache目录创建一个tmpfs挂载,数据存储在内存中。
- 优点:
- 因为数据存储在内存中,所以读写速度非常快,适合存储对性能要求高的临时数据。
- 当容器停止时,tmpfs挂载中的数据会自动清除,不需要额外的清理工作。
2、需要验证持久化的问题
情况说明:对于分别使用Volumes和Bind Mounts进行持久化时,当出现一下情况时会发生什么?
当宿主机路径下有内容,容器的路径下也有内容时,会发生什么?
当宿主机路径下有内容,容器的路径下没有内容时,会发生什么?
当宿主机路径下没有内容,容器的路径下有内容时,会发生什么?
当宿主机路径下没有内容,容器的路径下没有内容时,会发生什么?
3、验证持久化
3.1 验证数据卷(Volumes)
3.1.1 当宿主机和容器的路径下都没有内容
命令示例:
ls /var/lib/docker/volumes/myvolume01/_data
docker volume create myvolume01
ls /var/lib/docker/volumes/myvolume01/_data
docker run -it centos /bin/bash -c "ls /opt"
docker run -itd --name centos01 -v myvolume01:/opt centos /bin/bash
ls /var/lib/docker/volumes/myvolume01/_data
docker exec -it centos01 /bin/bash
ls /opt
mkdir /opt/images
echo "First Test" |tee /opt/index.html
ls /opt
exit
ls /var/lib/docker/volumes/myvolume01/_data
cat /var/lib/docker/volumes/myvolume01/_data/index.html
输出结果:
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume01/_data
ls: 无法访问/var/lib/docker/volumes/myvolume01/_data: 没有那个文件或目录
[root@MineGi ~]# docker volume create myvolume01
myvolume01
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume01/_data
[root@MineGi ~]# docker run -it centos /bin/bash -c "ls /opt"
[root@MineGi ~]# docker run -itd --name centos01 -v myvolume01:/opt centos /bin/bash
bde479338af07c10bc016bbcbc2fca24e818854ac223366826dc2e2d7d38f2fc
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume01/_data
[root@MineGi ~]# docker exec -it centos01 /bin/bash
[root@bde479338af0 /]# ls /opt
[root@bde479338af0 /]# mkdir /opt/images
[root@bde479338af0 /]# echo "First Test" |tee /opt/index.html
First Test
[root@bde479338af0 /]# ls /opt
images index.html
[root@bde479338af0 /]# exit
exit
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume01/_data
images index.html
[root@MineGi ~]# cat /var/lib/docker/volumes/myvolume01/_data/index.html
First Test
[root@MineGi ~]#
3.1.2 当宿主机路径下有内容而容器的路径下没有内容
命令示例:
ls /var/lib/docker/volumes/myvolume01/_data
cat /var/lib/docker/volumes/myvolume01/_data/index.html
docker run -it centos /bin/bash -c "ls /opt"
docker run -itd --name centos02 -v myvolume01:/opt centos /bin/bash
ls /var/lib/docker/volumes/myvolume01/_data
cat /var/lib/docker/volumes/myvolume01/_data/index.html
docker exec -it centos02 /bin/bash
ls /opt
mkdir /opt/gifs
echo "Second Test" |tee -a /opt/index.html
ls /opt
exit
ls /var/lib/docker/volumes/myvolume01/_data
cat /var/lib/docker/volumes/myvolume01/_data/index.html
输出结果:
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume01/_data
images index.html
[root@MineGi ~]# cat /var/lib/docker/volumes/myvolume01/_data/index.html
First Test
[root@MineGi ~]# docker run -it centos /bin/bash -c "ls /opt"
[root@MineGi ~]# docker run -itd --name centos02 -v myvolume01:/opt centos /bin/bash
cec621c8bd003be073b3c0cd3780f3c04273a40afdab10a9a13fb42e33c4034a
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume01/_data
images index.html
[root@MineGi ~]# cat /var/lib/docker/volumes/myvolume01/_data/index.html
First Test
[root@MineGi ~]# docker exec -it centos02 /bin/bash
[root@cec621c8bd00 /]# ls /opt
images index.html
[root@cec621c8bd00 /]# mkdir /opt/gifs
[root@cec621c8bd00 /]# echo "Second Test" |tee -a /opt/index.html
Second Test
[root@cec621c8bd00 /]# ls /opt
gifs images index.html
[root@cec621c8bd00 /]# exit
exit
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume01/_data
gifs images index.html
[root@MineGi ~]# cat /var/lib/docker/volumes/myvolume01/_data/index.html
First Test
Second Test
[root@MineGi ~]#
3.1.3 当宿主机和容器的路径下都有内容
命令示例:
ls /var/lib/docker/volumes/myvolume01/_data
docker run -it nginx /bin/bash -c "ls /usr/share/nginx/html"
docker run -d --name nginx01 -v myvolume01:/usr/share/nginx/html nginx
ls /var/lib/docker/volumes/myvolume01/_data
cat /var/lib/docker/volumes/myvolume01/_data/index.html
docker exec -it nginx01 /bin/bash
ls /usr/share/nginx/html
mkdir /usr/share/nginx/html/doc
echo "The third test" |tee -a /usr/share/nginx/html/index.html
ls /usr/share/nginx/html
exit
ls /var/lib/docker/volumes/myvolume01/_data
cat /var/lib/docker/volumes/myvolume01/_data/index.html
docker inspect nginx01 |grep -w IPAddress
curl 172.17.0.4
输出结果:
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume01/_data
gifs images index.html
[root@MineGi ~]# docker run -it nginx /bin/bash -c "ls /usr/share/nginx/html"
50x.html index.html
[root@MineGi ~]# docker run -d --name nginx01 -v myvolume01:/usr/share/nginx/html nginx
5d5212941bc97d47a5bc1215f74d11477a9466383aef27aee8dd155bde1563a7
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume01/_data
gifs images index.html
[root@MineGi ~]# cat /var/lib/docker/volumes/myvolume01/_data/index.html
First Test
Second Test
[root@MineGi ~]# docker exec -it nginx01 /bin/bash
root@5d5212941bc9:/# ls /usr/share/nginx/html
gifs images index.html
root@5d5212941bc9:/# mkdir /usr/share/nginx/html/doc
root@5d5212941bc9:/# echo "The third test" |tee -a /usr/share/nginx/html/index.html
The third test
root@5d5212941bc9:/# ls /usr/share/nginx/html
doc gifs images index.html
root@5d5212941bc9:/# exit
exit
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume01/_data
doc gifs images index.html
[root@MineGi ~]# cat /var/lib/docker/volumes/myvolume01/_data/index.html
First Test
Second Test
The third test
[root@MineGi ~]# docker inspect nginx01 |grep -w IPAddress
"IPAddress": "172.17.0.4",
"IPAddress": "172.17.0.4",
[root@MineGi ~]# curl 172.17.0.4
First Test
Second Test
The third test
[root@MineGi ~]#
3.1.4 当宿主机路径下没有内容而容器的路径下有内容
命令示例:
ls /var/lib/docker/volumes/myvolume02/_data
docker volume create myvolume02
ls /var/lib/docker/volumes/myvolume02/_data
docker run -it nginx /bin/bash -c "ls /usr/share/nginx/html"
docker run -d --name nginx02 -v myvolume02:/usr/share/nginx/html nginx
ls /var/lib/docker/volumes/myvolume02/_data
docker exec -it nginx02 /bin/bash
ls /usr/share/nginx/html
mkdir /usr/share/nginx/html/doc
echo "The fourth test" |tee /usr/share/nginx/html/test.html
ls /usr/share/nginx/html
exit
ls /var/lib/docker/volumes/myvolume02/_data
cat /var/lib/docker/volumes/myvolume02/_data/test.html
docker inspect nginx02 |grep -w IPAddress
curl 172.17.0.2/test.html
输出结果:
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume02/_data
ls: 无法访问/var/lib/docker/volumes/myvolume02/_data: 没有那个文件或目录
[root@MineGi ~]# docker volume create myvolume02
myvolume02
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume02/_data
[root@MineGi ~]# docker run -it nginx /bin/bash -c "ls /usr/share/nginx/html"
50x.html index.html
[root@MineGi ~]# docker run -d --name nginx02 -v myvolume02:/usr/share/nginx/html nginx
7c62452975eb15b280d8900a0d1a268565454b81a430aae5fd4feb7053239be0
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume02/_data
50x.html index.html
[root@MineGi ~]# docker exec -it nginx02 /bin/bash
root@7c62452975eb:/# ls /usr/share/nginx/html
50x.html index.html
root@7c62452975eb:/# mkdir /usr/share/nginx/html/doc
root@7c62452975eb:/# echo "The fourth test" |tee /usr/share/nginx/html/test.html
The fourth test
root@7c62452975eb:/# ls /usr/share/nginx/html
50x.html doc index.html test.html
root@7c62452975eb:/# exit
exit
[root@MineGi ~]# ls /var/lib/docker/volumes/myvolume02/_data
50x.html doc index.html test.html
[root@MineGi ~]# cat /var/lib/docker/volumes/myvolume02/_data/test.html
The fourth test
[root@MineGi ~]# docker inspect nginx02 |grep -w IPAddress
"IPAddress": "172.17.0.2",
"IPAddress": "172.17.0.2",
[root@MineGi ~]# curl 172.17.0.2/test.html
The fourth test
[root@MineGi ~]#
3.2 验证绑定挂载(Bind Mounts)
3.2.1 当宿主机和容器的路径下都没有内容
命令示例:
mkdir -p /data/myvolume01
ls /data/myvolume01
docker run -it centos /bin/bash -c "ls /opt"
docker run -itd --name 01-centos -v /data/myvolume01:/opt centos /bin/bash
ls /data/myvolume01
docker exec -it 01-centos /bin/bash
ls /opt
mkdir /opt/images
echo "First Test" |tee /opt/index.html
ls /opt
exit
ls /data/myvolume01
cat /data/myvolume01/index.html
输出结果:
[root@MineGi ~]# mkdir -p /data/myvolume01
[root@MineGi ~]# ls /data/myvolume01
[root@MineGi ~]# docker run -it centos /bin/bash -c "ls /opt"
[root@MineGi ~]# docker run -itd --name 01-centos -v /data/myvolume01:/opt centos /bin/bash
ae4c11249592c2f0231c641e5fd71dc989902fb913d05c17baa35ff004fe7640
[root@MineGi ~]# ls /data/myvolume01
[root@MineGi ~]# docker exec -it 01-centos /bin/bash
[root@ae4c11249592 /]# ls /opt
[root@ae4c11249592 /]# mkdir /opt/images
[root@ae4c11249592 /]# echo "First Test" |tee /opt/index.html
First Test
[root@ae4c11249592 /]# ls /opt
images index.html
[root@ae4c11249592 /]# exit
exit
[root@MineGi ~]# ls /data/myvolume01
images index.html
[root@MineGi ~]# cat /data/myvolume01/index.html
First Test
[root@MineGi ~]#
3.2.2 当宿主机路径下有内容而容器的路径下没有内容
命令示例:
ls /data/myvolume01
docker run -it centos /bin/bash -c "ls /opt"
docker run -itd --name 02-centos -v /data/myvolume01:/opt centos /bin/bash
ls /data/myvolume01
cat /data/myvolume01/index.html
docker exec -it 02-centos /bin/bash
ls /opt
mkdir /opt/gifs
echo "Second Test" |tee -a /opt/index.html
ls /opt
exit
ls /data/myvolume01
cat /data/myvolume01/index.html
输出结果:
[root@MineGi ~]# ls /data/myvolume01
images index.html
[root@MineGi ~]# docker run -it centos /bin/bash -c "ls /opt"
[root@MineGi ~]# docker run -itd --name 02-centos -v /data/myvolume01:/opt centos /bin/bash
ad0773af795ace32a0a3c42bb4456280f4c72a600ec438ab10cc51f174d483ac
[root@MineGi ~]# ls /data/myvolume01
images index.html
[root@MineGi ~]# cat /data/myvolume01/index.html
First Test
[root@MineGi ~]# docker exec -it 02-centos /bin/bash
[root@ad0773af795a /]# ls /opt
images index.html
[root@ad0773af795a /]# mkdir /opt/gifs
[root@ad0773af795a /]# echo "Second Test" |tee -a /opt/index.html
Second Test
[root@ad0773af795a /]# ls /opt
gifs images index.html
[root@ad0773af795a /]# exit
exit
[root@MineGi ~]# ls /data/myvolume01
gifs images index.html
[root@MineGi ~]# cat /data/myvolume01/index.html
First Test
Second Test
[root@MineGi ~]#
3.2.3 当宿主机和容器的路径下都有内容
命令示例:
ls /data/myvolume01
docker run -it nginx /bin/bash -c "ls /usr/share/nginx/html"
docker run -d --name 01-nginx -v /data/myvolume01:/usr/share/nginx/html nginx
ls /data/myvolume01
cat /data/myvolume01/index.html
docker exec -it 01-nginx /bin/bash
ls /usr/share/nginx/html
mkdir /usr/share/nginx/html/doc
echo "The third test" |tee -a /usr/share/nginx/html/index.html
ls /usr/share/nginx/html
exit
ls /data/myvolume01
cat /data/myvolume01/index.html
docker inspect 01-nginx |grep -w IPAddress
curl 172.17.0.5
输出结果:
[root@MineGi ~]# ls /data/myvolume01
gifs images index.html
[root@MineGi ~]# docker run -it nginx /bin/bash -c "ls /usr/share/nginx/html"
50x.html index.html
[root@MineGi ~]# docker run -d --name 01-nginx -v /data/myvolume01:/usr/share/nginx/html nginx
e774d8672b0ce99f15e438c0aad85a0abfdc31abe57fa828f3520c7c27de305f
[root@MineGi ~]# ls /data/myvolume01
gifs images index.html
[root@MineGi ~]# cat /data/myvolume01/index.html
First Test
Second Test
[root@MineGi ~]# docker exec -it 01-nginx /bin/bash
root@e774d8672b0c:/# ls /usr/share/nginx/html
gifs images index.html
root@e774d8672b0c:/# mkdir /usr/share/nginx/html/doc
root@e774d8672b0c:/# echo "The third test" |tee -a /usr/share/nginx/html/index.html
The third test
root@e774d8672b0c:/# ls /usr/share/nginx/html
doc gifs images index.html
root@e774d8672b0c:/# exit
exit
[root@MineGi ~]# ls /data/myvolume01
doc gifs images index.html
[root@MineGi ~]# cat /data/myvolume01/index.html
First Test
Second Test
The third test
[root@MineGi ~]# docker inspect 01-nginx |grep -w IPAddress
"IPAddress": "172.17.0.5",
"IPAddress": "172.17.0.5",
[root@MineGi ~]# curl 172.17.0.5
First Test
Second Test
The third test
[root@MineGi ~]#
3.2.4 当宿主机路径下没有内容而容器的路径下有内容
命令示例:
mkdir -p /data/myvolume02
ls /data/myvolume02
docker run -it nginx /bin/bash -c "ls /usr/share/nginx/html"
docker run -d --name 02-nginx -v /data/myvolume02:/usr/share/nginx/html nginx
ls /data/myvolume02
docker exec -it 02-nginx /bin/bash
ls /usr/share/nginx/html
mkdir /usr/share/nginx/html/doc
echo "The fourth test" |tee /usr/share/nginx/html/test.html
ls /usr/share/nginx/html
exit
ls /data/myvolume02
cat /data/myvolume02/test.html
docker inspect 02-nginx |grep -w IPAddress
curl 172.17.0.6/test.html
输出结果:
[root@MineGi ~]# mkdir -p /data/myvolume02
[root@MineGi ~]# ls /data/myvolume02
[root@MineGi ~]# docker run -it nginx /bin/bash -c "ls /usr/share/nginx/html"
50x.html index.html
[root@MineGi ~]# docker run -d --name 02-nginx -v /data/myvolume02:/usr/share/nginx/html nginx
7d4b386c9b81be57dbcc1132dd0c73737000ce4ed5e1b4a84202409fddde31a1
[root@MineGi ~]# ls /data/myvolume02
[root@MineGi ~]# docker exec -it 02-nginx /bin/bash
root@7d4b386c9b81:/# ls /usr/share/nginx/html
root@7d4b386c9b81:/# mkdir /usr/share/nginx/html/doc
root@7d4b386c9b81:/# echo "The fourth test" |tee /usr/share/nginx/html/test.html
The fourth test
root@7d4b386c9b81:/# ls /usr/share/nginx/html
doc test.html
root@7d4b386c9b81:/# exit
exit
[root@MineGi ~]# ls /data/myvolume02
doc test.html
[root@MineGi ~]# cat /data/myvolume02/test.html
The fourth test
[root@MineGi ~]# docker inspect 02-nginx |grep -w IPAddress
"IPAddress": "172.17.0.6",
"IPAddress": "172.17.0.6",
[root@MineGi ~]# curl 172.17.0.6/test.html
The fourth test
[root@MineGi ~]#
4、结论和总结
Volumes 情况分析
- 当宿主机路径下有内容,容器的路径下也有内容时:
- 当使用数据卷挂载时,容器内路径的原始内容会被隐藏。宿主机的数据卷内容会挂载到容器指定路径,容器内应用程序访问该路径时,看到的是数据卷中的内容。如果数据卷为空,那么容器内路径的原始内容会在挂载后被 “覆盖” 隐藏;如果数据卷有内容,这些内容将替换容器内路径原有的内容供应用程序访问。
- 当宿主机路径下有内容,容器的路径下没有内容时:
- 宿主机数据卷中的内容会挂载到容器指定路径,容器内的应用程序可以正常访问这些内容,就好像这些内容本来就在容器内的该路径下一样。
- 当宿主机路径下没有内容,容器的路径下有内容时:
- 数据卷创建时如果为空,挂载后容器内路径原有的内容依然可以访问。因为数据卷和容器内路径的内容是相互独立的,数据卷为空不会影响容器内已有内容的访问。
- 当宿主机路径下没有内容,容器的路径下没有内容时:
- 挂载后容器内指定路径依然为空,应用程序在该路径下进行读写操作时,会按照数据卷的正常逻辑在数据卷对应的存储位置(可能是宿主机文件系统的某个位置)创建新的内容。
Bind Mounts 情况分析
- 当宿主机路径下有内容,容器的路径下也有内容时:
- 绑定挂载会将宿主机路径下的内容覆盖容器路径下的内容。因为绑定挂载是将宿主机的目录或文件直接挂载到容器内,所以容器内该路径下原有的内容会被隐藏,容器内应用程序访问该路径时,看到的是宿主机路径下的内容。
- 当宿主机路径下有内容,容器的路径下没有内容时:
- 宿主机路径下的内容会挂载到容器内指定路径,容器内的应用程序可以正常访问这些内容,就像这些内容本来就在容器内一样。
- 当宿主机路径下没有内容,容器的路径下有内容时:
- 当进行绑定挂载时,容器内路径下的内容会被隐藏,因为宿主机路径下没有内容,容器内应用程序访问挂载后的路径时,看到的是一个空的目录或文件(取决于绑定挂载的是目录还是文件)。
- 当宿主机路径下没有内容,容器的路径下没有内容时:
- 挂载后容器内指定路径依然为空,应用程序在该路径下进行读写操作时,会直接在宿主机对应的挂载路径下创建新的内容。
数据持久化方式 | 宿主机路径与容器路径初始状态 | 挂载后容器内路径情况 | 对容器内应用读写的影响 |
Volumes | 宿主机有内容,容器有内容 | 容器内原有内容被隐藏,呈现数据卷内容 | 读写数据卷内容,原有容器内容不可见 |
Volumes | 宿主机有内容,容器无内容 | 呈现宿主机数据卷内容 | 正常读写宿主机数据卷内容 |
Volumes | 宿主机无内容,容器有内容 | 容器原有内容仍可访问,数据卷空 | 读写容器原有内容,数据卷空不影响 |
Volumes | 宿主机无内容,容器无内容 | 容器内路径为空 | 在数据卷对应存储位置创建新内容并读写 |
Bind Mounts | 宿主机有内容,容器有内容 | 容器内原有内容被宿主机内容覆盖 | 读写宿主机路径内容,容器原有内容不可见 |
Bind Mounts | 宿主机有内容,容器无内容 | 呈现宿主机路径内容 | 正常读写宿主机路径内容 |
Bind Mounts | 宿主机无内容,容器有内容 | 容器内原有内容被隐藏,呈现空目录或文件 | 若绑定目录可在宿主机路径创建新内容读写,若绑定文件则受限 |
Bind Mounts | 宿主机无内容,容器无内容 | 容器内路径为空 | 在宿主机对应挂载路径创建新内容并读写 |