有序启动和等待容器

Posted

技术标签:

【中文标题】有序启动和等待容器【英文标题】:Ordered starting and waiting for containers 【发布时间】:2019-08-26 03:49:27 【问题描述】:

我的测试中有两个容器使用 @Testcontainers 和 Junit5,一个 Kafka 和一个 KafkaConnect

@Container
private final KafkaContainer kafka = new KafkaContainer()
        .withNetwork(network)
        .withNetworkAliases("kafka");

@Container
private final GenericContainer KafkaConnect = 
        new GenericContainer("confluentinc/cp-kafka-connect:latest")
        .withEnv("CONNECT_BOOTSTRAP_SERVERS", "kafka:9092")
        .withEnv("CONNECT_REST_PORT", 8083)
        .withNetwork(network)
        ...

当我执行测试时,我发现一个错误,因为 kafkaConnect 中的 Kafka Connect 服务没有正确启动(映射端口 8083 没有监听)。这是因为kafkaConnectkafka 之前启动,并且在kafkaConnect 执行期间到达kafka:9092 url 时没有获得响应,因为kafka 尚未运行。 然后,我尝试推迟 kafkaConnect 启动以等待 kafka 以确保 kafka:9092 可用性。

我尝试了不同的方法来做到这一点,但我没有解决问题。 我尝试添加一些配置。

startupTimeout。据我所知,这个配置不会推迟启动操作。它只是增加了检查容器是否启动的时间。

.withStartupTimeout(Duration.of(240, SECONDS)) 

我还尝试了waitingFor 的一些配置,例如基于超时的配置,不出所料,它产生的结果与withStartupTimeout 相同

.waitingFor(Wait.defaultWaitStrategy().withStartupTimeout(...))

或基于端口,这并不能解决我的问题,因为它不指向kafka 容器,而是指向kafkaConnect

.waitingFor(Wait.forHttp("http://kafka:9092"))

我也尝试添加一些启动尝试,但它并没有解决问题,因为 kafkaConnect 会重新启动几次,但总是在 kafka 之前。

作为解决方案,我删除了kafkaConnect 声明中的@Container,以便手动管理其生命周期,因此我在测试用例中添加了显式开始,见下文

@Test
test() 
    kafkaConnect.start();
    ...

这确保kafkaConnectkafka 之后启动。但是,我没有找到在容器定义期间通过策略、策略或类似的东西来定义顺序的解决方案,以便在容器之间添加依赖关系并避免强制性和手动的生命周期管理。

有可能吗?

【问题讨论】:

我猜 Compose 在这里很有用,但我从容器声明中找到了解决方案 【参考方案1】:
import org.junit.rules.RuleChain;

// @Container <-- Remove annotation.
private final KafkaContainer kafka = new KafkaContainer()...;

// @Container <-- Remove annotation.
private final GenericContainer kafkaConnect = 
        new GenericContainer("confluentinc/cp-kafka-connect:latest")
        .withEnv("CONNECT_BOOTSTRAP_SERVERS", "kafka:9092")
        ...;

// Start the containers in the correct order.  Prevents
// "Mapped port can only be obtained after the container is started"
// error.
@Rule
public final RuleChain chain = 
    RuleChain
    // Started first.
    .outerRule(kafka)
    // Started later.
    .around(kafkaConnect);

【讨论】:

以上是关于有序启动和等待容器的主要内容,如果未能解决你的问题,请参考以下文章

等待容器在测试容器中使用 GenericContainer 启动自定义 PostgreSQL 映像

成功等待脚本后如何启动 docker 容器

在我的 spring-boot 应用程序启动之前,我如何等待数据库容器启动

docker-compose 等待启动,直到挂载主机文件系统

如何告诉python使用者等待客户端启动

docker asp.net 核心容器在 mysql 容器之后启动