Why does docker image rebuild every time when running an ASP.Net Core application using Dockerfile?

I'm using Rider 2023.2.1 to run an ASP.Net Core 7 application from a Dockerfile, with the “Fast Build” feature. Every time I run or start debugging, the container image is rebuilt. The entire process, in my case, takes around a minute, and makes the feature nearly unusable, since it takes upwards of  a minute to start the app, or relaunch after making changes.

Shouldn't the image only be rebuilt if I make changes to the Dockerfile? I have a pretty standard multi-stage build setup, and I have verified that the image created when Fast Build is used is only using the “base” stage. The base stage is defined as follows, so the image should be cached, and not need to be rebuilt unless I make a change to the Dockerfile right?

FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

 

Each time I run or debug, I see output similar to the following in the container Build Log, regardless of whether or not I've made any changes to the base stage build.

Deploying '<unknown> Dockerfile: MyProject/Dockerfile'…
Building image…
Preparing build context archive…
[==================================================>]17803/17803 files
Done

Sending build context to Docker daemon…
[==================================================>] 315.5MB
Done

Step 1/4 : FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
 ---> 75bbe6a90eb8
Step 2/4 : WORKDIR /app
 ---> Using cache
 ---> 5ba930f4c5bd
Step 3/4 : EXPOSE 80
 ---> Using cache
 ---> 5c35c21ac5c4
Step 4/4 : EXPOSE 443
 ---> Using cache
 ---> 19e79ec81a87

Successfully built 19e79ec81a87
Successfully tagged myproject:dev
Creating container…
Container Id: f3e5429b3f9191b8e38556edb6de6842f5405cf48fd7579815c27c0caa828cd7
Container name: 'myproject'
Starting container 'myproject'
...

 

FWIW, the “Preparing build context archive…” and “Sending build context to Docker daemon…” steps are the ones that take a long time.

0
11 comments

Hello,

From your build log you are already running under Docker Fast Mode. 
In the Docker Fast Mode, only base stage of the dockerfile will be executed. Applicaiton will be complied locally and will execute by mounting the folder into the container. 
When changing the bind mount configuration of the container, docker will rebuild it.
You can compare the time spent with disabling Docker Fast Mode.  This instruction introduces how to modify docker debug configurations.
We also have a blog that introduced How Docker Fast Mode Works in Rider, hope it will help you.

Regards,

Tao

0

Tao Sun thank you for the reply. I do not want to disable Fast Mode. I want to use it to help work locally with containers.

I understand that if the volume/bind mount changes, then the container needs to be rebuilt. But my issue does not have to do with rebuilding the container, which is very fast, but with rebuilding the image. Rider appears to be rebuilding the image every time, and it is quite slow. Why should the image, which is simply based on the “base” stage from the Dockerfile build, need to be rebuilt if my Dockerfile has not changed?

 

Notice that this output appears every single time I use a “Dockerfile” launch configuration to run my application, even if I do not touch the Dockerfile at all. The “Preparing build context archive…” step is the one that generally takes the longest (typically 30-45s in my case)

Building image…
Preparing build context archive…
[==================================================>]17803/17803 files
Done

 

I have done a very similar setup using docker-compose, instead of launching directly with the Dockerfile, also using Fast Mode, and I do not experience the same problem. When using docker-compose, everything builds and launches very fast. Why should running from a Dockerfile, without docker-compose, not be equally as fast?

0

Hello,

If you use the default dockerfile for Fast Mode, the image will not be rebuilt every time. It will be reused for building new containers.
You can check the image ID in Rider's Services tool window or Docker Desktop, if the application image has been rebuilt, the image ID will be changed. 

By creating a simple new ASP.NET Core solution in Rider (with Docker support enabled), will you see the image ID been changed every time run your code in Rider?

If you still can see the image ID has been changed when click Run button in Rider (with Fast Mode enabled), please provide a sample project that can reproduce the issue, and your Rider/Docker version information.


I will try it on my machine to isolate whether the issue relates to Docker settings or Rider.

Regards,

Tao

0

Tao Sun ,

Perhaps I described/framed the issue incorrectly. Rider may not be rebuilding the image each time, but what is happening each time is the “Preparing build context archive” step is run:

Preparing build context archive…
[==================================================>]17803/17803 files

The problem seems to be that for larger projects, with 1000s of files, the “Preparing build context archive” step is quite slow. Like I said, it typically takes 30-45s for me, and it was looking at over 17,000 files (a few hundred MB in size).

If I use docker-compose to launch a container, the “Preparing build context archive” step does not seem to happen every time, so subsequent launches after the image is initially built are very quick.

I also tested by running docker build from the command line, to rebuild the image, and this was incredibly fast as well, since Docker had already cached everything locally, and nothing had changed. I used the --target=base option to simulate what would happen with fast mode enabled.

