Docker COPY 複製文件夾的詭異行爲

問題現象

在製作 docker 鏡像時,有複製某一個路徑下所有文件和文件夾到鏡像的需求,寫下了如下 dockerfile:

FROM alpine
WORKDIR /root/test_docker_proj
COPY * ./

原始目錄結構是這樣的:

/projects/test_docker_proj
├── Dockerfile
├── dir1
│   ├── dir11
│   │   └── file11
│   └── file1
└── file2

然而複製到 docker 鏡像裏的目錄結構變成了這樣:

/root/test_docker_proj
├── Dockerfile
├── dir11
│   └── file11
├── file1
└── file2

可以看到 dir1 這個文件夾並沒有被複制到鏡像裏,但是 dir1 中的子文件夾和文件都被複制進來了,和 dir1 同級的文件也被複制了。也就是說,在 COPY 執行的過程中,第一層文件夾被「解包」了。

COPY/ADD 行爲邏輯

爲了確定 COPY 和相似的 ADD 命令的行爲,做了以下測試:

FROM alpine

WORKDIR /root/test_docker_proj_1
COPY * ./

WORKDIR /root/test_docker_proj_2
ADD * ./

WORKDIR /root/test_docker_proj_3
COPY ./ ./

WORKDIR /root/test_docker_proj_4
ADD ./ ./

WORKDIR /root/test_docker_proj_5
COPY ./dir* ./

WORKDIR /root/test_docker_proj_6
ADD ./dir* ./

通過測試可以發現 COPY/ADD 命令有這麼幾個規則:

  1. ADD 命令和 COPY 命令在複製文件時行爲一致
  2. 使用 * 作爲 COPY/ADD 命令的源時候表示的是 ./*
  3. COPY/ADD 命令的源如果是文件夾,複製的是文件夾的內容而不是其本身
  4. COPY ./* target 中的 * 會被翻譯成如下的邏輯:
COPY ./sub_dir1 target
COPY ./sub_dir2 target
COPY ./file1 target
COPY ./file2 target

文件系統裏的文件夾和文件,本質上都是文件,我們熟悉的操作系統的 cp 命令在執行 cp * target 時會把文件夾當成文件一股腦的複製到目標路徑下,可以認爲複製了文件本身,而 docker 的 COPY/ADD 在複製文件夾時複製的是其內容

docker 的這種「奇怪」的邏輯已經被詬病許久了,但是似乎還沒有要改變的意思,最新的進展可以參考下面兩個 issue,在 docker 做出修改之前,只能在寫 dockerfile 時候注意一下了。

參考文檔

https://stackoverflow.com/questions/30256386/how-to-copy-multiple-files-in-one-layer-using-a-dockerfile

https://github.com/moby/moby/issues/15858

https://github.com/moby/moby/issues/29211

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章