Docker COPY与文件夹通配符

Tom*_*han 12 docker dockerfile

给定这样的文件结构:

project root
|-- X.sln
|-- src
|    |-- Foo
|    |    |-- Foo.fsproj
|    |    |-- Foo.fs
|    |-- Bar
|         |-- Bar.fsproj
|         |-- Bar.fs
|-- test
     |-- Baz
          |-- Baz.fsproj
Run Code Online (Sandbox Code Playgroud)

我想首先将所有.fsproj文件添加到我的Docker镜像,然后运行命令,然后添加其余文件.我尝试了以下,但当然它不起作用:

COPY X.sln .
COPY **/*.fsproj .
RUN dotnet restore
COPY . .
RUN dotnet build
Run Code Online (Sandbox Code Playgroud)

这个想法是在前两个COPY步骤之后,图像上的文件树是这样的:

working dir
|-- X.sln
|-- src
|    |-- Foo
|    |    |-- Foo.fsproj
|    |-- Bar
|         |-- Bar.fsproj
|-- test
     |-- Baz
          |-- Baz.fsproj
Run Code Online (Sandbox Code Playgroud)

树的其余部分仅在之后 添加RUN dotnet restore.

有没有办法模仿这种行为,最好不要求助于dockerfile之外的脚本

Ale*_*roß 9

如果您使用dotnet命令来管理您的解决方案,您可以使用这段代码:

  1. 将解决方案和所有项目文件复制到WORKDIR
  2. 列出解决方案中的项目dotnet sln list
  3. 迭代项目列表并将相应的*proj文件移动到新创建的目录中。
COPY *.sln ./
COPY */*/*.*proj ./
RUN dotnet sln list | \
      tail -n +3 | \
      xargs -I {} sh -c \
        'target="{}"; dir="${target%/*}"; file="${target##*/}"; mkdir -p -- "$dir"; mv -- "$file" "$target"'
Run Code Online (Sandbox Code Playgroud)


小智 7

您可以使用两个 RUN 命令来解决此问题,即使用 shell 命令(find、sed 和 xargs)。

按照步骤:

  1. 查找所有 fsproj 文件,使用正则表达式提取不带扩展名的文件名,并使用 xargs 使用此数据通过 mkdir 创建目录;
  2. 基于前面的脚本,更改正则表达式以创建 from-to 语法,并使用 mv 命令将文件移动到新创建的文件夹。

例子:

    COPY *.sln ./
    COPY */*.fsproj ./
    RUN find *.fsproj | sed -e 's/.fsproj//g' | xargs mkdir
    RUN find *.fsproj | sed -r -e 's/((.+).fsproj)/.\/\1 .\/\2/g' | xargs -I % sh -c 'mv %'
Run Code Online (Sandbox Code Playgroud)

参考:

如何在搜索模式中将 xargs 与 sed 结合使用


小智 0

无需借助 Dockerfile 之外的脚本即可实现您想要的效果的一种模式是:

    COPY <project root> .    
    RUN <command to tar/zip the directory to save a copy inside the container> \
         <command the removes all the files you don't want> \
         dotnet restore \
         <command to unpack tar/zip and restore the files> \
         <command to remove the tar/zip> \
         dotnet build
Run Code Online (Sandbox Code Playgroud)

这会将您的所有操作保留在容器内。我将它们全部捆绑在一个 RUN 命令中,以将所有这些活动保留在构建的单层中。如果需要,您可以将它们拆开。

这里只是 Linux 上的一个示例,说明如何递归删除除不需要的文件之外的所有文件: https: //unix.stackexchange.com/a/15701/327086。根据您的示例,我的假设是,这对您来说不会是一项成本高昂的操作。

  • 但这无法实现我最初问题的原因:因为你`COPY。.` 作为第一步,当我更改源文件时,构建上下文将会发生更改,这迫使我在没有包更改的情况下也等待“dotnet Restore”。所以这并没有比天真的 `COPY 提供任何价值。.`、`RUN dotnet restore`、`RUN dotnet build`,而不关心首先复制项目文件。 (10认同)