3

I am creating a Docker container from this .NET Core application that has multiple projects inside the solution, and I wonder if it is better to COPY each project file separately, or in a single line.

Visual Studio generates a Dockerfile that copies each project file on a new line, like this:

WORKDIR /src
COPY Dir1/Dir1.csproj Dir1/
COPY Dir2/Dir2.csproj Dir2/
COPY Dir3/Dir4/Dir4.csproj Dir3/Dir4/
RUN dotnet restore Dir1/Dir1.csproj

However, the Microsoft documentation for creating a .NET application with Docker shows as an "optimization" to use only a single COPY statement, like so:

WORKDIR /src
COPY . .
RUN dotnet restore Dir1/Dir1.csproj

Which is said to, in my understanding of the article, create a larger image, but wouldn't have to COPY all other projects if one project changes.

Interestingly, the Docker documentation mentions to

COPY them individually, rather than all at once. This ensures that each step’s build cache is only invalidated (forcing the step to be re-run) if the specifically required files change.

Which basically contradicts what the Microsoft article says, about the COPY step having to be rerun when one project changes.

I would like to know which option is better, and why, or for what purpose. Or perhaps I misunderstood some of the documentation, then please explain the difference to me.

Marthe Veldhuis
  • 316
  • 2
  • 16

1 Answers1

3

IMO the best practice approach is to copy each project as a separated layer, ie a dedicated COPY statement.

use separated layers.

  1. faster build: docker is caching the layers, so if you made a change in one project - next time the image is built docker will only build the changed layer and use cache for the others.
  2. faster deployment: layers can be pulled in parallel
  3. efficient hosting: thanks to docker copy on write mechanism, layers can be shared across images to save space and IO:

Copy-on-write is a strategy of sharing and copying files for maximum efficiency. If a file or directory exists in a lower layer within the image, and another layer (including the writable layer) needs read access to it, it just uses the existing file. The first time another layer needs to modify the file (when building the image or running the container), the file is copied into that layer and modified. This minimizes I/O and the size of each of the subsequent layers

the reason why you see the common COPY . . statement in Dockerfiles is because usually a dockerfile contains a single project, thats a best practice which i would like to recommend for your case too - place a dockerfile in each project and build separated images (on top of a common base image).

if you ought to host all of your projects in a single image, at least copy them as different layers.

Efrat Levitan
  • 5,181
  • 2
  • 19
  • 40
  • It then still seems contradictory that the Microsoft documentation says that using the `COPY . .` command "would use the cache" for the other projects when rebuilding if just 1 project has changes. Isn't that exactly what the separated layers are for? – Marthe Veldhuis Jul 23 '19 at 09:14
  • go through the middle. dont copy each file in different layer, but also dont copy multiple projects in the same line. do what is best and readable for you needs. in the artisacle you attached, microsoft probably meant "dont copy every file as a single layer" whic is correct, but imo different projects should be copies as different layers. – Efrat Levitan Jul 23 '19 at 11:16
  • What happens when you’ve got multiple project reference dependencies and they often change? Have to manually update your dockerfile manually? – Mark Walsh Jun 29 '22 at 21:51
  • Every project dependency has its own layer so every change makes it refreshed, if they are nuget packs they have version and version change in csproj clears the cache. But I was going to add another note : Every project even in separate stages is better because https://docs.docker.com/build/cache/ says "If a layer changes, all other layers that come after it are also affected." – AbbasAli Hashemian Sep 01 '23 at 11:34