将文件从主机复制到Docker容器


1573

我正在尝试为我们使用的Docker容器构建备份和还原解决方案。

我已经创建了Docker基本映像ubuntu:base,并且不想每次都使用Docker文件重建它来向其添加文件。

我想创建一个从主机运行的脚本,并使用ubuntu:baseDocker映像创建一个新容器,然后将文件复制到该容器中。

如何将文件从主机复制到容器?


11
如果您不想重建,为什么不使用“ docker commit ”呢?这样可以保存您的图像。
Berend de Boer 2014年

26
只是对一个概念的评论,没有人提到:通常,将容器视为“短暂的”。在某些情况下,可以将文件复制到正在运行的容器中或从正在运行的容器中复制文件(测试,原型制作)。但是,如果您发现自己处在无法使用Dockerfiles和/或compose重建所需内容的位置,那么您可能会陷入困境。通常,您不希望将容器备份为OS或VM对象。一般来说:-)
Scott Prive

Answers:


2668

cp命令可用于复制文件。

可以将一个特定文件复制到容器,例如:

docker cp foo.txt mycontainer:/foo.txt

可以从容器中复制一个特定文件,例如:

docker cp mycontainer:/foo.txt foo.txt

为了强调,mycontainer是一个容器的ID,一个图像 ID。

src可以target使用以下命令将文件夹包含的多个文件复制到该文件夹中:

docker cp src/. mycontainer:/target
docker cp mycontainer:/src/. target

参考:适用于的Docker CLI文档cp

在1.8之前的Docker版本中,只能将文件从容器复制到主机。不是从主机到容器。


2
还请注意,这可以在主机vm或主OS上,并且可以在主机到容器或vm到主机(或主操作系统)上工作
Adam Tuliper-MSFT 2015年

7
在Dockerfile中,您可以使用ADD关键字在构建期间添加文件。
0x7d7b

4
@ h3nrik 在适用时COPY优先ADD使用。
富兰克林·于

10
用于docker cp从容器复制到主机的效果很好,但是当使用它将文件从主机复制到容器时,没有效果……有人知道为什么吗?docker版本:Docker版本1.10.3,内部版本cb079f6-unsupported
Ace.Yin,2016年

2
我可以使用docker cp从主机到容器复制多个文件吗?
Yogesh

182
  1. 获取容器名称或简短的容器ID:

    $ docker ps
    
  2. 获取完整的容器ID:

    $ docker inspect -f   '{{.Id}}'  SHORT_CONTAINER_ID-or-CONTAINER_NAME
    
  3. 复制文件:

    $ sudo cp path-file-host /var/lib/docker/aufs/mnt/FULL_CONTAINER_ID/PATH-NEW-FILE
    

例:

$ docker ps

CONTAINER ID      IMAGE    COMMAND       CREATED      STATUS       PORTS        NAMES

d8e703d7e303   solidleon/ssh:latest      /usr/sbin/sshd -D                      cranky_pare

$ docker inspect -f   '{{.Id}}' cranky_pare

要么

$ docker inspect -f   '{{.Id}}' d8e703d7e303

d8e703d7e3039a6df6d01bd7fb58d1882e592a85059eb16c4b83cf91847f88e5

$ sudo cp file.txt /var/lib/docker/aufs/mnt/**d8e703d7e3039a6df6d01bd7fb58d1882e592a85059eb16c4b83cf91847f88e5**/root/file.txt

13
对我来说,主机的安装路径只包含aufs一个devicemapper。检查容器安装路径(运行时)的最简单方法是运行command mount
derenio

3
我尝试了上述解决方案。它将文件复制到docker特定目录中。但是,当我将bash用于docker容器时,文件未显示在此处。我有什么想念的吗?
AppleBud 2014年

2
新路径为/ var / lib / docker / devicemapper / mnt / << id >> / rootfs /
mcuadros

4
对我来说,在Docker 1.4.1(最新)上,它是/var/lib/docker/aufs/diff/<id>/
user193130

3
对于贫穷的MacOS用户呢?mount目录/var/lib适合我。find / -name docker也没有帮助。
prayagupd

141

最干净的方法是在启动容器时在容器上挂载主机目录:

{host} docker run -v /path/to/hostdir:/mnt --name my_container my_image
{host} docker exec -it my_container bash
{container} cp /mnt/sourcefile /path/to/destfile

3
如何运行容器?我以为你只能用图像做到这一点。
帕维尔·扎伊采夫

当容器存在时,我无法运行它。下面的焦油效果很好。
EinoMäkitalo2015年

1
对我而言唯一有效的方法是在运行映像的同时附加卷(实例化容器)。结尾于:docker run -d -p -v /host/path:/mnt --name container_name image_name
彼得n

