【问题标题】:How do you add items to .dockerignore?如何将项目添加到 .dockerignore?
【发布时间】:2021-06-13 05:47:04
【问题描述】:

我找不到很多 .dockerignore 文件应该是什么样子的示例。

使用 puppet 在 docker 容器上安装一些包会导致映像从 600MB 爆炸到 3GB。我正在尝试使用.dockerignore 文件将大小保持在最小值

$ cat Dockerfile  
FROM centos:centos6

#Work around selinux problem on cent images
RUN yum install -y --enablerepo=centosplus libselinux-devel

RUN yum install -y wget git tar openssh-server; yum -y clean all

Add Puppetfile / 
RUN librarian-puppet install
RUN puppet apply --modulepath=/modules -e "class { 'buildslave': jenkins_slave => true,}"
RUN librarian-puppet clean

如果我运行docker images --tree,我可以看到图像立即增长了几 GB

$ docker images --tree
                ├─e289570b5555 Virtual Size: 387.7 MB
                │ └─a7646acf90d0 Virtual Size: 442.5 MB
                │   └─d7bc6e1fbe43 Virtual Size: 442.5 MB
                │     └─772e6b204e3b Virtual Size: 627.5 MB
                │       └─599a7b5226f4 Virtual Size: 627.5 MB
                │         └─9fbffccda8bd Virtual Size: 2.943 GB
                │           └─ee46af013f6b Virtual Size: 2.943 GB
                │             └─3e4fe065fd07 Virtual Size: 2.943 GB
                │               └─de9ec3eba39e Virtual Size: 2.943 GB
                │                 └─31cba2716a12 Virtual Size: 2.943 GB
                │                   └─52cbc742d3c4 Virtual Size: 2.943 GB
                │                     └─9a857380258c Virtual Size: 2.943 GB
                │                       └─c6d87a343807 Virtual Size: 2.964 GB
                │                         └─f664124e0080 Virtual Size: 2.964 GB
                │                           └─e6cc212038b9 Virtual Size: 2.964 GB Tags: foo/jenkins-centos6-buildslave:latest

我相信图像变得如此之大的原因是因为 librarian-puppet 将 puppet 模块克隆到 /modules 从而破坏了构建缓存

我尝试了以下.dockerignore 文件,但没有成功。

