Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Dockerfile task to be UP-TO-DATE #357

Closed
ayedo opened this issue Mar 21, 2017 · 28 comments
Closed

Allow Dockerfile task to be UP-TO-DATE #357

ayedo opened this issue Mar 21, 2017 · 28 comments
Assignees
Labels
Milestone

Comments

@ayedo
Copy link

ayedo commented Mar 21, 2017

First of all: thanks for your awesome work!

I was wondering: why does the Dockerfile task set the following in the constructor:

Dockerfile() { outputs.upToDateWhen { false } }

I'm using the plugin to start a postgres database during the build in order to generate a jOOQ meta model. Incremental building does not work since in the end, the build chain depends on the Dockerfile task, which is never upToDate.

I tried overwriting the directive in my task, but without success.

@orzeh orzeh self-assigned this Mar 22, 2017
@orzeh orzeh changed the title Problems with Incremental Build Allow Dockerfile task to be UP-TO-DATE Mar 22, 2017
@orzeh
Copy link
Collaborator

orzeh commented Mar 22, 2017

@ayedo I think this is worth considering. I can imagine use cases when generated Dockerfile (task output) does not change for subsequent builds. We could remove the outputs.upToDateWhen { false } statement and allow developers to define task inputs explicit using standard Gradle syntax.

@cdancy WDYT?

@ayedo are you interested in submitting PR?

@cdancy
Copy link
Collaborator

cdancy commented Mar 22, 2017

@orzeh I agree. Think this was probably left in from when we attempted a go at making docker image reproduction "UP-TO-DATE".

@remmeier
Copy link

would be very helpful if this is fixed

@cdancy
Copy link
Collaborator

cdancy commented Apr 20, 2017

@remmeier submit a PR?

@cdancy cdancy added this to the v3.0.7 milestone May 14, 2017
@cdancy
Copy link
Collaborator

cdancy commented May 14, 2017

Removed in master. Next release will have change.

@cdancy cdancy closed this as completed May 14, 2017
@childnode
Copy link
Contributor

currently we suspect this change to cause images are not rebuild properly with the application plugin (com.bmuschko.docker-java-application) since a dockerDistTar anyway doesn't respect the distTar state and therefor this change in Dockerfile leads to deprecated Dockerfile even the distTar has changed

@kaserf
Copy link

kaserf commented Aug 6, 2017

Hi, I ran into a problem recently where I would change my "Dockerfile" task (specifically adding some environment variables and changing the entry point), however when I rebuild a task that depends on the "Dockerfile" task, the build task thinks that the "Dockerfile" task is up to date.

Could it be that this is a regression that was introduced by the fix for this issue? It sounds a bit like what @childnode is experiencing as well.

@cdancy
Copy link
Collaborator

cdancy commented Aug 7, 2017

@kaserf what version of the plugin are you using?

@kaserf
Copy link

kaserf commented Aug 7, 2017

@cdancy 3.0.9

@cdancy
Copy link
Collaborator

cdancy commented Aug 7, 2017

@kaserf that's why. Try upgrading to 3.0.12 and let me know how things workout. Fix for this was merged within the past couple releases.

@kaserf
Copy link

kaserf commented Aug 7, 2017

Just tried with 3.0.12, same problem.

@kaserf
Copy link

kaserf commented Aug 7, 2017

@cdancy can you point me to a commit that fixed this? Maybe that helps narrowing down my issue.

@orzeh
Copy link
Collaborator

orzeh commented Aug 7, 2017

Hi, I ran into a problem recently where I would change my "Dockerfile" task (specifically adding some environment variables and changing the entry point), however when I rebuild a task that depends on the "Dockerfile" task, the build task thinks that the "Dockerfile" task is up to date.

@kaserf You have to explicitly set inputs for task of type Dockefile. Try below snippet:

buildscript {
	repositories {
		jcenter()
	}
}

plugins {
	id "com.bmuschko.docker-remote-api" version "3.0.12"
}

ext {
	alpineVersion = "3"
}

task dockerfile(type: com.bmuschko.gradle.docker.tasks.image.Dockerfile) {
	from "alpine:$alpineVersion"
	inputs.property "alpineVersion", alpineVersion
}

task build {
	dependsOn dockerfile
}

