bigywater.tech
Docker · 30

docker cp:不进入容器怎么读写文件

不进入容器怎么读写文件?docker cp 看起来简单,但源路径末尾的 /.、目标路径存不存在、拷到挂载目录里,结果各不相同。这篇逐一实测,包括一个会悄悄丢文件的情形。

src/.
加上 /. 只拷目录的内容,不带则目录本身也放进目标
退出码 0 却没文件
docker cp 到容器的 tmpfs 挂载点时的结果
799 vs 513 ms
64 MiB 文件拷进与拷出容器的中位数

目录的写法

实测 · 本机执行输出
  docker cp src {容器}:/d1(/d1 已存在):/d1 下:/d1/src/a.txt | /d1/src/sub/b.txt
  docker cp src/. {容器}:/d2(/d2 已存在):/d2 下:/d2/a.txt | /d2/sub/b.txt
  docker cp src {容器}:/d3/newname(/d3 不存在)→ 退出码 1;Error response from daemon: Could not find the file /d3 in container cc392b8bc1ce1c90fbd55d9efcca4f6
  docker cp src {容器}:/newname(/newname 不存在,但上级 / 存在):/newname/a.txt | /newname/sub/b.txt(目录被改名为 newname)

docker cp src 容器:/d1 在 /d1 已存在时会得到 /d1/src/…;docker cp src/. 容器:/d2 只拷内容。目标不存在但上级存在时,源目录被改名成目标名;上级也不存在则报错退出码 1。

属主

实测 · 本机执行输出
  宿主机文件属主 uid=501:不带 -a:501:20;带 -a(archive):501:20
  容器里属主 1234:5678 的文件拷出来:不带 -a → 宿主机上 uid=501;带 -a → uid=501(带 -a 的 docker cp 退出码 0;输出 无)

在 macOS 的 Docker Desktop 上,拷进容器的文件属主是宿主机的 uid:gid(501:20),带不带 -a 一样;拷出时属主也是当前用户。这是这台机器上的观察,Linux 宿主机上默认的属主处理我没有测。

挂载点

实测 · 本机执行输出
  docker cp 到 命名卷 /vol:退出码 0;容器里读到 = one
  docker cp 到 bind mount /bnd:退出码 0;容器里读到 = one
  docker cp 到 tmpfs /tmp1:退出码 0;容器里读到 = cat: can't open '/tmp1/x.txt': No such f
  docker cp 到 普通可写层 /plain:退出码 0;容器里读到 = one
  tmpfs 目录里实际有什么:(空)
  bind mount 目录在宿主机上有 x.txt 吗?True
  容器已停止:docker cp 进去 → 退出码 0;再 docker cp 出来 → 退出码 0,内容 one

拷到命名卷、bind mount 都成功;拷到 tmpfs 挂载点,命令退出码为 0 但文件不在。要往 tmpfs 里放文件,只能用 docker exec 之类的方式(本文没有逐一试)。

符号链接和 hostname

实测 · 本机执行输出
  拷出容器里的符号链接 /lnk:不带 -L → 符号链接 → /etc/os-release;带 -L → 普通文件(189 字节)
  拷出 /etc/hostname(Docker 为容器生成的文件):退出码 0;内容 = 3650c7c6d258;容器 ID 前 12 位 = 3650c7c6d258

默认拷出符号链接本身,-L 才拷内容。Docker 为容器生成的 /etc/hostname 也能拷出来,内容是容器 ID 的前 12 位。

速度

实测 · 本机执行输出
  64 MiB 拷进容器 3 次:[669, 1159, 799] ms(中位数 799);拷出 3 次:[612, 513, 438] ms(中位数 513)
  拷回来的文件和原文件一致吗?True

64 MiB 拷进容器 0.7~1.2 秒,拷出 0.4~0.6 秒(3 次);内容一致。docker cp 是把文件打成 tar 流经 API 传输的,大量小文件的开销我没有测。

分步演示

docker cp
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。宿主机侧的文件在本项目临时目录下;大文件用 os.urandom 生成,每个方向测 3 次并列出全部;其余场景各运行一次;实验后已删除容器、卷和临时文件
    • 没有验证:Linux 宿主机的属主规则、很多小文件的拷贝开销、docker cp - 与 tar 流的用法、拷贝时容器正在写同一个文件、--follow-link 之外的符号链接边界情况、rootless Docker
    京ICP备2026067502号-1京公网安备11010502063487号