• Dockerfile COPY的奇怪行为:自动解包一级目录


    记录一下今天遇到的坑:Dockerfile

    这两天在部署项目的时候,新加进去了一个驱动,需要将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 文件
    
    • 1
    • 2
    • 3
    • 4

    其中a文件夹下包含a.txt、b.txt两个文件。

    可以看出来我是想将a文件夹及其下面的两个文件以及1.txt文件COPY进镜像,但是执行之后却发现了问题,容器中/home/jim下并没有a文件夹,只放着三个文件,目录结构如下:

    我想要的:
    /home/jim
           ├── a
           |   ├── a.txt
           |   └── b.txt
           └── 1.txt
    
    • 1
    • 2
    • 3
    • 4
    • 5
    我得到的
    /home/jim
           ├── a.txt
           ├── b.txt
           └── 1.txt
    
    • 1
    • 2
    • 3
    • 4

    搜索一番才了解到Docker有个迷之操作:若是COPY的对象是文件夹,则只会COPY里面的文件,忽略文件夹
    就这么个问题,找了好久,其实我一开始猜到了,甚至怀疑是不是也有-r这样的参数,但是没去尝试(所以实践出真知,真的要多操作操作)。



    👾 修正

    将Dockerfile改到这面这样,就可以实现上面的需求:

    FROM tomcat:9
    RUN mkdir -p /home/jim/a
    COPY ./a /home/jim/a
    COPY ./1.txt /home/jim
    
    • 1
    • 2
    • 3
    • 4
    1. FROM镜像这个不必要解释
    2. 第二步不再是只创建/home/jim,而是/home/jim/a,这样一来的话,/home/jim文件也有了,/home/jim/a文件夹也有了。
    3. COPY ./a文件夹到/home/jim/a,由于COPY是拷贝的文件夹里的文件们,所以这一步是把a.txt和b.txt放进/home/jim/a目录下
    4. COPY 1.txt/home/jim文件夹下

    这样一来,容器里面的/home/jim文件夹下就是:

    .
    ├── a
    |   ├── a.txt
    |   └── b.txt
    └── 1.txt
    
    • 1
    • 2
    • 3
    • 4
    • 5


    🥥 验证

    # 打包
    docker build -f Dockerfile -t test:v1 .
    # 启动
    docker run -d --name test --restart always -p 8080:8080 test:v1
    # 进入
    docker exec -it test bash
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6


    📎 求实

    后面又去搜了一下资料,根据资料有偿试了一下,发现只是第一层目录会被「解包」,二级目录及其子文件还是会正常Copy进去的。

    通过测试可以发现 COPY/ADD 命令有这么几个规则:

    • ADD 命令和 COPY 命令在复制文件时行为一致
    • 使用 * 作为 COPY/ADD 命令的源时候表示的是 ./*
    • COPY/ADD 命令的源如果是文件夹,复制的是文件夹的内容而不是其本身
    • COPY ./* target 中的 * 会被翻译成如下的逻辑:
    COPY ./sub_dir1 target
    COPY ./sub_dir2 target
    COPY ./file1 target
    COPY ./file2 target
    
    • 1
    • 2
    • 3
    • 4

    文件系统里的文件夹和文件,本质上都是文件,我们熟悉的操作系统的 cp 命令在执行 cp * target 时会把文件夹当成文件一股脑的复制到目标路径下,可以认为复制了文件本身,而 docker 的 COPY/ADD 在复制文件夹时复制的是其内容。

    docker 的这种「奇怪」的逻辑已经被诟病许久了,但是似乎还没有要改变的意思,最新的进展可以参考下面两个 issue,在 docker 做出修改之前,只能在写 dockerfile 时候注意一下了。



    🖋️ 参考文章

    参考文章:「简书:Docker COPY 复制文件夹的诡异行为」

  • 相关阅读:
    QtService实现Qt后台服务程序其一_基本使用步骤
    FIddler抓手机的通讯包的设置记录
    2024年火爆全网的三款ai智能直播系统,你知道哪一种?
    Unity Editor 遍历指定文件夹下的所有prefab
    探索人工智能的世界:构建智能问答系统之前置篇
    使用 IDEA 快速远程调试 Docker 中运行的 Java 应用程序 (附解决思考过程)
    【即将开源】⽤于3D激光雷达SLAM闭环检测的词袋模型BoW3D
    Java学数据结构(4)——PriorityQueue(优先队列)& 二叉堆(binary heap)
    Web实验总
    【视频加水印】Video Watermark Pro视频添加动态水印(附工具下载地址)
  • 原文地址:https://blog.csdn.net/Hsk_03/article/details/132611095