2
这对我不起作用。Atleast无法运行容器。只能运行图像
Shashank Hegde 2015年

1
我很惊讶这docker cp是单向手术!
ThorSummoner

115

以下是执行此操作的相当难看的方法,但它可以工作。

docker run -i ubuntu /bin/bash -c 'cat > file' < file

7
这很棒!但不要忘记进行更改:docker commit `docker ps -l -q` ubuntu-with-file。否则更改将丢失(使用您想要的任何名称代替ubuntu-with-file
Michael_Scharf 2014年

@Erik:容器运行时文件位于何处?
coanor 2014年

49
此外,我们可以使用新docker exec功能来运行容器:docker exec -it <container_id> bash -c 'cat > /path/to/container/file' < /path/to/host/file/
Mikl 2014年

17
@Mikl我认为应该docker exec -i ...代替@Mikl -it,因为从文件管道输入时没有TTY。
z0r

4
如果您仍然停留在旧版本的Docker上(如我所愿)并且想要复制整个目录,则可以执行以下操作:tar -c -v -f - /path/to/host/directory | docker exec -i <container-name> bash -c 'tar -x -v --strip-components 1 -f - -C /path/to/container/directory'
eahanson

43

如果需要在运行中的容器上执行此操作,则可以使用docker exec(1.3中添加)。

首先,找到容器的名称或ID:

$ docker ps
CONTAINER ID        IMAGE                        COMMAND             CREATED             STATUS              PORTS                   NAMES
b9b7400ddd8f        ubuntu:latest                "/bin/bash"         2 seconds ago       Up 2 seconds                                elated_hodgkin

在上面的示例中,我们可以使用b9b7400ddd8felated_hodgkin

如果要将/tmp/somefiles主机上的所有内容复制到/var/www容器中:

$ cd /tmp/somefiles
$ tar -cv * | docker exec -i elated_hodgkin tar x -C /var/www

然后/bin/bash,我们可以在容器中执行并验证其是否有效:

$ docker exec -it elated_hodgkin /bin/bash
root@b9b7400ddd8f:/# ls /var/www
file1  file2

在Centos 7.4上的docker 1.16上运行良好。
Dudi Boy '18

41
  1. 创建一个新的dockerfile并将现有映像用作基础。

    FROM myName/myImage:latest
    
    ADD myFile.py bin/myFile.py
    
  2. 然后构建容器:

    docker build .
    

2
这对我有用。没有其他的。谢谢!
Owen

它将创建一个新图像,而不是直接创建一个新容器。如果在myFile.py更改时重用此映像,除非重建映像,否则它将使用文件的旧版本。
纪尧姆·勒布雷顿

只有在远程服务器上进行测试时,我才能找到最快的方法。
Dominik Krulak '19

根据这个大多数人应该使用COPY而不是增加。但是对于本地文件(如本例所示),它们是等效的。
hoosierEE

39

解决方案如下:

在Docker Shell中,

root@123abc:/root#  <-- get the container ID

来自主持人

cp thefile.txt /var/lib/docker/devicemapper/mnt/123abc<bunch-o-hex>/rootfs/root

该文件应直接复制到容器在文件系统上的位置。


10
好答案。在较新的Docker版本中,路径已重命名为/ var / lib / docker / aufs / mnt /
Alex Volkov 2014年

devicemapper路径在docker 1.6的fedora上似乎不起作用。把它作为一个单独的Q,stackoverflow.com/questions/29939419/…,任何评论将不胜感激。
Yogesh_D 2015年

33

通常有三种类型:

  1. 从容器到主机

    docker cp container_id:./bar/foo.txt .
    

开发1

  1. 从主机到容器

    docker exec -i container_id sh -c 'cat > ./bar/foo.txt' < ./foo.txt
    

dev2

  1. 从一个容器到另一个容器,混合1和2

    docker cp container_id1:./bar/foo.txt .
    
    docker exec -i container_id2 sh -c 'cat > ./bar/foo.txt' < ./foo.txt
    

开发3


6
docker cp可以双向工作。无需执行,分类和重定向。docker cp host_file.txt容器:/ path /
tbm

32

将文件复制到正在运行的容器中的另一种解决方案是使用tar:

tar -c foo.sh | docker exec -i theDockerContainer /bin/tar -C /tmp -x

将文件复制foo.sh/tmp容器中。

编辑:删除多余的-f,感谢Maarten的评论。


如果您需要发送整个目录,这很好。对于单个文件,Erik的答案更简单。
开尔文

1
@Kelvin:但是tar也保留文件属性和名称。除其他外,这意味着您仅需键入一次名称即可(从shell中获得制表符补全)。因此,我想说tar实际上更简单,只要将其安装在容器中即可。
Maarten 2015年

1
-f -有点多余,虽然,默认行为是编写反正到标准输出。
Maarten 2015年

这意味着存在对tar的主机依赖性
cellige 2016年

没错-您需要在主机上和容器内安装tar。如今,使用docker cp是更好的解决方案。
joemat '16

24

将文件从主机复制到正在运行的容器

docker exec -i $CONTAINER /bin/bash -c "cat > $CONTAINER_PATH" < $HOST_PATH

基于Erik的答案以及Mikl和z0r的评论。


公认的解决方案有时会在传输到运行中的容器时干扰文件的缩进。这非常适合此类情况
梦想


15

这是标题中此问题中提出的“将文件从主机复制到Docker容器中”问题的直接答案。

尝试docker cp。这是最简单的方法,即使在我的Mac上也可以使用。用法:

docker cp /root/some-file.txt some-docker-container:/root

这会将主机some-file.txt目录中的文件复制/root到命名some-docker-container为目录的Docker容器中/root。它非常接近安全复制语法。如前一篇文章所示,反之亦然。即,您还将文件从容器复制到主机。

在您下传此帖子之前,请输入docker cp --help。有时,阅读文档可能会很有帮助。

如果您不喜欢这种方式,并且想要在已创建并正在运行的容器中存储数据量,那么,重新创建是当今唯一的选择。另请参阅如何将卷添加到现有Docker容器中?


15

我在这里尝试了大多数(建议的)解决方案,但在docker 17.09(2018年)中不再有/ var / lib / docker / aufs文件夹。

这个简单的docker cp解决了这个任务。

docker cp c:\path\to\local\file container_name:/path/to/target/dir/

如何获得container_name?

 docker ps 

有一NAMES节。不要使用IMAGE


12

要在容器和本地文件系统之间复制文件/文件夹,请键入以下命令:

docker cp {SOURCE_FILE} {DESTINATION_CONTAINER_ID}:/{DESTINATION_PATH}

例如,

docker cp /home/foo container-id:/home/dir

要获取容器ID,请输入以下命令:

docker ps

以上内容取自docker.com


8

假设容器已经在运行,请输入以下命令:

# cat /path/to/host/file/ | docker exec -i -t <container_id> bash -c "/bin/cat > /path/to/container/file"

要使用共享目录共享文件,请通过输入给定命令来运行容器:

# docker run -v /path/to/host/dir:/path/to/container/dir ...

注意:权限问题可能会出现,因为容器的用户与主机的用户不同。


1
此外:docker exec -it <container_id> bash -c 'cat > /path/to/container/file' < /path/to/host/file/
Mikl

2
请注意,cat退出后不会终止。如果对您来说很重要(如果要复制bash脚本,bash将拒绝运行它们),则应运行lsof | grep yourfilename并杀死cat保存所述文件的进程。
johndodo 2014年

谢谢!大提示。您能告诉我如何用一个命令杀死该进程吗?有点像kill $(lsof | grep /path/to/file | sed ...)。我会在你们的帮助表示感谢
Mikl

kill $(docker top CONTAINERNAME | sed -n '/cat$/p' | sed 's/^root[^0-9]\+\([0-9]\+\).*$/\1/')
Mikl 2014年

8

这是将数据从Docker复制到主机的命令:

docker cp container_id:file path/filename /hostpath

docker cp a13fb9c9e674:/tmp/dgController.log /tmp/

以下是将数据从主机复制到docker的命令:

docker cp a.txt ccfbeb35116b:/home/

7

在docker环境中,所有容器都位于目录中:

/var/lib/docker/aufs/required-docker-id/

要将源目录/文件复制到容器的任何部分,请键入以下命令:

sudo cp -r mydir/ /var/lib/docker/aufs/mnt/required-docker-id/mnt/


5

tar并且docker cp是复制目录中所有内容的良好组合。

创建数据卷容器

docker create --name dvc --volume /path/on/container cirros

保留目录层次结构

tar -c -C /path/on/local/machine . | docker cp - dvc:/path/on/container

检查你的工作

docker run --rm --volumes-from dvc cirros ls -al /path/on/container

5

如果主机是CentOS或Fedora,则在中有一个NOT代理/var/lib/docker/aufs,但该代理位于/proc

cp -r /home/user/mydata/* /proc/$(docker inspect --format "{{.State.Pid}}" <containerid>)/root

此cmd会将data目录的所有内容复制到/ID为“ containerid”的容器中。


这不是Redhat独有的:它也适用于Debian。(也许所有带有的Gnu / Linux /proc)。还要扩展路径以将文件放置在其他位置,而不仅仅是根目录。
ctrl-alt-delor

5

万一像我这样的人不清楚mycontainer@ h3nrik答案中的含义,它实际上是容器ID。要复制文件WarpSquare.mp4/app/example_scenes/1440p60从激发泊坞窗容器当前文件夹我用这个。

docker cp `docker ps -q -l`:/app/example_scenes/1440p60/WarpSquare.mp4 .

在其中docker ps -q -l拉出最后一个退出实例的容器ID。如果它不是已退出的容器,则可以通过docker container ls或获取它docker ps


1
您可以使用docker ps -a或列出已退出容器的ID docker container ls -a
0x7d7b

4

许多发现此问题的人实际上可能会遇到在创建文件时将文件复制到Docker映像中的问题(我做到了)。

在这种情况下,您可以使用中的COPY命令Dockerfile来创建图像。

请参阅文档


4

您可以使用以下命令跟踪本地计算机的IP地址

ifconfig

然后进入您的Docker容器并输入

scp user_name@ip_address:/path_to_the_file destination

无论如何,如果您没有安装SSH客户端和服务器,只需使用以下命令进行安装:

sudo apt-get install openssh-server

非常感谢,它对我来说效果很好。另外,我发现它比其他方式更有效
user1314742 2015年

就安全性而言,这是一个可怕的解决方案。

4

这是一个在线程序,用于在运行tomcat容器时复制单个文件。

docker run -v /PATH_TO_WAR/sample.war:/usr/local/tomcat/webapps/myapp.war -it -p 8080:8080 tomcat

这会将war文件复制到webapps目录,并使您的应用立即运行。


1
-v将挂载(即创建链接),而不是复制
Vitaliy Ulantikov

结果的不同之处在于,安装会隐藏先前的容器内容,例如,如果将主机文件夹安装在容器文件夹上,您将无法再看到先前的容器文件夹内容
mrq

4

容器启动语法:

 docker run -v /HOST/folder:/Container/floder 

在docker文件中

COPY hom* /myFolder/        # adds all files starting with "hom"
COPY hom?.txt /myFolder/    # ? is replaced with any single character, e.g., "home.txt"


3

有很好的答案,但是太具体了。我发现docker ps获取您感兴趣的容器ID的好方法。然后

mount | grep <id>

查看卷的安装位置。那是

/var/lib/docker/devicemapper/mnt/<id>/rootfs/

对我来说,但这可能是不同的路径,具体取决于操作系统和配置。现在,只需将文件复制到该路径即可。

使用-v并不总是可行的。


3

我刚刚开始使用docker编译VLC,这是您可以从容器来回复制文件的操作:

su -
cd /var/lib/docker
ls -palR > /home/user/dockerfilelist.txt

在该txt中搜索一个熟悉的文件,您将拥有该文件夹,并以root和voila的身份访问cd!复制所有您想要的。

可能其中包含“合并”的路径,我想您想要其中包含“ diff”的路径。

另外,如果您退出容器并想回到上次停靠的地方:

docker ps -a
docker start -i containerid

我想这在您未使用以下命令命名时很有用

docker run -it registry.videolan.org:5000/vlc-debian-win64 /bin/bash

当然可以使用黑客方法,但是怎么办!


3
docker cp SRC_PATH CONTAINER_ID:DEST_PATH

例如,我要将文件xxxx / download / jenkins复制到tomcat

我开始获取容器Tomcat的ID

docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
63686740b488        tomcat              "catalina.sh run"   12 seconds ago      Up 11 seconds       0.0.0.0:8080->8080/tcp   peaceful_babbage

docker cp xxxx/download/jenkins.war  63686740b488:usr/local/tomcat/webapps/

2

我最喜欢的方法:

容器:

CONTAINER_ID=$(docker ps | grep <string> | awk '{ print $1 }' | xargs docker inspect -f '{{.Id}}')

file.txt

mv -f file.txt /var/lib/docker/devicemapper/mnt/$CONTAINER_ID/rootfs/root/file.txt

要么

mv -f file.txt /var/lib/docker/aufs/mnt/$CONTAINER_ID/rootfs/root/file.txt

devicemapper路径在docker 1.6的fedora上似乎不起作用。把它作为一个单独的Q,stackoverflow.com/questions/29939419/…,任何评论将不胜感激。
Yogesh_D 2015年

2

我认为您不必复制映像中的文件,但可以对文件使用GIT或SVN,然后设置与本地文件夹同步的卷。运行容器时使用脚本,该脚本可以检查本地文件夹中是否已存在数据(如果未从GIT存储库中复制数据)。这使您的图像非常轻巧。


这似乎有安全隐患,等待访问的噩梦正在发生。您如何从映像中提供对git存储库的访问?即使假设它是一个公共存储库,您也将假设容器运行的主机可以访问该存储库。
tbm19年

如果在docker容器中使用git,我同意你的看法。但是在我们的例子中,脚本是从主机上运行的
h.aittamaa
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.