I did put together a very basic ASP.Net Core project and solution, which you can download using the link below, but it does not demonstrate the issue very well at all. That's because the build context only contains 51 files, and is just a few KB in size. The “Preparing build context archive” step does run each time, but it is nearly instantaneous, where on a larger project, with a larger build context, it certainly is not.

https://drive.google.com/file/d/12JafPk_tfELOYhVByJeF-ENjYTvQ6BQ5/view?usp=sharing

0

Hello,

I tried with the project provided, it indeed doesn't show the obvious slowness with running by Rider. 
Before investigating further, I suggest upgrading your Rider and Docker to the latest stable version, make sure we are using the same version.

The Preparing build context archive… happens during the container create stage, but not image build stage. The image in Fast Mode is designed in a way, so it will not take a long time on the build stage.

In the next step we will try troubleshooting the container create/execute stage, i.e. docker run stage. 

1. Delete all related containers and images in your environment, then run the dockerfile in Rider. 

2. When the container is created, delete it.

3. Create a standalone terminal and execute docker events to monitor all docker related events.

4. Run the dockerfile in Rider again, please notice, if it's using Fast Mode, corresponding image ID will not change, it will be used to create new container.

5. Check how long it takes to start the new container.

You could also use some tools like runlike extract the corresponding docker run command from the container created by Rider. 
The container created by the extracted command is different from Rider's but will follow similar build steps. 
Just try this way to see if the slowness will remain by running the command directly, so that we can verify whether the issue is from Docker or Rider.

Regards,

Tao

0

Tao Sun ,

I have the latest and greatest stable releases of both Rider (2023.2.1) and Docker Desktop for Windows (4.23.0)

I did as you suggested, deleted all images and containers tied to my project, and re-ran everything. It took around 55 seconds to build and start the container. I then re-ran the dockerfile, without deleting the existing image or container, and it essentially took the exact same amount of time for the container to start (55 seconds).

The two steps that took 99% of the time were the Preparing build context archive… step, and the Sending build context to Docker daemon… step. These steps ran, regardless of whether a container or image already existed. While these steps were running, nothing was logged by “docker events”. Could this mean that these are steps that are handled by Rider, and not by Docker? Here's exactly what the output in the build log looked like for these 2 steps once everything had finished:

Preparing build context archive…
[==================================================>]17874/17874 files
Done

Sending build context to Docker daemon…
[==================================================>] 315.5MB
Done

 

Once those 2 steps finished, it only took around 500ms for the container to be created and start (according to “docker events” timestamps)

Next, I installed the runlike utility, used it to extract a “docker run” command, then deleted the container, and ran the command from the solution root folder. The container started up almost instantly. Based on the timestamps from “docker events”, the actual time between the “container create” and “container start” events was around 500ms. Here's an abbreviated log of those events

2023-09-25T09:43:37.851809900-04:00 container create 67afc7a989319bedc29ba7472a32d524132efafe9b009bcc47ba9325dcef16e2
2023-09-25T09:43:37.907170439-04:00 network connect e886709bb3240847b8668283ce25df816547d7b68c3f320ff227828cd89d3056 (container=67afc7a989319bedc29ba7472a32d524132efafe9b009bcc47ba9325dcef16e2, name=bridge, type=bridge)
2023-09-25T09:43:38.341467321-04:00 container start 67afc7a989319bedc29ba7472a32d524132efafe9b009bcc47ba9325dcef16e2

 

I hope this info helps uncover the underlying issue(s).

0

Hello,

I attempted to replicate your issue using the latest release of Rider 2023.2 and Docker Desktop 4.23, but I couldn't reproduce the slowness you mentioned.

In my test environment, all docker image/container build actions are recorded by docker events. For your reference, when I initiate the project from the DockerFile in Rider, I can see the container, named after my project, created in Docker.

2023-10-09T12:57:55.684389192+08:00 image tag sha256:6db2a1fac16e579b533226589697a32de69b415071d13fa03cdf781631b9ef41 (name=authapitest:dev)

2023-10-09T12:57:55.852060065+08:00 container create eb4a1873a6b10b7c06c42a6acfb807505f92e3286f680721863a38a8250480a4 (desktop.docker.io/binds/0/Source=C:\Users\Brick\.nuget\packages, desktop.docker.io/binds/0/SourceKind=hostFile, desktop.docker.io/binds/0/Target=/root/.nuget/fallbackpackages, desktop.docker.io/binds/1/Source=C:\Users\Brick\RiderProjects\Core8WebApp\AuthApiTest, desktop.docker.io/binds/1/SourceKind=hostFile, desktop.docker.io/binds/1/Target=/app, desktop.docker.io/binds/2/Source=C:\Users\Brick\RiderProjects\Core8WebApp, desktop.docker.io/binds/2/SourceKind=hostFile, desktop.docker.io/binds/2/Target=/src, image=6db2a1fac16e, name=authapitest)

2023-10-09T12:57:56.071769637+08:00 network connect 0d2ab3cecae72b916e5c0d1dba1ae64dd00d298cb484d946b6746d9dc97d76ff (container=eb4a1873a6b10b7c06c42a6acfb807505f92e3286f680721863a38a8250480a4, name=bridge, type=bridge)

2023-10-09T12:57:56.411533200+08:00 container start eb4a1873a6b10b7c06c42a6acfb807505f92e3286f680721863a38a8250480a4 (desktop.docker.io/binds/0/Source=C:\Users\Brick\.nuget\packages, desktop.docker.io/binds/0/SourceKind=hostFile, desktop.docker.io/binds/0/Target=/root/.nuget/fallbackpackages, desktop.docker.io/binds/1/Source=C:\Users\Brick\RiderProjects\Core8WebApp\AuthApiTest, desktop.docker.io/binds/1/SourceKind=hostFile, desktop.docker.io/binds/1/Target=/app, desktop.docker.io/binds/2/Source=C:\Users\Brick\RiderProjects\Core8WebApp, desktop.docker.io/binds/2/SourceKind=hostFile, desktop.docker.io/binds/2/Target=/src, image=6db2a1fac16e, name=authapitest)

2023-10-09T12:57:57.146795117+08:00 image save sha256:c66b5f2b707a5a8b2af848a23e3d39b8d5ecbe7e61778ab8e0171d49e491208d (name=sha256:c66b5f2b707a5a8b2af848a23e3d39b8d5ecbe7e61778ab8e0171d49e491208d)

2023-10-09T12:58:00.792647573+08:00 image save sha256:6db2a1fac16e579b533226589697a32de69b415071d13fa03cdf781631b9ef41 (name=sha256:6db2a1fac16e579b533226589697a32de69b415071d13fa03cdf781631

Docker events are designed to capture all activity on the local docker server. While Rider has its own mechanism for docker execution, any interaction with the docker server should still be logged via the command. I'm uncertain why these events aren't appearing in your environment. As a potential solution, try launching a terminal with elevated permissions to see if you can capture the events.

I'd recommend updating your IDE first to check for any improvements. Additionally, start the IDE with Administrator permissions. Then, create a new ASP.NET Core project and observe if the issue persists.

Regards,

0

Tao Sun ,

I have the latest stable version of Rider (2023.2.2), and I can assure you the problem still persists.

As I've mentioned before, this problem is not observable on small projects, with small numbers of files, because in those cases the operations I'm referring to will always be fast, since the container build context will be small. However, on a project where the container build context contains thousands of files (in my case, over 17,000), and total file size is several hundred MBs, the problem is easily observable. As I've mentioned previously, it takes around 45s to run the project from the Dockerfile, with fast mode enabled, and even if the image has been previously built and cached and no changes have been made to anything.

When using docker-compose, this issue simply doesn't occur. There seems to be something in how Rider runs a project from a Dockerfile vs using something like docker-compose.

Unfortunately, I can't easily provide you with a sample project with 10,000+ files, so instead I have added screenshots and a screen capture GIF to show you what is happening. Please note that this happens every single time the project is run from the Dockerfile, regardless of whether any changes were made to the Dockerfile or the source code (which shouldn't matter anyways).

 

This first screenshot shows the existing container and image, which were previously built. Prior to running, no changes were made to any files in the project, so the existing image can be reused.

 

This next screenshot shows the button I used to run the project from the Dockerfile.

 

Lastly, this screen capture will show you how long it took to start up the project, even with 0 changes. It took over 50 seconds.

0

Jholzer Could you test the workaround provided below?

  1. Create a .dockerignore file if you don't already have one.
  2. Add all files from your working directory using *.
  3. When using Rider for docker execution, it will respect this configuration and will not rebuild the image. Please try it out and check if the Fast Mode works properly under these settings.

Note: Be cautious and refrain from committing this configuration to your VCS.

Please let me know if you observe any improvements.

0

Tao Sun 

Yes, I notice improvements if I add a * entry to my .dockerignore file, because the number of files in the build context drops from 18,000 to 3, and the build context size is only 889 bytes

Preparing build context archive…
[==================================================>]3/3 files
Done

Sending build context to Docker daemon…
[==================================================>]  889.0B
Done

 

I understand that this is a workaround, and it's obviously not a permanent solution.

I'm also still trying to understand why I'm able to build a container using the exact same Dockerfile and context w/ docker-compose, and do not experience similar issues. When I utilize docker-compose, the container is rebuilt and launches very quickly (typically 1-2 seconds).

0

Hi Jholzer,

I created an issue in our issue tracker for developers to investigate the problem. It seems to be an issue related to IDEA docker execution.

IDEA-334979 IDE will rebuild container even Docker Fast Mode enabled when starting project with DockerFile

We would appreciate it if you would upvote it in order to bring increased awareness to the issue. One can also click `Watch` to monitor the status. I will keep following up on the ticket as well.

Regards,

Tao

 

0

Please sign in to leave a comment.