Preemptive apology for the novel of a comment, but I wanted to be detailed with my thoughts.
hrmpw is absolutely right, building the image every time does mostly defeat the purpose, but being able to store our Docker definition alongside our pipeline definition is exceedingly convenient for both our dev and QA in my experience so far.
This may or may not be hard to do from your end (I'm not too familiar with the code managing the Dockerfile interactions), but here's the way I imagine the Dockerfile flow in declarative pipeline could work:
Each declarative pipeline job run using a Dockerfile would retain 1 or more pairs of fingerprints, where each pair would contain a Dockerfile fingerprint and the fingerprint of the Docker image built from said Dockerfile.
Thus, for each declarative pipeline job run that utilizes Dockerfiles there are two possible paths to follow:
- The Dockerfile fingerprint does match the fingerprint from the previous job run, meaning that ideally we shouldn't rebuild unless we have to.
To determine that, we check the current node for the image fingerprint from the previous job run:
- If the current node does have an image that matches the image fingerprint from the previous job run, just run that image and continue with the job.
- If the current node doesn't have an image that matches the image fingerprint from the previous job run, then we logically need to build it on the current node even though the Dockerfile itself hasn't changed.
- The Dockerfile fingerprint doesn't match the fingerprint from the previous job run, meaning we should rebuild and clean up previously created Docker images if present.
Just like the first path we check the current node for the image fingerprint from the previous job run, but this time we focus on cleanup:
- If the current node does have an image that matches the image fingerprint from the previous job run, remove that image from the current node and then build and run like normal.
- If the current node doesn't have an image that matches the image fingerprint from the previous job run, then we've at least done our due diligence to clean up and just build and run like normal.
Keeping Dockerfile and Docker image fingerprints associated as a pair ensures that you can selectively remove or rebuild per Dockerfile used, and removing images only relative to fingerprints from the last job run handles what I'm guessing is the common case for Dockerfile image management.
I think this gives us the best overall user-friendliness for Dockerfiles in the declarative pipeline syntax, following the mentality that users generally shouldn't have to think too much about managing or selecting the nodes they're utilizing (or what arbitrary Docker images they create).
Let me know what you think or if I obviously missed something!
Interesting question here - how do we handle this? Do we want to delete the image after every build? michaelneale, jamesdumay, hrmpw - thoughts?