@kaserf
Copy link

kaserf commented Aug 8, 2017

Thanks, I think there is a slight misunderstanding though!

What about the following change:

task createContext(type: Copy) {
  // copy the relevant files into it's own directory
}

task createDockerfile(type: Dockerfile, dependsOn: createContext) {
  destFile = file("somePath/Dockerfile")
  from baseImage
  instruction(['ENTRYPOINT', '/bin/bash'].join(' '))
}
task createContext(type: Copy) {
  // copy the relevant files into it's own directory
}

task createDockerfile(type: Dockerfile, dependsOn: createContext) {
  destFile = file("somePath/Dockerfile")
  from baseImage
  instruction(['ENTRYPOINT', 'echo', 'foobar'].join(' ')) // <------- changed this line
}

Should this set the up to date check to false? I would assume so. I am changing the task itself, that should always set it to not be up to date.

@orzeh
Copy link
Collaborator

orzeh commented Aug 8, 2017

@kaserf you are right. I think this is a bug. In Dockerfile class instructions property should have @Input rather then @Internal annotation. @cdancy WDYT?

@childnode
Copy link
Contributor

childnode commented Aug 8, 2017

so, this inputs.property thingy seems not to be a adequate solution since this will force to have a bunch of input.property setters and keep them in sync with any changes made to the Dockerfile ...
(but I see discussion continued since I began to write this ;=) and we're on track)

I would also suggest to implicit define the input properties on every instruction change. If this is the case when you change @Internal to/add @Input in Dockerfile: fine 👍
But please bear in mind to also add a defined Input like inputs.files distTar.outputs.files in case of the Application Plugin dockerDistTar definition to get an updated Dockerfile anytime the distTar changes ;)

Ps.: Time to reopen this issue or creating a PR for?

@cdancy
Copy link
Collaborator

cdancy commented Aug 8, 2017

@orzeh @kaserf @childnode so while we could make the instructions data structure as Optional and as an Input I don't think that will help folks along here at all. We have every method possible exposed to allow developers to pass along what they need to without having to touch this map. If anything I think we should make this private so that folks are not confused.

@kaserf from your snippet above were you able to move forward? It wasn't clear after trying the above if you were able to get around your problem.

@childnode if you have something in mind please feel free to send in a PR for review.

@kaserf
Copy link

kaserf commented Aug 8, 2017

Well, my workaround currently is to append this to my gradle file:

tasks.withType(Dockerfile) {
  outputs.upToDateWhen { false }
}

I took over this code from someone else, the gist seems to be not to use instructions but in my case use the entryPoint directive directly? In that case, I agree that this should probably be made private not to confuse people.

@cdancy
Copy link
Collaborator

cdancy commented Aug 8, 2017

@kaserf correct. You could either use entrypoint method or as I believe you used above the instruction method.

@childnode
Copy link
Contributor

@kaserf that brings us back to the beginning

@cdancy I don't understand in which cases the instruction list is not filled with the relevant information due to extensions on interfaces?

@cdancy
Copy link
Collaborator

cdancy commented Aug 8, 2017

@childnode there are 2 separate issues here at play. Yours is slightly different and it might warrant opening up another ISSUE/PR as you say if only to avoid folks chiming in here and confusing the flow of conversation.

@kaserf
Copy link

kaserf commented Aug 8, 2017

Talking about confusion...

@cdancy are you saying the way I am doing things (modulo the upToDateWhen hack forcing it to false), using instruction should work? That's what I got from your comment (#357 (comment)), but it's not working for me. Will try entrypoint later.

@kaserf
Copy link

kaserf commented Aug 8, 2017

Using entryPoint doesn't work either. If I change the string I pass to entryPoint, gradle does not consider that enough to set the task to "not up to date". Same behavior for me as when using instruction.

Should I open a bug for this @cdancy ?

@orzeh orzeh reopened this Aug 8, 2017
@orzeh
Copy link
Collaborator

orzeh commented Aug 8, 2017

OK, I was hacking with this for a while, and it turns out both issues have the same root. After removing outputs.upToDateWhen { false } from constructor, Dockerfile task once executed is up-to-date as long as resulting file exists. This leads to errors when instructions change either in custom Dockerfile task, as in @kaserf case or in generated by the DockerJavaApplicationPlugin as in @childnode case, respectively.

