Java Testcontainers-无法连接到裸露的端口

时间:2019-10-02 13:36:56

标签: java docker junit dockerfile testcontainers

我使用javax.mail实现了POP3服务器和客户端,只是为了尝试与Docker进行集成测试。因此,我基于openjdk:8-jre映像创建了两个Docker映像,并将jars复制到它们并启动了它。根据我的配置(请参见下文),它正在运行。他们正在互相交谈。

但是,由于要进行多个集成测试,因此为每个构建一个映像并启动它们将很繁琐。我也不知道如何自动化结果。 但是后来我偶然发现了TestContainers,这似乎对实现这些测试有很大帮助。

因此,我开始使用POP3服务器映像作为GenericContainer将这些测试移植到TestContainers,并在JUnit测试方法中启动POP3 Client类。我暴露了POP3服务器正在监听的端口24999。但是当我尝试连接到服务器时,出现以下错误:

com.sun.mail.util.MailConnectException: Couldn't connect to host, port: localhost, 32782; timeout -1;
  nested exception is:
    java.net.ConnectException: Connection refused
...

TestContainers中可能缺少一些设置。你能帮我吗?

这是我正在使用的代码:

public class DockerPop3AutocryptKeyProvidingAndReceivingTest {
    @Test
    public void test() throws InterruptedException {
        GenericContainer container = new GenericContainer<>("immerfroehlich/emailfilter:latest")
                .withExposedPorts(24999);

        container.start();

        String host = container.getContainerIpAddress();
        String port = container.getFirstMappedPort().toString();

        //The following is simplified, but copied from the working jar used in the Docker Client image/container
        MyPOP3Client client = new MyPOP3Client(host, port);
        client.connect();

        container.stop();
    }
}

这是我创建Docker映像的方式:

FROM openjdk:8-jre

ADD build/distributions/MyPOP3Server.tar . #This is where I have packeded all the needed files to. It gets unpackeded by Docker.
#EXPOSE 24999 #I tried both with and without this expose
WORKDIR /MyPOP3Server/bin
ENTRYPOINT ["sh","MyPOP3Server"] #Executes the shell script wich runs java with my jar

这是在服务器Jar中运行的代码的简化版本:

MyPOP3Server server = new MyPOP3Server();
server.listenToPort(24999);

请告诉我我想念的是什么。怎么了?

谢谢和亲切的问候。

5 个答案:

答案 0 :(得分:1)

尝试添加http检查。

 new GenericContainer<>("immerfroehlich/emailfilter:latest")
 .withExposedPorts(24999)
 .waitingFor(new HttpWaitStrategy().forPort(24999)
 .withStartupTimeout(Duration.ofMinutes(5)));

容器可能会启动,但是您在服务器初始化之前尝试连接。

此外,注册一个日志附加程序,以查看容器中服务器的运行情况。

 .withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger(
              DockerPop3AutocryptKeyProvidingAndReceivingTest.class)))

答案 1 :(得分:0)

由于您的邮件服务器和客户端正在容器中运行,我认为您应该连接到端口24999而不是映射的端口

答案 2 :(得分:0)

尝试使用container.getMappedPort(24999)而不是getFirstMappedPort。可能您的docker映像暴露了两个端口。

答案 3 :(得分:0)

在其他答案中有一些好的建议;我将通过其他一些技巧来补充这些信息:

正如已经建议的:

  • 绝对添加LogConsumer,以便您可以看到容器的日志输出-可能在现在或将来会出现一些有用的信息。拥有总是很好。

  • 在启动容器之后,就在启动客户端之前设置断点。

此外,我希望以下事情能有所作为。在断点处暂停时:

  • 在终端上运行docker ps -a
  • 首先,检查您的容器是否正在运行并且尚未退出。如果已经退出,请查看终端中容器的日志。
  • 第二,检查docker ps输出中的端口映射。您应该看到类似0.0.0.0:32768->24999/tcp的内容(不过第一个端口号是随机的)。
  • 在IDE中评估container.getFirstMappedPort(),并检查返回的端口号是否与随机公开的端口号相同。除非您在本地计算机上安装了非常不寻常的Docker,否则应该可以通过localhost: +此端口访问此容器。
  • 如果您到此为止,那么容器或客户端代码可能有问题。您可以尝试将其他客户端连接到正在运行的容器-如果您没有其他POP3客户端,即使nc之类的设备也可以提供帮助。

另一种尝试是手动运行容器,只是为了减少发生的间接访问量。您提供的Testcontainers代码段等效于:

docker run -p 24999 immerfroehlich/emailfilter:latest

您可能会发现这可以帮助您将问题空间分成较小的部分。

答案 4 :(得分:0)

感谢您的所有帮助。这引导我走向解决方案。这是缺少的WaitStrategy和端口映射问题的组合。

这是我所做的: 1)在MyPop3Server.listenToPort(String port)方法中,我添加了System.out.println:

public class MyPop3Server {
  public void listenToPort(String port) {
     //simplified: do initialization and listenToPort
     System.out.println("Awaiting Connection...");
  }
}

在测试中,我添加了一个LogMessageWaitStrategy,用于监听“等待连接”

GenericContainer container = new GenericContainer<>("immerfroehlich/emailfilter:latest")
   .waitingFor(Wait.forLogMessage("Awaiting Connection.*", 1))
   .withExposedPorts(24999);

2)我从container.getFirstMappedPort()切换到

container.getMappedPort(24999);

这是整个已更改且有效的测试代码:

public class DockerPop3AutocryptKeyProvidingAndReceivingTest {
    @Test
    public void test() throws InterruptedException {
        GenericContainer container = new GenericContainer<>("immerfroehlich/emailfilter:latest")
                .waitingFor(Wait.forLogMessage("Awaiting Connection.*", 1))
                .withExposedPorts(24999);

        container.start();

        String host = container.getContainerIpAddress();
        String port = container.getMappedPort(24999).toString();

        //The following is simplified, but copied from the working jar used in the Docker Client image/container
        MyPOP3Client client = new MyPOP3Client(host, port);
        client.connect();

        container.stop();
    }
}

谢谢大家。