Testcontainers with sftp image throws Error on "nc not found" or "Address Not Available"

3.5k Views Asked by At

I have this very simple code for running my integration test: (using Testcontainer artifact version 1.16.2) Note: I have tested whether this port in test is available before running the test case.

@Testcontainers
public class SftpServerTestContainer {
    private static final int PORT = 2222;
    private static final String DOCKER_IMAGE_NAME = "atmoz/sftp:latest";
    private static final String USER_PASS = "foo:pass:::folder";

    @Container
    private static final GenericContainer sftpContainer =
            new GenericContainer<>(DockerImageName.parse(DOCKER_IMAGE_NAME));

    @Bean
    @Profile("test")
    public GenericContainer sftpContainerAsABean(){
        sftpContainer
            .withAccessToHost(true)  
                .withExposedPorts(PORT)
                .withCommand(USER_PASS);
        sftpContainer.start();
        return sftpContainer;
    }
}

It has a very simple startup process of a GenericContainer with a given name. But i could never start it up and end up in the following failure:

[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 >> "Content-Length: 26[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 >> "Host: localhost:2375[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 >> "Connection: keep-alive[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 >> "User-Agent: Apache-HttpClient/5.0.3 (Java/17)[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 >> "[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 >> "{"Detach":null,"Tty":null}"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 << "HTTP/1.1 200 OK[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 << "Content-Type: application/vnd.docker.raw-stream[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 << "Api-Version"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 << ": 1.41[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 << "Docker-Experimental: false[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 << "Ostype: linux[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 << "Server: Docker/20.10.13 (linux)[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] wire - http-outgoing-4 << "[\r][\n]"
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] headers - http-outgoing-4 << HTTP/1.1 200 OK
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] headers - http-outgoing-4 << Content-Type: application/vnd.docker.raw-stream
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] headers - http-outgoing-4 << Api-Version: 1.41
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] headers - http-outgoing-4 << Docker-Experimental: false
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] headers - http-outgoing-4 << Ostype: linux
[DEBUG] 2022-03-25 09:06:43.078 [docker-java-stream-164976604] headers - http-outgoing-4 << Server: Docker/20.10.13 (linux)
[DEBUG] 2022-03-25 09:06:43.137 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0][0x1a]/bin/sh: 1: nc: not found[\n]"
[DEBUG] 2022-03-25 09:06:43.138 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0]x/bin/bash: connect: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.138 [docker-java-stream-164976604] wire - http-outgoing-4 << "/bin/bash: /dev/tcp/localhost/2222: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.242 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0][0x1a]/bin/sh: 1: nc: not found[\n]"
[DEBUG] 2022-03-25 09:06:43.243 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0]x/bin/bash: connect: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.243 [docker-java-stream-164976604] wire - http-outgoing-4 << "/bin/bash: /dev/tcp/localhost/2222: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.346 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0][0x1a]/bin/sh: 1: nc: not found[\n]"
[DEBUG] 2022-03-25 09:06:43.347 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0]x/bin/bash: connect: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.347 [docker-java-stream-164976604] wire - http-outgoing-4 << "/bin/bash: /dev/tcp/localhost/2222: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.451 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0][0x1a]/bin/sh: 1: nc: not found[\n]"
[DEBUG] 2022-03-25 09:06:43.452 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0]x/bin/bash: connect: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.452 [docker-java-stream-164976604] wire - http-outgoing-4 << "/bin/bash: /dev/tcp/localhost/2222: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.555 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0][0x1a]/bin/sh: 1: nc: not found[\n]"
[DEBUG] 2022-03-25 09:06:43.556 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0]x/bin/bash: connect: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.556 [docker-java-stream-164976604] wire - http-outgoing-4 << "/bin/bash: /dev/tcp/localhost/2222: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.665 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0][0x1a]/bin/sh: 1: nc: not found[\n]"
[DEBUG] 2022-03-25 09:06:43.668 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0]x/bin/bash: connect: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.668 [docker-java-stream-164976604] wire - http-outgoing-4 << "/bin/bash: /dev/tcp/localhost/2222: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.778 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0][0x1a]/bin/sh: 1: nc: not found[\n]"
[DEBUG] 2022-03-25 09:06:43.780 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0]x/bin/bash: connect: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.780 [docker-java-stream-164976604] wire - http-outgoing-4 << "/bin/bash: /dev/tcp/localhost/2222: Cannot assign requested address[\n]"
[DEBUG] 2022-03-25 09:06:43.890 [docker-java-stream-164976604] wire - http-outgoing-4 << "[0x2][0x0][0

For some reason, I think docker-java lib that TestContainers is using nc to do some networking stuff. But if it is because of that, i quickly changed the image to atmoz/sftp:alpine and I received the following error (similar but not the same):

[DEBUG] 2022-03-25 09:11:36.145 [docker-java-stream--355075128] wire - http-outgoing-4 << "/bin/bash: line 1: /dev/tcp/localhost/2222: Address not available[\n]"
[DEBUG] 2022-03-25 09:11:36.250 [docker-java-stream--355075128] wire - http-outgoing-4 << "[0x2][0x0][0x0][0x0][0x0][0x0][0x0]l/bin/bash: connect: Address not available[\n]"
[DEBUG] 2022-03-25 09:11:36.250 [docker-java-stream--355075128] wire - http-outgoing-4 << "/bin/bash: line 1: /dev/tcp/localhost/2222: Address not available[\n]"

So I do not understand the underlying mechanism of Testcontainers in this case.

By the way, I also ran same integration test on keycloak image, and discovered that I always have nc not found error as well. But I think that's because Keycloak base image hardens the image for security purposes.

2

There are 2 best solutions below

8
On

First check if port 2222 is free in the machine that is launching the TestContainer.

Second, change you setup of GenericContainer to:

sftpContainer = new GenericContainer<>(DockerImageName.parse("atmoz/sftp:latest")).withExposedPorts(PORT)
        .withCommand("foo:pass:::folder")
        .withCreateContainerCmdModifier(
            cmd -> cmd.withHostConfig(
                new HostConfig()
                    .withPortBindings(new PortBinding(Ports.Binding.bindPort(22), new ExposedPort(PORT)))));

You need to map the exposed port (in your case 2222) into the internal port (22).

This example run on version 1.16.0 of testcontainers.

2
On

Testcontainers runs a couple of commands from within the container to determine when the intenral port of the container is available: https://github.com/testcontainers/testcontainers-java/blob/5e6dbc791b6184f0de6d1f9d184a78324c1ec945/core/src/main/java/org/testcontainers/containers/wait/internal/InternalCommandPortListeningCheck.java#L29-L38

This is part of the default HostPortWaitStrategy. It might be the case, that the atmoz/sftp:latest does not allow any of those commands to be run.

Also, your log level is on DEBUG, you should not give extra attention to those messages. What is the actual error you are getting?