这两天在部署项目的时候,新加进去了一个驱动,需要将2个文件夹以及1个文件COPY进镜像,大刀阔斧一个Dockerfile就写完了,结果COPY进去的文件有问题,Dockerfile的内容如下(因涉及到商用项目,只复现,正好本地有tomcat9的镜像,就用这个啦)。
FROM tomcat:9
RUN mkdir -p /home/jim/
COPY ./a /home/jim # COPY 文件夹
COPY ./1.txt /home/jim # COPY 文件
其中a文件夹下包含a.txt、b.txt两个文件。
可以看出来我是想将
a文件夹
及其下面的两个文件以及1.txt
文件COPY进镜像,但是执行之后却发现了问题,容器中/home/jim
下并没有a
文件夹,只放着三个文件,目录结构如下:
/home/jim
├── a
| ├── a.txt
| └── b.txt
└── 1.txt
/home/jim
├── a.txt
├── b.txt
└── 1.txt
搜索一番才了解到Docker有个迷之操作:若是COPY的对象是文件夹,则只会COPY里面的文件,忽略文件夹。
就这么个问题,找了好久,其实我一开始猜到了,甚至怀疑是不是也有-r
这样的参数,但是没去尝试(所以实践出真知,真的要多操作操作)。
将Dockerfile改到这面这样,就可以实现上面的需求:
FROM tomcat:9
RUN mkdir -p /home/jim/a
COPY ./a /home/jim/a
COPY ./1.txt /home/jim
/home/jim
,而是/home/jim/a
,这样一来的话,/home/jim
文件也有了,/home/jim/a
文件夹也有了。./a
文件夹到/home/jim/a
,由于COPY
是拷贝的文件夹里的文件们,所以这一步是把a.txt和b.txt放进/home/jim/a
目录下1.txt
到/home/jim
文件夹下这样一来,容器里面的
/home/jim
文件夹下就是:. ├── a | ├── a.txt | └── b.txt └── 1.txt
# 打包
docker build -f Dockerfile -t test:v1 .
# 启动
docker run -d --name test --restart always -p 8080:8080 test:v1
# 进入
docker exec -it test bash
后面又去搜了一下资料,根据资料有偿试了一下,发现只是第一层目录会被「解包」,二级目录及其子文件还是会正常Copy进去的。
通过测试可以发现 COPY/ADD 命令有这么几个规则:
COPY ./sub_dir1 target
COPY ./sub_dir2 target
COPY ./file1 target
COPY ./file2 target
文件系统里的文件夹和文件,本质上都是文件,我们熟悉的操作系统的 cp 命令在执行 cp * target 时会把文件夹当成文件一股脑的复制到目标路径下,可以认为复制了文件本身,而 docker 的 COPY/ADD 在复制文件夹时复制的是其内容。
docker 的这种「奇怪」的逻辑已经被诟病许久了,但是似乎还没有要改变的意思,最新的进展可以参考下面两个 issue,在 docker 做出修改之前,只能在写 dockerfile 时候注意一下了。
参考文章:「简书:Docker COPY 复制文件夹的诡异行为」