如何在已停止/未启动的Docker容器中编辑文件


93

为了解决我的应用程序的错误并调试问题,该应用程序分布在多个容器中,我经常在容器中编辑文件:

  • 我完全懒惰并安装nano并直接在容器中进行编辑,或者

  • 我将cp文件从容器中移出,对其进行编辑,复制并重新启动容器

这些是进入容器构建新内容之前的中间步骤,这比上述步骤要花很多时间(当然,这只是中间步骤)。

现在,我经常中断容器的启动程序,在中断情况下,该程序要么是节点脚本,要么是python Web服务器脚本,它们通常都因语法错误而失败。

有什么办法可以保存那些容器?由于它们没有启动,因此我无法在其中执行docker exec,因此它们对我丢失了。然后在构建输入中修复有问题的文件后,我走了rm / rmi / build / run路线。

如何在停止的容器中编辑文件,或者在停止的容器中cp它们或启动外壳程序-可以修复该容器的任何方法?

(似乎有点像在远程计算机上工作并破坏网络配置-这种方式“永远”失去连接,并且必须使用后备(如果存在)。)

如何从主机编辑Docker容器文件?看起来相关,但已过时。


这也可能是一种解决方法stackoverflow.com/a/32353134/586754-希望有一个更好的解决方案。
Andreas Reiff 2015年

1
也许您应该考虑挂载卷,以便可以在主机上而不是在容器内编辑文件。一旦对您的代码感到满意,您就可以docker cp将文件放到容器中(或构建新映像)
Thomasleveil

是的,但是如果我从一开始就没有做过这样的设置,那将有些迟。我认为这对恢复无效。
Andreas Reiff 2015年

许多读者只希望查看文件而不是编辑它们。在这些情况下,您可以使用docker commit命令来断开新图像。name=$(docker commit); docker run -it $name /bin/sh会做你想要的。
Att Righ

如此看来,已停止容器的文件系统在最后是相对永久的?
Webwoman

Answers:


138

我有一个容器问题,由于我进行了错误的配置更改,该容器无法启动。我能够从停止的容器中复制文件并进行编辑。就像是:

docker cp docker_web_1:/etc/apache2/sites-enabled/apache2.conf .

(更正文件)

docker cp apache.conf docker_web_1:/etc/apache2/sites-enabled/apache2.conf

22
这应该是公认的答案。由于某种原因,我不认为CP在停止的容器上工作。真好!
Proximo '18年

完善。我从容器中复制了一个文件(我知道它的路径),然后对其进行了编辑,然后再复制回该容器中的相同位置。为我工作!谢谢!
Nawaz

有没有办法删除文件?
科德兰

1
@kodlan仅当它仅出现在UpperDir您所获得的文件中时,docker container inspect您才需要尝试看看叠加系统如何表示底层结构中已在上层删除的文件。
Tim Baverstock

谢谢,这帮助我修复了在macOS上的docker中运行的MySQL容器。
mazedlx

60

回答我自己的问题..仍然希望从一个知识渊博的人那里得到更好的答案!

有两种可能性。

1)直接在主机上编辑文件系统。这有些危险,并且有可能完全破坏容器,并可能根据发生的问题彻底破坏其他数据。

2)将启动脚本更改为永不失败的内容,例如启动bash,进行修复/编辑,然后再次将启动程序更改为所需的程序(例如节点或以前的版本)。

更多细节:

1)使用

docker ps

查找正在运行的容器或

docker ps -a

查找所有容器(包括停止的容器)并

docker inspect (containername)

查找“ Id”,第一个值之一。

这是包含实现细节的部分,可能会更改,请注意,这样可能会丢失容器。

/var/lib/docker/aufs/diff/9bc343a9..(long container id)/

在那里您会找到所有更改为容器所基于的图像的文件。您可以覆盖文件,添加或编辑文件。

同样,我不建议这样做。

2)如https://stackoverflow.com/a/32353134/586754所述,您可以在以下路径找到配置json config.json

/var/lib/docker/containers/9bc343a99..(long container id)/config.json

在那里,您可以将参数从“ nodejs app.js”更改为“ / bin / bash”。现在重新启动docker服务并启动容器(您应该看到它现在已正确启动)。你应该用

docker start -i (containername)

确保它不会立即退出。您现在可以使用容器和/或以后再附加

docker exec -ti (containername) /bin/bash

另外,docker cp对于复制在容器外部编辑的文件非常有用。

而且,如果容器无论如何或多或少地“丢失”,则应该只使用那些措施,因此任何更改都将是一种改进。


仍然希望有更好的答案-请随时提出一个答案,我也将移动“已回答”标签。
Andreas Reiff 2015年

我使用第二种方法,并且config.json每次不得不编辑文件时都必须重新启动docker服务
Vitaly Isaev 2015年

2
我有config.v2.json,每次启动僵尸容器时,它都会还原我的Path / EntryPoint更新并再次死亡。使用“ docker cp”更新entrypoint.sh脚本以仅运行bash对其进行了修复。
柯蒂斯·雅洛普

@CurtisYallop我正在经历同样的事情。您是如何解决的?
Brett McLain's

1
@BrettMcLain我使用docker cp而不是在主机上对其进行编辑。像这样:查找入口点脚本位置:“ docker inspect container_name | grep Entry”。获取脚本:“ docker cp container_name:/entrypoint.sh ./”。(将其编辑)将脚本放回容器中:“ docker cp entrypoint.sh container_name:/entrypoint.sh”。您可以使入口点运行bash或运行睡眠循环,例如“ while:; do sleep 10; done”。第一脚本行必须为“#!/ bin / bash”。
Curtis Yallop

9

您可以直接编辑容器文件系统,但是我不知道这是一个好主意。首先,您需要找到目录路径,该路径用作容器的运行时根。运行docker container inspect id/nameUpperDir在JSON输出中查找密钥。

那是你的目录。


找到了目录,但是没有包含所有文件。
aioobe

它是OverlayFS,因此您的文件必须位于这些目录中的一个中。
Tejas Sarade

目录名称可能与“ UpperDir”不同,例如,在我的情况下,它是“源”。但这有效!
Rajni Kewlani

0

如果您尝试重新启动已停止的容器,并且由于配置错误而需要更改容器,但是容器没有启动,则可以使用“ docker cp”命令执行以下操作(类似于先前的建议)。此过程使您可以删除文件并进行其他所需的更改。幸运的是,您可以跳过以下许多步骤。

  1. 使用docker inspect查找入口点(在某些版本中命名为Path)
  2. 创建使用docker run的副本
  3. 使用docker exec -ti bash输入克隆(如果* nix容器)
  4. 通过查找要查找的克隆来找到入口点文件位置
  5. 使用docker cp复制旧的入口点脚本:./
  6. 修改或创建新的入口点脚本,例如

    #!/bin/bash tail -f /etc/hosts

  7. 确保脚本具有执行权限
  8. 使用docker cp ./替换旧的入口点:
  9. 使用开始启动旧容器
  10. 重做步骤6-9,直到开始
  11. 解决容器中的问题
  12. 如果需要,请还原入口点,并根据需要重做步骤6-9
  13. 如果需要,删除克隆
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.