草庐IT

不小心删除了docker容器怎么恢复?

卓有成效的程序员 2023-04-10 原文

如果不小心执行了docker rm 容器A,通过查找到docker volumes中删除容器的数据,将其挂载到新启动的容器中,即可恢复应用+状态+数据。

背景

docker作为优秀的开源容器引擎,能够像集装箱一样以一种非常标准化、轻量、可移植的方式帮助我们进行开发、交付和运行应用程序。

当镜像运行起来成为容器时会需要相关的存储资源来支撑软件服务的运行,如存储的日志文件,用户传入的数据,伴随运行生成的文件等。

由于docker运行程序实在是太便利了,在有些时候,一些用于调试的docker项目(自研、开源),不知不觉就投入了使用,并没有对数据做很合理安全的配置(挂载,备份),此后如果一不小心删除了运行中的容器,再启动镜像时,就会发现这是一个全新的服务,之前程序运行过程中积累的状态数据、用户数据、日志数据不复存在。

最近就遇到了这个问题:之前调研了一个开源的OA系统,在测试阶段,很好用,对接了内部的认证系统后,很多同事纷纷上去试用,不知不觉积累了很多数据。

直到有一天,运维同事在这个开发环境为了升级相关服务,便执行了如下容器删除语句:

docker rm {这个OA容器}

当天晚上,很多行政同事就炸锅了,反馈以为是正式环境,自己这一周的相关报表、报告都在上面。

怎么办?

关于Volumes机制

如下图,可以看到docker容器运行过程中,相关的应用数据可以分为三类。

1 bind mount

类似linux,可以将宿主机上的文件系统的某个路径、地址挂载到容器内的某个路径下,实现数据的持久化。比如将宿主机的/data/nfs/log/appA/挂载到容器内的/var/log/,即可在容器外部的/data/nfs/log/下轻松获取到各个应用(如appA)的日志信息。

2 volume

使用docker自带的volume机制进行数据的持久化。docker会在宿主机的特定位置(如/var/lib/docker/volumes)维护各个volumes,并提供了一系列的维护CLI命令。在启动容器时,类似mount一样,可以将某个volumes挂载到容器内的指定目录。docker自带的volume相比使用宿主机的文件系统存储有若干的好处,详见官方文档

3 tmpfs mount

如果在mount时使用了tmpfs(temporary file system, 临时文件存储),docker容器运行时的相关数据不会进行持久化存储:容器如果被删除了,那么相关存储也会被清除掉。

综上,面对容器删除的问题,有如下几个结论。

  1. 容器启动(docker run)时,即使没有显示的指定-v -mount参数,容器的相关数据已经被作为volumes持久化存储了,比如在/var/lib/docker/volumes下面,所以数据是在的。
  2. 但如果 docker run时,显示指定使用了tmpfs的mount类型,删除容器时才会被清理。
  3. 或者如果docker rm时指显示定了-v参数,也会连带删除容器依赖的volumes数据。

所以,只要没有手残强制使用了临时存储或者删除时强制指定了删除数据,数据还是在的。

如何恢复

知道了volumes的存在,那么恢复的路径也就随之明确了。

  1. 找到删除容器对应的volumes
  2. 基于一样的镜像启动新的容器
  3. 将之前的volumes迁移/挂载到新的容器上

1 找到删除容器的volumes

如下图,进入volumes存储目录(比如CentOS在/var/lib/docker/volumes), 通过ls或者du等命令来观察目录的创建时间和大小,来推断删除容器的volumes是哪(几)个。

如果通过时间,大小等维度不容易判断,就需要根据文件夹内部的文件内容、目录结构来推断。比如可以启动一个新的容器,看生成的volumes内部的目录结构来对之前的目录进行判断。

注: 找到volume后先进行备份

2 启动新的容器

基于之前的镜像,直接启动容器,通过inspect命令查看新容器的volume名称。

如下图,通过docker inspect 新容器可以看到在Mounts列表中,type为volume的就是我们要找的目标,从Source字段即可定位到目录位置。

注: 如果对于镜像的使用比较了解了,则可以直接在启动时,将找到的volumes挂载到正确的位置即可略过第3步骤:将之前的volumes迁移/挂载到新的容器上

3 将之前的volume迁移/挂载到新的容器上

  1. 执行docker stop 新容器停止新容器。
  2. 使用mv命令,在/var/lib/docker/volumes中将步骤1获取的目录的名称修改为步骤2获取的新容器的目录名称:mv 旧的volume名称 新的volume名称
  3. 执行docker start 新容器再次启动新容器。
  4. 完成

延伸

k8s中,volume的路径在/var/lib/kubelet/pods/, 通过在node上对指定pod对应的容器执行docker inspect可以看到对应的容器数据存储路径。

结论

  1. 如果不小心执行了docker rm 容器A,是可以恢复应用+状态+数据的。
  2. 去/var/lib/docker/volumes下,能够看到一系列的volumes,根据目录里面的内容、创建时间、更新时间判断哪(几)个目录是属于你删除的容器A的。
  3. 先备份好这些volumes。
  4. 基于相同的镜像新启动一个容器B(虽然没有数据)。
  5. 通过docker inspect 容器B找到容器B在/var/lib/docker/volumes中的volume目录。
  6. 执行docker stop 容器B停止容器B。
  7. 使用mv命令,在/var/lib/docker/volumes中将容器A目录的名称修改为容器B目录的名称。
  8. 执行docker start 容器B再次启动容器B。
  9. 顺利的话,你之前删除的容器应用+应用状态+应用数据应该都恢复了。

参考资料

https://docs.docker.com/storage/volumes/

有关不小心删除了docker容器怎么恢复?的更多相关文章

  1. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  2. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  3. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  4. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

  5. ruby - 怎么来的(a_method || :other) returns :other only when assigning to a var called a_method? - 2

    给定以下方法:defsome_method:valueend以下语句按我的预期工作:some_method||:other#=>:valuex=some_method||:other#=>:value但是下面语句的行为让我感到困惑:some_method=some_method||:other#=>:other它按预期创建了一个名为some_method的局部变量,随后对some_method的调用返回该局部变量的值。但为什么它分配:other而不是:value呢?我知道这可能不是一件明智的事情,并且可以看出它可能有多么模棱两可,但我认为应该在考虑作业之前评估作业的右侧...我已经在R

  6. ruby-on-rails - 我该怎么办 :remote location validation with CarrierWave? - 2

    我在我的Rails3示例应用程序上使用CarrierWave。我想验证远程位置上传,因此当用户提交无效URL(空白或非图像)时,我不会收到标准错误异常:CarrierWave::DownloadErrorinImageController#createtryingtodownloadafilewhichisnotservedoverHTTP这是我的模型:classPaintingtrue,:length=>{:minimum=>5,:maximum=>100}validates:image,:presence=>trueend这是我的Controller:classPaintingsC

  7. ruby - 如何安全地删除文件? - 2

    在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?

  8. ruby-on-rails - 标准化文件名的字符串,删除重音和特殊字符 - 2

    我正在尝试找到一种方法来规范化字符串以将其作为文件名传递。到目前为止我有这个:my_string.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.gsub(/[^a-z]/,'_')但第一个问题:-字符。我猜这个方法还有更多问题。我不控制名称,名称字符串可以有重音符、空格和特殊字符。我想删除所有这些,用相应的字母('é'=>'e')替换重音符号,并将其余的替换为'_'字符。名字是这样的:“Prélèvements-常规”“健康证”...我希望它们像一个没有空格/特殊字符的文件名:“prelevements_routin

  9. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  10. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

随机推荐