$ cat .dockerignore
/modules
/modules/
/modules/*

这是 .dockerignore 文件的正确语法吗?
有没有其他方法可以防止这些容器变得如此之大?

其他信息:

http://kartar.net/2013/12/building-puppet-apps-inside-docker/
http://danielmartins.ninja/posts/a-week-of-docker.html

【问题讨论】:

    标签: puppet docker


    【解决方案1】:

    .dockerignore 文件类似于.gitignore 语法。以下是一些示例规则:

    # Ignore a file or directory in the context root named "modules"
    modules
    
    # Ignore any files or directories within the subdirectory named "modules" 
    # in the context root
    modules/*
    
    # Ignore any files or directories in the context root beginning with "modules"
    modules*
    
    # Ignore any files or directories one level down from the context root named
    # "modules"
    */modules
    
    # Ignore any files or directories at any level, including the context root, 
    # named modules
    **/modules
    
    # Ignore every file in the entire build context (see next rule for how this 
    # could be used)
    *
    
    # Re-include the file or directory named "src" that may have been previously
    # excluded. Note that you cannot re-include files in subdirectories that have 
    # been previously excluded at a higher level
    !src
    

    请注意,“构建上下文”是您在构建命令末尾传递的目录,通常是 . 以指示当前目录。此目录是从 docker 客户端打包的,不包括您使用 .dockerignore 忽略的任何文件,并发送到 docker 守护程序以执行构建。即使守护程序与您的客户端位于同一主机上,构建也只能在此上下文中运行,而不是直接从文件夹中运行。

    构建只有一个.dockerignore,它必须位于构建上下文的根目录中。如果它位于您的主目录中(假设您从子目录构建),它将不起作用,并且它不会在构建上下文的子目录中起作用。

    要测试当前构建上下文中的内容并验证 .dockerignore 文件的行为是否正确,您可以复制/粘贴以下内容(假设您没有名为 test-context 的图像,它将被覆盖,然后如果你这样做了,请删除):

    # create an image that includes the entire build context
    docker build -t test-context -f - . <<EOF
    FROM busybox
    COPY . /context
    WORKDIR /context
    CMD find .
    EOF
    
    # run the image which executes the find command
    docker container run --rm test-context
    
    # cleanup the built image
    docker image rm test-context
    

    【讨论】:

      【解决方案2】:

      .dockerignore 是为了防止在您执行docker build 时将文件添加到发送到 docker 守护进程的初始构建上下文中,它不会创建一个全局规则来排除在所有生成的图像中创建文件通过 Dockerfile。

      需要注意的是,每个RUN 语句都会生成一个新图像,该图像的父级是由它上面的 Dockerfile 语句生成的图像。尝试将您的 RUN 语句合并为一个以减小图像大小:

      RUN librarian-puppet install &&\
       puppet apply --modulepath=/modules -e "class { 'buildslave': jenkins_slave => true,}" &&\
       librarian-puppet clean
      

      【讨论】:

      • 感谢您对我的回答的评论以及对最初问题的这个很好的解决方案。
      • 如果实际运行容器不需要这些文件,您可以将它们作为 Dockerfile 中的最后“清理”步骤删除。生成的映像更小,您还可以安全地删除中间构建映像以释放磁盘空间。
      • @Abe Voelker:我尝试将所有 RUN 语句折叠成一个 RUN 语句,但图像大小是相同的。这是为什么呢?
      【解决方案3】:

      .dockerignore 的格式类似于.gitignore 的格式。请参阅 sample file 和 docker documentation(但存在一些差异 - 例如,请参阅下面的评论)

      该文件应该是由换行符分隔的排除模式列表(相对于.dockerignore 文件的路径)。

      所以你应该试试下面的.dockerignore:

      modules/*
      

      开头的/可能是错误的,因为它只对文件的根目录有效(但对子目录无效,所以也许没有/的递归版本会做得更好而是)。

      【讨论】:

      • 感谢您的回答。我将 .dockerignore 更新为建议的语法并重新构建,看起来 contianer 仍在增长到 3GB。也许我误解了 .dockerignore 文件应该做什么。
      • @spuder 嗯,我必须承认,到目前为止我还没有对 Puppet 做过任何事情,所以我不明白上面的每个命令。但对我来说,它看起来不像 .dockerignore 相关问题。您注意到的行为对我来说似乎很奇怪,并且不应该像现在这样。所以你也会让我很想知道问题出在哪里。因此,请随意打开一个新的 general 问题,问题可能出在哪里,甚至在 docker git 存储库中打开一个问题。也许有人经历过类似的行为并且知道答案。有关更好的信息,请尝试从构建中获取一些日志文件。
      • .dockerignore 不完全等同于 .gitignore。例如,.gitignore 有评估目录的规则,.dockerignore 没有遵循;例如.gitignore 中的 /log 将忽略 .gitignore 所在目录中的 log 目录,但 .dockerignore 不会以相同的方式处理前导 / 并且不会将其从构建中排除语境。因此,您不一定能够将规则直接从您的 .gitignore 复制到您的 .dockerignore 未修改。
      • 让我感到困扰的是换行符必须是 Unix 换行符,而不是 Windows 换行符。我将在 Windows 上编辑的 .dockerignore 文件发送到 Unix 系统,docker 一直“忽略”我的忽略,直到我将其转换为 Unix 风格的换行符!
      • 更新 - 在 docker 1.1.0 中添加了 .dockerignore。在撰写本文时,我的 ubuntu repo 有 docker 1.0.1,但最新版本的 docker 是 1.4.0。不确定 .dockerignore 文件的早期实现,但在 docker 1.3.3 中,它不支持目录名称的尾部斜杠,这意味着您无法区分文件名和目录名称。如果将foo 添加到 .dockerignore 文件中,名为 foo 的文件和名为 foo 的目录都将被忽略。从 1.4.0 开始,支持目录名称的尾部斜杠,匹配 .gitignore 语法。
      【解决方案4】:

      都不是:

      modules/*
      

      也没有

      modules
      

      对我不起作用,docker 一直在用不必要的文件污染图像,直到我这样设置:

      **/modules
      

      也适用于:

      **/modules/*.py
      

      【讨论】:

      • 这应该是公认的答案,这个语法似乎是windows上docker唯一尊重的语法
      • 谢谢,您为我节省了很多时间。我有 17GB 的 pdf 文件夹,一遍又一遍地重建是没有意义的。
      【解决方案5】:

      另一种方法是创建一个较小的映像,即run librarian-puppet in the host,而不是在 Docker 中,因此您不会以安装在映像中的图书管理员、ruby、gems 等结束。

      我以jenkins slave using Puppet 的 622MB 图像和image without Puppet 的 480MB 图像结束。

      【讨论】:

        【解决方案6】:

        http://docs.docker.com/articles/dockerfile_best-practices/

        在我看来你的方法是倒退的(同意@csanchez),你应该从 puppet 生成你的 docker 容器,而不是在容器中运行 puppet...

        另外,您应该将&amp;&amp; install/apply/clean 行放在一起...每个 docker 命令创建一个增量映像...如果有临时/资源文件是 centos yum 命令的一部分,您也应该这样做。

        FROM centos:centos6
        
        # Add your needed files first
        # maybe you could use a baseimage and make this a volume mount point?
        Add Puppetfile / 
        
        # combine multiple commands with cleanup of cache/temporary
        # space in the same run sequence to reduce wasted diff image space.
        
        #Work around selinux problem on cent images
        RUN yum install -y --enablerepo=centosplus libselinux-devel && \
            yum install -y wget git tar openssh-server; yum -y clean all && \
            librarian-puppet install && \
            puppet apply --modulepath=/modules -e "class { 'buildslave': jenkins_slave => true,}" && \
            librarian-puppet clean

        真的建议避免在容器中使用 SELINUX,它不会在容器中为您提供任何东西。更不用说,根据您要创建的内容,可以从比 centos6 更小的地方开始。我相信 ubuntu 更小,debian:wheezy 更小,甚至是 alpine 的微小起点。

        值得注意的是,如果您使用支持虚拟挂载的文件系统,您的文件大小可以为多个实例重用相同的基础映像,因此它不会增长更多

        【讨论】:

          【解决方案7】:

          优化容器镜像大小是 .dockerignore 背后的主要目标,因为它的目的类似于您的 .gitignore,因为它在提供服务的同时减少了延迟和响应时间.对于 Puppet、SaltStack 或 Ansible 等部署自动化来说确实如此。为服务执行部署定义的时间戳可能会因为较大的图像大小和较低的网络带宽而失败。所以 .dockerignore 有助于使图像的大小尽可能小。

          您可以将其放入我们在 docker build 命令末尾指定的 构建上下文目录 中。该文件遵循glob 模式,用于文件和目录以从最终构建映像中排除它们。

          假设我有一个目录 .img/ 到我的构建上下文中,并且我想在构建映像时排除它,我只需将以下行添加到 .dockerignore 文件中,

          .img
          

          而且,如果我想排除所有以 .然后简单地,添加行,

          .*
          

          (注意:不要混淆 Unix glob 模式与正则表达式不同)

          此外,我将从构建上下文中排除更多文件,

          .*
          docs
          my-stack.dab
          docker-compose.overrride.yml
          test*
          *.md
          !README.md
          

          这里,*.md 行不包括所有降价文件(我的项目中有很多降价文件)。但是,我想包含 README.md 并且不包含其他降价文件。作为上面的最后一行,我们添加了带有 ! 的 README.md 或将其排除在外,同时排除所有其他降价文件。

          因此,我们可以借助 .dockerignore 减少构建映像的开销,并利用它来缩小映像大小。

          【讨论】:

            【解决方案8】:

            我认为最适合您的用例的解决方案是在您的 docker 文件中使用 Multi-stage build。您的 Dockerfile 必须位于一个空目录中,并且您在一次性容器中运行 puppet。

            从上面的链接:

            对于多阶段构建,您可以在您的程序中使用多个 FROM 语句 Docker 文件。每个 FROM 指令可以使用不同的基数,并且每个 其中开始了构建的新阶段。您可以选择性地复制 从一个阶段到另一个阶段的文物,留下你的一切 不希望出现在最终图像中。

            【讨论】:

              猜你喜欢
              • 2012-01-05
              • 2019-04-11
              • 1970-01-01
              • 2017-07-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-01-11
              相关资源
              最近更新 更多