Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a more elegant way to copy specific files using Docker COPY to the working directory?

Tags:

Attempting to create a container with microsoft/dotnet:2.1-aspnetcore-runtime. The .net core solution file has multiple projects nested underneath the solution, each with it's own .csproj file. I am attemping to create a more elegant COPY instruction for the sub-projects

The sample available here https://github.com/dotnet/dotnet-docker/tree/master/samples/aspnetapp has a solution file with only one .csproj so creates the Dockerfile thusly:

COPY *.sln . COPY aspnetapp/*.csproj ./aspnetapp/ RUN dotnet restore 

It works this way

COPY my_solution_folder/*.sln . COPY my_solution_folder/project/*.csproj my_solution_folder/ COPY my_solution_folder/subproject_one/*.csproj subproject_one/ COPY my_solution_folder/subproject_two/*.csproj subproject_two/ COPY my_solution_folder/subproject_three/*.csproj subproject_three/ 

for a solution folder structure of:

my_solution_folder\my_solution.sln my_solution_folder\project\my_solution.csproj my_solution_folder\subproject_one\subproject_one.csproj my_solution_folder\subproject_two\subproject_two.csproj my_solution_folder\subproject_three\subproject_three.csproj 

but this doesn't (was a random guess)

COPY my_solution_folder/*/*.csproj working_dir_folder/*/ 

Is there a more elegant solution?

like image 718
sturmstrike Avatar asked Jul 17 '18 03:07

sturmstrike


People also ask

How do I copy a file from one directory to another in docker?

Another way to copy files to and from Docker containers is to use a volume mount. This means we make a directory from the host system available inside the container. The command above runs a grafana container and mounts the /tmp directory from the host machine as a new directory inside the container named /transfer.

Does docker copy copy recursively?

The command interprets a local machine's relative paths as relative to the current working directory where docker cp is run. The cp command behaves like the Unix cp -a command in that directories are copied recursively with permissions preserved if possible.

Does docker copy make directory?

Docker Copy CommandIts role is to duplicate files/directories in a specified location in their existing format.


1 Answers

2021: with BuildKit, see ".NET package restore in Docker cached separately from build" from Palec.


2018: Considering that wildcard are not well-supported by COPY (moby issue 15858), you can:

  • either experiment with adding .dockerignore files in the folder you don't want to copy (while excluding folders you do want): it is cumbersome
  • or, as shown here, make a tar of all the folders you want

Here is an example, to be adapted in your case:

find .. -name '*.csproj' -o -name 'Finomial.InternalServicesCore.sln' -o -name 'nuget.config' \   | sort | tar cf dotnet-restore.tar -T - 2> /dev/null 

With a Dockerfile including:

ADD docker/dotnet-restore.tar ./ 

The idea is: the archive gets automatically expanded with ADD.


The OP sturmstrike mentions in the comments "Optimising ASP.NET Core apps in Docker - avoiding manually copying csproj files (Part 2)" from Andrew Lock "Sock"

The alternative solution actually uses the wildcard technique I previously dismissed, but with some assumptions about your project structure, a two-stage approach, and a bit of clever bash-work to work around the wildcard limitations.

We take the flat list of csproj files, and move them back to their correct location, nested inside sub-folders of src.

# Copy the main source project files COPY src/*/*.csproj ./   RUN for file in $(ls *.csproj); do mkdir -p src/${file%.*}/ && mv $file src/${file%.*}/; done 

L01nl suggests in the comments an alternative approach that doesn't require compression: "Optimising ASP.NET Core apps in Docker - avoiding manually copying csproj files", from Andrew Lock "Sock".

FROM microsoft/aspnetcore-build:2.0.6-2.1.101 AS builder WORKDIR /sln  COPY ./*.sln ./NuGet.config  ./  # Copy the main source project files COPY src/*/*.csproj ./ RUN for file in $(ls *.csproj); do mkdir -p src/${file%.*}/ && mv $file src/${file%.*}/; done  # Copy the test project files COPY test/*/*.csproj ./ RUN for file in $(ls *.csproj); do mkdir -p test/${file%.*}/ && mv $file test/${file%.*}/; done  RUN dotnet restore  # Remainder of build process 

This solution is much cleaner than my previous tar-based effort, as it doesn't require any external scripting, just standard docker COPY and RUN commands.
It gets around the wildcard issue by copying across csproj files in the src directory first, moving them to their correct location, and then copying across the test project files.

like image 135
VonC Avatar answered Oct 01 '22 17:10

VonC