The problem is that Gradle knows task output, but doesn't know anything about inputs. We can't just add @Input annotation to instructions as I suggested earlier, because property must be Serializable (and it is not). Reading Gradle documentation about task inputs I found this:

You can specify a closure or Callable as the value of the property. In which case, the closure or Callable is executed to determine the actual property value.

This can be used to do the following:

Dockerfile() {
   inputs.property("instructionsCache", { instructions.collect { it.build() }.join('\n') })
}

Gradle will track string with instructions, which is the real task input. The closure will be evaluated in task execution phase, so everything should work as expected.

I've prepared proof-of-concept of this solution and will submit it as a PR. Any feedback welcome!

@orzeh orzeh added bug and removed enhancement labels Aug 8, 2017
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 9, 2017
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 9, 2017
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 9, 2017
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 9, 2017
@childnode
Copy link
Contributor

even I see this might be more related to #433 now, I'll continue here as an answer to @orzeh
And since they both have the same root (thanks for pointing out the differences you saw but I didn't) I don't see what to discuss in two threads?! never mind ...

once executed is up-to-date as long as resulting file exists.

what is predictable since gradle always only checks for incoming changes but not if the outcome would change .. have to, because else it will produce an outcome to then decide "not to run the task"

You can specify a closure or Callable as the value of the property. In which case, the closure or Callable is executed to determine the actual property value.

this ^ and the suggested change

inputs.property("instructionsCache", { instructions.collect { it.build() }.join('\n') })

would lead to longer build times, gradle startups due to the fact on any configuration phase, even the task is called or not, the input.property closure is evaluated and therefor the build() for all instructions are called.
Not only this, this also changes the behaviour of error handling or time of errors beeing presented to the user; because now it will be executed anytime, it will show instructions.build() errors even on every configuration phase instead of only on the task execution phase.

so I suggest to take the more affordable way to make instructions list Serializable. The only nut I see is to handle the closures given, but we can just serialize a hash from it, can't we?

just started to write a regression test ... childnode@1e2690c

childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 9, 2017
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 9, 2017
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 9, 2017
@cdancy
Copy link
Collaborator

cdancy commented Aug 9, 2017

@childnode if there is any room for improvement feel free to add that to your branch and we can review it there.

would lead to longer build times

I think this may be Ok as tasks of this nature should generally be smaller and the process time should be quick enough though if there is a better way then by all means put that into your branch/PR and lets have at it! ;)

childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 9, 2017
@childnode
Copy link
Contributor

childnode commented Aug 9, 2017

ok, seems to #433 fixed -both- two out of three (see more in #434) and has no negative affects. Thanks @cdancy and @orzeh for you affords

P.S: I expect

I tried overwriting the directive in my task, but without success.
is not a use case that someone intended but was an outcome of the try and error workaround of this issue before?
Let me ask a little bit different ... is anyone trying to do s.th. like

task dockerFile(type: Dockerfile) {
    outputs.upToDateWhen { moon.inZenith }
    from "alpine"
    environmentVariable "Foo", "Bar"
}

? If yes, this seems no to work in conjunction with the fix from #433

childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 9, 2017
…nZenith } }` a valid use case now the base issue is fixed by bmuschko#433 ? <<  bmuschko#357 (comment)
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 9, 2017
…nZenith } }` a valid use case now the base issue is fixed by bmuschko#433 ? <<  bmuschko#357 (comment)
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 16, 2017
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 16, 2017
…nZenith } }` a valid use case now the base issue is fixed by bmuschko#433 ? <<  bmuschko#357 (comment)
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 16, 2017
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 16, 2017
childnode added a commit to childnode/gradle-docker-plugin that referenced this issue Aug 17, 2017
cdancy pushed a commit that referenced this issue Aug 18, 2017
* added a first regression test for dockerfile error handling and upToDateSpec - adressing #357 and #433

* added some regression test for dockerfile error handling and upToDateSpec - adressing #357 and #433
@cdancy
Copy link
Collaborator

cdancy commented Aug 18, 2017

Closing as this has been addressed in a few PR's in an attempt to alleviate some (not all) of the issues noted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants