fabric8io / docker-maven-plugin

Maven plugin for running and creating Docker images
https://dmp.fabric8.io
Apache License 2.0
1.88k stars 642 forks source link

How to avoid rebuilding image on every ```mvn clean install``` #355

Open heapifyman opened 8 years ago

heapifyman commented 8 years ago

I am trying out a copy of the https://github.com/rhuss/docker-maven-sample project but with a Dockerfile to build the image and it seems that now every time I run mvn clean install the image is built anew.

Shouldn't it reuse the one that is already there as long as I don't change anything in pom.xml or Dockerfile?

I see the following in the log on every run - with Built image hash becoming the Removed image hash on the subsequent run:

[INFO] DOCKER> [acme/docker-maven-test:0.0.1] "docker-maven-test": Built image eb971627ac16
[INFO] DOCKER> [acme/docker-maven-test:0.0.1] "docker-maven-test": Removed image 66e2b730e234
jgangemi commented 8 years ago

no - the container gets rebuilt every time, we don't currently prevent this if there were no changes.

if you really don't want that to happen, you can gate the docker:build command w/ a profile so it only gets built when you request it.

heapifyman commented 8 years ago

Hm, then I have some strange behaviour here. I now excluded the project artifact from being included into the container and then ran mvn clean install twice on my local machine, then twice on jenkins, then twice on my local machine again. With no changes to the code or anything between the two builds on the respective machine.

The results were:

  1. local run: image gets built (takes quite a while because several apt-get installs are run), old image gets removed
  2. local run: image gets built, no output about removing any old image and container is started immediately. docker ps does not show any of the apt-get install commands being run, instead the final start command of the docker file is run. I assume docker here re-uses the old image from cache? The log says Built image b4650e4511e5, where the hash is the same as in the previous run.
  3. run on jenkins: same behaviour as 1. local run
  4. run on jenkins: same behaviour as 2. local run
  5. local run: same behaviour as 1. local run
  6. local run: same behaviour as 2. local run

This kind of seems to contradict your statement that the image gets rebuilt each time or maybe I misunderstood something.

I should maybe mention that the docker host (daemon) is running on a remote machine.

If this behaviour is indeed the intended one, I assume it would be best to move the "expensive" operations into a separate image and let my project's image be based on that?

jgangemi commented 8 years ago

can you post your pom profile?

rhuss commented 8 years ago

It gets rebuild, but Docker itself does an internal caching. When it builds an image based on an Dockerfile it will reuse the image layers create by each command as soon as it hits one which differs from a previous run. From this point on it will execute every line in the Dockerfile.

Indeed it makes sense to create an intermediated image (on which your application image is based) for things which doesn't change often.

jgangemi commented 8 years ago

this seems weird though - we don't remove the old image until the new one is built, so i'd think the layers would still be cached. can you post the Dockerfile you use as well?

rhuss commented 8 years ago

@jgangemi btw we have a regression in 0.13.7 which introduces a 'forced' removal of a previous image. But 'force' doesn't help if there is still a container running with this image so the build breaks at this point. which it shouldn't (warning is ok).

Will do a 0.13.8 soon with a fix for that.

jgangemi commented 8 years ago

is there an issue for that?

ooh - does that mean my xmas present comes early then too? :)

heapifyman commented 8 years ago

reverting back to 0.13.6 seems to fix the issue. as long as I do not add the project's artifact to the container like https://github.com/rhuss/docker-maven-sample does in assembly.xml and pom.xml.

if I do that, every mvn clean install seems to trigger a complete rebuild of the image, ignoring docker's cache. and it doesn't matter if it's run on jenkins or local.

mabrarov commented 3 years ago

I use Maven Assembly Plugin to build TAR of all files I add from build host into Docker image and this approach works fine with image layer cache, so that rebuild of project doesn't generate new image(s) if there are no new commits (but even with new commits we can use constant project.build.outputTimestamp to avoid rebuilding if no actual changes were made in the files packaged into the image). Refer to https://github.com/mabrarov/docker-compose-init-container repository for example.

Note that you need the recent versions of Maven Assembly Plugin and Spring Boot Maven Plugin supporting reproducible builds.

rhuss commented 3 years ago

Nice idea, would make a nice examples in the samples/ directory, too. Unfortunately I don't have any free spare cycles for doing this, but if you or some else is fancy to submit a PR I'm happy helping to integrate.

mabrarov commented 3 years ago

Nice idea, would make a nice examples in the samples/ directory

Hmm... Let me take that.

mabrarov commented 3 years ago

@rhuss,

Nice idea, would make a nice examples in the samples/ directory

Refer to the pull request #1412 for example which is friendly to Docker build cache and uses approach which I described in previous comment.