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

Bug: KafkaContainer.tc_start not starting when using a Network

Open champialex opened this issue 1 year ago • 1 comments

If fails to start, since tc_start assumes that the container is using host networking

from docker.types import EndpointConfig
from testcontainers.core.container import DockerContainer
from testcontainers.core.network import Network
from testcontainers.kafka import KafkaContainer

def _connect_to_network(ctr: DockerContainer, network: Network, alias: str):
    # Needed until https://github.com/testcontainers/testcontainers-python/issues/645 is fixed
    ctr.with_kwargs(
        network=network.name, networking_config={network.name: EndpointConfig("1.33", aliases=[alias])}
    )

with Network() as network:
      ctr = KafkaContainer(image=f"confluentinc/cp-kafka:{KAFKA_VERSION}")
     _connect_to_network(ctr, network, "kafka")
     with ctr:
           assert ctr.get_bootstrap_server(). # This should start

A possible fix:


def tc_start(self):
    # We replace these three lines, which assume host networking
    # host = self.get_container_host_ip()
    # port = self.get_exposed_port(self.port)
    # listeners = f"PLAINTEXT://{host}:{port},BROKER://$(hostname -i | cut -d' ' -f1):9092"
    listeners = f"PLAINTEXT://{self._get_network_alias()}:{self.port},BROKER://$(hostname -i | cut -d' ' -f1):9092"
    data = (
        dedent(
            f"""
            #!/bin/bash
            {self.boot_command}
            export KAFKA_ADVERTISED_LISTENERS={listeners}
            . /etc/confluent/docker/bash-config
            /etc/confluent/docker/configure
            /etc/confluent/docker/launch
            """
        )
        .strip()
        .encode("utf-8")
    )
    self.create_file(data, KafkaContainer.TC_START_SCRIPT)

champialex avatar Aug 12 '24 05:08 champialex

I expanded this solution so I can connect from the docker network as well as the host:

class CustomKafkaContainer(KafkaContainer):
    def __init__(self):
        super().__init__()
        self.security_protocol_map += ",EXTERNAL:PLAINTEXT"
        self.with_env(
            "KAFKA_LISTENER_SECURITY_PROTOCOL_MAP", self.security_protocol_map
        )

        self.listeners = f"PLAINTEXT://0.0.0.0:29092,BROKER://0.0.0.0:9092,EXTERNAL://0.0.0.0:{self.port}"
        self.with_env("KAFKA_LISTENERS", self.listeners)

    def tc_start(self):
        listeners = ",".join(
            [
                f"EXTERNAL://{self.get_bootstrap_server()}",
                f"PLAINTEXT://{self._get_network_alias()}:29092",
                "BROKER://$(hostname -i | cut -d' ' -f1):9092",
            ]
        )
        data = (
            dedent(
                f"""
                #!/bin/bash
                {self.boot_command}
                export KAFKA_ADVERTISED_LISTENERS={listeners}
                . /etc/confluent/docker/bash-config
                /etc/confluent/docker/configure
                /etc/confluent/docker/launch
                """
            )
            .strip()
            .encode("utf-8")
        )
        self.create_file(data, KafkaContainer.TC_START_SCRIPT)

sushi30 avatar Aug 15 '24 13:08 sushi30