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

Add new withDockerfile methods to ImageFromDockerfile #1535

Merged

Conversation

aguibert
Copy link
Contributor

@aguibert aguibert commented Jun 6, 2019

These methods are preferable to the existing withDockerfilePath
methods because the docker-java API will honor .dockerignore files
if withDockerfile(File) is used.

@aguibert
Copy link
Contributor Author

aguibert commented Jun 6, 2019

Fixes #1534

Copy link
Member

@rnorth rnorth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this - it's a good idea. I have a few suggestions; hopefully we can resolve these fairly easily.

* It is recommended to use {@link #withDockerfile} instead because it honors .dockerignore
* files and therefore will be more efficient
* @param relativePathFromBuildRoot
*/
public ImageFromDockerfile withDockerfilePath(String relativePathFromBuildRoot) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder, would it be possible to make the existing withDockerfilePath take advantage of buildImageCmd::withDockerfile as well? I think it would be nice to change this PR so that:

  • Existing users of the withDockerfilePath method get the benefits of .dockerignore
  • We don't need to add (an effectively duplicate) method for withDockerfile(String pathname)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion, I had thought of this too and experimented a bit initially. Unfortunately I don't think this is feasible because we'd have to take into account things like setting the docker build path. I'm not sure if I'm missing any more, but I'm not familiar enough with the docker-java API (yet) to confidently make this change with certainty it will not break existing users.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shoud we deperecate the old method in this case?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense @aguibert - I can see how complexity could run away in trying to make it work.

I agree with @kiview re deprecating the existing method

log.info("Transferred {} KB to Docker daemon", bytesToDockerDaemon % 1024);
if (bytesToDockerDaemon > 50 * 1024 * 1024) // warn if >50MB sent to docker daemon
log.warn("A large amount of data was sent to the Docker daemon ({}). Consider using a .dockerignore file for better performance.",
bytesToDockerDaemon % (1024 * 1024));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, shouldn't it be?

Suggested change
bytesToDockerDaemon % (1024 * 1024));
bytesToDockerDaemon / (1024 * 1024));

and add MB to the log message so that it's clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, good catch!

}
tarArchive.finish();
}

log.info("Transferred {} KB to Docker daemon", bytesToDockerDaemon % 1024);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure about this calculation?

Shouldn't it be:

Suggested change
log.info("Transferred {} KB to Docker daemon", bytesToDockerDaemon % 1024);
log.info("Transferred {} KB to Docker daemon", bytesToDockerDaemon / 1024);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, why not use a consistent unit (either KB or MB) for both log messages?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to use MB for the "woa you transferred a lot of data" message, because at that order of magnitude it will be more easily readable. However, for this log statement there will be a lot of cases where <1MB will be transferred and I didn't want to report "0 MB of data transferred" because that's confusing. Also didn't think it was worth branching the code to do "report in KB if <1MB otherwise report in MB"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We happen to have commons-io FileUtils on the classpath - we could actually delegate all this formatting to its byteCountToDisplaySize method, and not have to worry about which is the most appropriate unit for either message. WDYT?

}

@Test
public void testDockerignoreWithString() throws Exception {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I missing something, or is this the same test as testDockerignoreWithFile()?

}
tarArchive.finish();
}

log.info("Transferred {} KB to Docker daemon", bytesToDockerDaemon % 1024);
if (bytesToDockerDaemon > 50 * 1024 * 1024) // warn if >50MB sent to docker daemon
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about adding constants for those magic numbers? 50_MB, MB_FACTOR for 1024 * 1024?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see commons-io FileUtils has some constants so I'll use those instead

* It is recommended to use {@link #withDockerfile} instead because it honors .dockerignore
* files and therefore will be more efficient
* @param relativePathFromBuildRoot
*/
public ImageFromDockerfile withDockerfilePath(String relativePathFromBuildRoot) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shoud we deperecate the old method in this case?

return this;
}

public ImageFromDockerfile withDockerfile(String pathname) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's not have this method, since it is unclear whether it will be using the classpath or FS

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. It could also be a dockerfile as a string!

