testcontainers-java icon indicating copy to clipboard operation
testcontainers-java copied to clipboard

ImageFromDockerfile does not support container reuse

Open ArthurasJ opened this issue 4 years ago • 10 comments

After updating to the 1.15.1 version of testcontainers I've noticed an issue, when trying to reuse containers for subsequent runs. I'm creating an image using ImageFromDockerfile, but it defines an image with "default" labels, that includes TESTCONTAINERS_SESSION_ID_LABEL. As far as I've checked, there is no way to not to inherit labels when creating a container using docker, which means, that container also contains this label and is removed by ryuk after test run. The commit that added "default" labels is this one: https://github.com/testcontainers/testcontainers-java/commit/6ac18b2b882f4c1a8b5d550d9ca79de339ce0265

ArthurasJ avatar Feb 24 '21 10:02 ArthurasJ

I can confirm that this bug is present from 1.14.3 to 1.15.3 with this class test :

public class MyTest {

    @Test
    public void testWorking() {
       PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:12.0").withReuse(true);

        postgres.start();

        System.out.println("containerid : " + postgres.getContainerId());

        // The container with image postgres:12.0 stays up after the end of the test
    }

    @Test
    public void testNotWorking() {

        GenericContainer<?> postgres = new GenericContainer<>(
                new ImageFromDockerfile().withDockerfileFromBuilder(builder -> builder
                .from("postgres:12.0")
                .expose(5432)
                .build())).withReuse(true);

        postgres.start();

        System.out.println("containerid : " + postgres.getContainerId());

        // The container with image postgres:12.0 is killed after the end of the test
    }
}

loic-seguin avatar May 01 '21 20:05 loic-seguin

This problem is really important because it forbids me to go upper 1.14.2 because I am using the reuse feature.

loic-seguin avatar May 11 '21 16:05 loic-seguin

@loic-seguin

// The container with image postgres:12.0 is killed after the end of the test

Most probably what happens is Ryuk removing the image, and the container is getting terminated as a result.

The reuse feature is very experimental, and ImageFromDockerfile was never promised to work with it. If you don't want the image to be removed, as a workaround, you may consider using buildImageCmd directly.

What's your use case for the image building, btw?

bsideup avatar May 11 '21 16:05 bsideup

This king of things for example :

new GenericContainer<>(
                new ImageFromDockerfile(urlImageDocker).withDockerfileFromBuilder(builder -> builder
                        .from(urlImageDocker)
                        .user("root")
                        .add("jenkins_home.tar.gz", "/var")
                        .expose(8080)
                        .run("chmod -R 777 /var/jenkins_home")
                        .build())
                        .withBuildArg("no-cache", "true")
                        .withFileFromClasspath("jenkins_home.tar.gz", "containers/jenkins/jenkins_home.tar.gz"))
                .withNetworkAliases("host")
                .withExposedPorts(8080)
                .withEnv("JAVA_OPTS", "-Djava.awt.headless=true -Xmx2048m ")
                .withEnv("JENKINS_OPTS", "--handlerCountMax=300")
                .waitingFor(Wait.forHttp("/login"))

loic-seguin avatar May 12 '21 07:05 loic-seguin

@loic-seguin you can do all of it with just GenericContainer, there is no need to build any image at all.

See withCopyFileToContainer (to copy the file) and withCreateContainerCmdModifier (to change the user)

bsideup avatar May 12 '21 07:05 bsideup

I have the same problem.

I'm baking my db migration scripts into a Dockerfile with the intent that layer caching will mean that I can have a clean but migrated DB on every container start.

But because ryuk is deleting the image every time it's actually more expensive, because the build has to install wget and flyway every time when those layers ought to be cached.

Mahoney avatar Nov 26 '21 08:11 Mahoney

Raised #4702 as I think it's a subtly different point that I don't want to delete the image at all!

Mahoney avatar Nov 26 '21 09:11 Mahoney

Is possible, that this issue is still open and not solved? I have simmilar problem, I added .withReuse(true) to my containers and Ryuk is still removing testing containers after tests finishes. I just upgraded docker to 4.21.1.

honzastefan avatar Jul 11 '23 12:07 honzastefan

I conducted some research on this issue and found out that reuse with imageFromDockerfile can be used in the following way and it will work:

@Test
public void myTest() {
    ImageFromDockerfile imageFromDockerfile = new ImageFromDockerfile("my-image:1.0", false)
    .withDockerfileFromBuilder(builder -> builder.from("postgres:12.0")
    .expose(5432).build());

    GenericContainer<?> postgres = new GenericContainer<>(imageFromDockerfile).withReuse(true);
    postgres.start();
    System.out.println("containerid : " + postgres.getContainerId());
}

Please note that you need to use the constructor ImageFromDockerfile with the parameters dockerImageName and deleteOnExit = false.

ilyaChekasin93 avatar Jun 13 '24 21:06 ilyaChekasin93

This issue might be closed since it's possible to use reuse along with dockerfile. However, when using the constructor with dockerImageName and deleteOnExit parameters and making changes to the dockerfile, if the image was previously created according to this dockerfile, the new image version will get the tag of dockerImageName while the old version will not be deleted and will get the none:none tag. I understand that this behavior is not related to testcontainers but to docker, still, I'd like to delete the old image version when it's updated. Would you mind if I created a task and made the corresponding change?

ilyaChekasin93 avatar Jun 14 '24 08:06 ilyaChekasin93