77import org .testcontainers .utility .DockerImageName ;
88
99import java .util .ArrayList ;
10+ import java .util .HashSet ;
1011import java .util .List ;
12+ import java .util .Set ;
13+ import java .util .function .Supplier ;
1114
1215/**
1316 * Testcontainers implementation for Apache Kafka.
@@ -24,11 +27,11 @@ public class KafkaContainer extends GenericContainer<KafkaContainer> {
2427
2528 private static final int KAFKA_PORT = 9092 ;
2629
27- private static final String DEFAULT_INTERNAL_TOPIC_RF = "1" ;
28-
2930 private static final String STARTER_SCRIPT = "/tmp/testcontainers_start.sh" ;
3031
31- private static final String DEFAULT_CLUSTER_ID = "4L6g3nShT-eMCtK--X86sw" ;
32+ private final Set <String > listeners = new HashSet <>();
33+
34+ private final Set <Supplier <String >> advertisedListeners = new HashSet <>();
3235
3336 public KafkaContainer (String imageName ) {
3437 this (DockerImageName .parse (imageName ));
@@ -39,31 +42,16 @@ public KafkaContainer(DockerImageName dockerImageName) {
3942 dockerImageName .assertCompatibleWith (DEFAULT_IMAGE_NAME , APACHE_KAFKA_NATIVE_IMAGE_NAME );
4043
4144 withExposedPorts (KAFKA_PORT );
42- withEnv ("CLUSTER_ID" , DEFAULT_CLUSTER_ID );
43-
44- withEnv (
45- "KAFKA_LISTENERS" ,
46- "PLAINTEXT://0.0.0.0:" + KAFKA_PORT + ",BROKER://0.0.0.0:9093, CONTROLLER://0.0.0.0:9094"
47- );
48- withEnv ("KAFKA_LISTENER_SECURITY_PROTOCOL_MAP" , "BROKER:PLAINTEXT,PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT" );
49- withEnv ("KAFKA_INTER_BROKER_LISTENER_NAME" , "BROKER" );
50- withEnv ("KAFKA_PROCESS_ROLES" , "broker,controller" );
51- withEnv ("KAFKA_CONTROLLER_LISTENER_NAMES" , "CONTROLLER" );
52-
53- withEnv ("KAFKA_NODE_ID" , "1" );
54- withEnv ("KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR" , DEFAULT_INTERNAL_TOPIC_RF );
55- withEnv ("KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS" , DEFAULT_INTERNAL_TOPIC_RF );
56- withEnv ("KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR" , DEFAULT_INTERNAL_TOPIC_RF );
57- withEnv ("KAFKA_TRANSACTION_STATE_LOG_MIN_ISR" , DEFAULT_INTERNAL_TOPIC_RF );
58- withEnv ("KAFKA_LOG_FLUSH_INTERVAL_MESSAGES" , Long .MAX_VALUE + "" );
59- withEnv ("KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS" , "0" );
45+ withEnv (KafkaHelper .envVars ());
6046
6147 withCommand ("sh" , "-c" , "while [ ! -f " + STARTER_SCRIPT + " ]; do sleep 0.1; done; " + STARTER_SCRIPT );
6248 waitingFor (Wait .forLogMessage (".*Transitioning from RECOVERY to RUNNING.*" , 1 ));
6349 }
6450
6551 @ Override
6652 protected void configure () {
53+ KafkaHelper .resolveListeners (this , this .listeners );
54+
6755 String firstNetworkAlias = getNetworkAliases ().stream ().findFirst ().orElse (null );
6856 String networkAlias = getNetwork () != null ? firstNetworkAlias : "localhost" ;
6957 String controllerQuorumVoters = String .format ("%s@%s:9094" , getEnvMap ().get ("KAFKA_NODE_ID" ), networkAlias );
@@ -80,7 +68,10 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) {
8068 List <String > advertisedListeners = new ArrayList <>();
8169 advertisedListeners .add ("PLAINTEXT://" + getBootstrapServers ());
8270 advertisedListeners .add (brokerAdvertisedListener );
71+
72+ advertisedListeners .addAll (KafkaHelper .resolveAdvertisedListeners (this .advertisedListeners ));
8373 String kafkaAdvertisedListeners = String .join ("," , advertisedListeners );
74+
8475 String command = "#!/bin/bash\n " ;
8576 // exporting KAFKA_ADVERTISED_LISTENERS with the container hostname
8677 command += String .format ("export KAFKA_ADVERTISED_LISTENERS=%s\n " , kafkaAdvertisedListeners );
@@ -89,6 +80,69 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) {
8980 copyFileToContainer (Transferable .of (command , 0777 ), STARTER_SCRIPT );
9081 }
9182
83+ /**
84+ * Add a listener in the format {@code host:port}.
85+ * Host will be included as a network alias.
86+ * <p>
87+ * Use it to register additional connections to the Kafka broker within the same container network.
88+ * <p>
89+ * The listener will be added to the list of default listeners.
90+ * <p>
91+ * Default listeners:
92+ * <ul>
93+ * <li>0.0.0.0:9092</li>
94+ * <li>0.0.0.0:9093</li>
95+ * <li>0.0.0.0:9094</li>
96+ * </ul>
97+ * <p>
98+ * The listener will be added to the list of default advertised listeners.
99+ * <p>
100+ * Default advertised listeners:
101+ * <ul>
102+ * <li>{@code container.getConfig().getHostName():9092}</li>
103+ * <li>{@code container.getHost():container.getMappedPort(9093)}</li>
104+ * </ul>
105+ * @param listener a listener with format {@code host:port}
106+ * @return this {@link KafkaContainer} instance
107+ */
108+ public KafkaContainer withListener (String listener ) {
109+ this .listeners .add (listener );
110+ this .advertisedListeners .add (() -> listener );
111+ return this ;
112+ }
113+
114+ /**
115+ * Add a listener in the format {@code host:port} and a {@link Supplier} for the advertised listener.
116+ * Host from listener will be included as a network alias.
117+ * <p>
118+ * Use it to register additional connections to the Kafka broker from outside the container network
119+ * <p>
120+ * The listener will be added to the list of default listeners.
121+ * <p>
122+ * Default listeners:
123+ * <ul>
124+ * <li>0.0.0.0:9092</li>
125+ * <li>0.0.0.0:9093</li>
126+ * <li>0.0.0.0:9094</li>
127+ * </ul>
128+ * <p>
129+ * The {@link Supplier} will be added to the list of default advertised listeners.
130+ * <p>
131+ * Default advertised listeners:
132+ * <ul>
133+ * <li>{@code container.getConfig().getHostName():9092}</li>
134+ * <li>{@code container.getHost():container.getMappedPort(9093)}</li>
135+ * </ul>
136+ * @param listener a supplier that will provide a listener
137+ * @param advertisedListener a supplier that will provide a listener
138+ * @return this {@link KafkaContainer} instance
139+ */
140+ public KafkaContainer withListener (String listener , Supplier <String > advertisedListener ) {
141+ this .listeners .add (listener );
142+ this .advertisedListeners .add (advertisedListener );
143+ return this ;
144+ }
145+
92146 public String getBootstrapServers () {
93147 return String .format ("%s:%s" , getHost (), getMappedPort (KAFKA_PORT ));
94148 }
0 commit comments