I don't see why we couldn't remove this method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking it may be convenient so people don't have to do withDockerfile(new FIle("Dockerfile")) in the normal case. Since it may cause confusion I'll remove it though

@@ -63,6 +64,7 @@
private final Map<String, Transferable> transferables = new HashMap<>();
private final Map<String, String> buildArgs = new HashMap<>();
private Optional<String> dockerFilePath = Optional.empty();
private Optional<File> dockerfile = Optional.empty();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have Path here please?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bsideup do you mean hold an Optional<Path> object in the field and make the with-setter accept a Path, or just change the field type?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have File here because the underlying docker-java API takes a File, so I thought it would be best to not do the unnecessary conversion. Is there a particular reason we should be using Path over File?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path is a bit more forward thinking abstraction, easier to work with and I hope docker-java will adopt Path API soon too, so that we can avoid temporary files when it is possible.
I would prefer to have it in Testcontainers, because that's our public API, and to not block us from making changes to it later :)

@aguibert aguibert force-pushed the ImageFromDockerfile-withDockerfile branch from dd002ce to 96cc9ae Compare June 12, 2019 21:51
@aguibert
Copy link
Contributor Author

@rnorth @kiview @bsideup thanks for the reviews! I've updated my PR which I believe addresses all of the review comments thus far -- please have another look when you get some time


@Test
public void testValidDockerignore() throws Exception {
try (final GenericContainer container = new GenericContainer(new ImageFromDockerfile()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit1: please extract the image definition

nit2: could you please add a line break after try ( and also before ) {? I know that we're a bit inconsistent, but usually it helps, especially with long fluent-style chains

@@ -0,0 +1 @@
this file should be ignored by a .dockerignore file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filename says that it should not be ignored

@aguibert aguibert force-pushed the ImageFromDockerfile-withDockerfile branch from 96cc9ae to a74b77f Compare June 21, 2019 19:51
.withDockerfile(DockerfileBuildTest.RESOURCE_PATH.resolve("Dockerfile-currentdir"));
try (final GenericContainer<?> container = new GenericContainer<>(img.get())
.withStartupCheckStrategy(new OneShotStartupCheckStrategy())
.withCommand("ls", "/"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If would be nice to format it like here:

try(
GenericContainer container = new GenericContainer("alpine:latest")
.withCommand("sleep","3000")
.withCopyFileToContainer(MountableFile.forClasspathResource("/mappable-resource/"), containerPath)
) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(maybe this a space between try and (

.get();
fail("Should not be able to build an image with an invalid .dockerignore file");
}
catch(DockerClientException e) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
catch(DockerClientException e) {
catch (DockerClientException e) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must say you are quite particular on code formatting @bsideup ;) Perhaps if you want to enforce this strict of formatting conventions, you could add a checkstyle plugin to the project?

.withCommand("cat", "/test.txt")) {

.withCommand("cat", "/test.txt"))
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this is an unrelated change. Just cleaning up formatting to match what you had requested in another review comment since I was changing this file already

@aguibert aguibert force-pushed the ImageFromDockerfile-withDockerfile branch from a74b77f to 7c87b38 Compare July 8, 2019 04:25
@bsideup bsideup requested review from rnorth and kiview July 16, 2019 09:50
@bsideup bsideup added this to the next milestone Jul 16, 2019
These methods are preferable to the existing withDockerfilePath
methods because the docker-java API will honor .dockerignore files
if withDockerfile(File) is used.
@aguibert aguibert force-pushed the ImageFromDockerfile-withDockerfile branch from ee8e534 to aeb7557 Compare July 16, 2019 13:45
@aguibert
Copy link
Contributor Author

rebased branch so it's up-to-date with master. Should be good to merge now

Copy link
Member

@kiview kiview left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the useful PR, just had one more question, we can address this later.

@rnorth
Copy link
Member

rnorth commented Jul 17, 2019

That's 3 approvals, I'll merge. Thanks for another great contribution @aguibert, and sorry that it's taken a while to get this in.

@rnorth rnorth merged commit 7ca3f9f into testcontainers:master Jul 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants