Skip to content

Conversation

@strowk
Copy link

@strowk strowk commented Aug 3, 2025

What does this PR do?

Adding support for apache/kafka and apache/kafka-native images into existing kafka module without breaking backward compatibility for users who might have used existing Confluent features.

Apache images are significantly faster, especially native one (~2-3 seconds vs 11-17 for example test).

Why is it important?

Put simply Kafka Native is blazingly fast. It is based on GraalVM in native mode, which compiles Java code into native binary. This translates into very fast starting time and starting time is what always important in tests (unlike in runtime) and what is normally very slow for Java. In my relatively simple tests on my relatively powerful machine, the improvement is from 16.6 seconds to 3.6 seconds. Translate this into say 100 tests and the improvement can be measured in minutes if not hours for big projects.

This change also can fix this issue due to changed way of starting the process: #2206
, so long as user would switch image to the one from Apache.

Related issues

How to test this PR

Explain here how this PR will be tested by the reviewer: commands, dependencies, steps, etc.

# pull images first
docker pull confluentinc/confluent-local:7.4.0
docker pull confluentinc/confluent-local:7.5.0
docker pull apache/kafka-native:4.0.1
docker pull apache/kafka:4.0.1
docker pull apache/kafka-native:3.9.1
docker pull apache/kafka:3.9.1

# run test for all those images
cd modules/kafka && go test -timeout 90s -count 1 -run '^TestKafka$' github.com/testcontainers/testcontainers-go/modules/kafka; cd -

Check out difference in start times:

cd modules/kafka && go test -timeout 30s -count 1 -run '^ExampleRun_confluentinc$' github.com/testcontainers/testcontainers-go/modules/kafka; cd -

cd modules/kafka && go test -timeout 30s -count 1 -run '^ExampleRun_apacheNative$' github.com/testcontainers/testcontainers-go/modules/kafka; cd -

cd modules/kafka && go test -timeout 30s -count 1 -run '^ExampleRun_apacheNotNative$' github.com/testcontainers/testcontainers-go/modules/kafka; cd -

Typical outcome:

image

These are benchmarks that only measure start and stop:

goos: linux
goarch: amd64
pkg: github.com/testcontainers/testcontainers-go/modules/kafka
cpu: AMD Ryzen 9 7940HS w/ Radeon 780M Graphics
=== RUN   BenchmarkConfluentStartStop
BenchmarkConfluentStartStop
BenchmarkConfluentStartStop-16                 1        13686264643 ns/op        9148552 B/op      50522 allocs/op
=== RUN   BenchmarkApacheNativeStartStop
BenchmarkApacheNativeStartStop
BenchmarkApacheNativeStartStop-16              2         882227018 ns/op         2650628 B/op      10643 allocs/op
=== RUN   BenchmarkApacheStartStop
BenchmarkApacheStartStop
BenchmarkApacheStartStop-16                    1        3708939089 ns/op         7082360 B/op      34003 allocs/op

Confluent: ~13.7 s
Apache Native: ~0.9 s
Apache: ~3.7 s

Additional Context

There are two other PR's attempting to add Kafka Native support.

Difference with 2683

A brief difference:

  • this PR keeps kafka module backwards-compatible to avoid potentially breaking workflows for users depending on details of confluent implementation
  • this PR does not attempt to add SASL support and instead only focuses on using apache/kafka and apache/kafka-native images
  • this PR does not remove starting script (advertising needs to detect correct hostname, at least for docker in Windows) and instead just adds "exec" before starting Apache Kafka process, this should help with related issue linked above because exec would replace process instead of starting a new one and piping streams, so signals would go to the right process properly

Difference with 3488

A brief difference:

  • this PR updates documentation in such a way that would steer new users towards most efficient apache/kafka-native image, but also is clear about which module version supports it and about tradeoffs (i.e missing CLI tools)
  • this PR introduces three separate ExampleRun_.. methods in order to have three different "tabs" in documentation for every kind of supported image
  • this PR does not change starterScriptContent or CMD for confluent case in any meaningful way, so has a chance of being more backwards compatible
  • this PR keeps env variables such that docs still show them completely (or as completely as before)
  • this PR does not add docker inspect call that would be used to build starter script
  • this PR keeps two separate starter scripts - one for confluent and one for apache instead of making script smarter to pick what to do based on presence of confluent-related files (and documentation is changed accordingly to show both scripts depending on what user picks)
  • this PR instead chooses starting script based on prefix of docker image - this might break, however, if user does not use "docker.io", but some different registry. In this case user has an option to override the choice: kafka.WithApacheFlavor() or kafka.WithConfluentFlavor() or even pass their own custom script using kafka.WithStarterScript

@strowk strowk requested a review from a team as a code owner August 3, 2025 03:57
@netlify
Copy link

netlify bot commented Aug 3, 2025

Deploy Preview for testcontainers-go ready!

Name Link
🔨 Latest commit 3034eea
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-go/deploys/691efc1077bbca00089064f1
😎 Deploy Preview https://deploy-preview-3249--testcontainers-go.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@strowk strowk force-pushed the feature/kafka_native branch 2 times, most recently from eabd044 to b4dcd24 Compare August 3, 2025 04:03
@strowk
Copy link
Author

strowk commented Aug 3, 2025

For comparison: on my machine currently, TestKafka in kafka_native runs in 3.6 seconds, while original module test runs in 16.6 seconds. On big codebases and weaker machines this could translate in significant speed up!

$ cd modules/kafka_native && go test -timeout 30s -count 1 -run '^TestKafka$' github.com/testcontainers/testcontainers-go/modules/kafka_native ; cd -
ok      github.com/testcontainers/testcontainers-go/modules/kafka_native        3.693s

$ cd modules/kafka && go test -timeout 30s -count 1 -run '^TestKafka$' github.com/testcontainers/testcontainers-go/modules/kafka ; cd -
ok      github.com/testcontainers/testcontainers-go/modules/kafka       16.654s

Tests themselves are identical, only different images and less confluent-dependant configs.

Upd: Commands above are outdated, check PR description for up to date way to measure.

@strowk strowk force-pushed the feature/kafka_native branch from b4dcd24 to b044a54 Compare August 3, 2025 04:19
@strowk strowk force-pushed the feature/kafka_native branch from b044a54 to 1ef2f84 Compare August 3, 2025 04:22
@mdelapenya
Copy link
Member

mdelapenya commented Sep 11, 2025

Hi @strowk thanks for adding this! I'm currently taking a look, also discussing internally with the other TC maintainers if this code should live as a new sub-package under the kafka module. What are your thoughts on this?

@mdelapenya mdelapenya added the feature New functionality or new behaviors on the existing one label Sep 11, 2025
@strowk
Copy link
Author

strowk commented Sep 14, 2025

Sounds ok, though not sure what would interface look like

@mdelapenya
Copy link
Member

mdelapenya commented Sep 15, 2025

Hmmm thinking more in depth about the submodule, will the existing kafka options apply to this native image? If so, then we should probably find them, although it can be probably done in a follow-up.

@mabrarov
Copy link
Contributor

mabrarov commented Nov 8, 2025

Hi @mdelapenya and @strowk,

Are we ensured we need a new module instead of extending existing one (kafka)? I planned to prepare that change - refer to main...mabrarov:testcontainers-go:feat/kafka_alt_images - since May 2025 (refer to #2683 (comment) and mabrarov/testcontainers-go-kafka-2206#2), but I got time for that just recently.

Please note that (my case) usage of apache/kafka-native image can be problematic due to this image doesn't contain tools (like kafka-topics) which can be required for Kafka health check (e.g. in Docker Compose or Kubernetes). Using different images for tests (Testcontainers: apache/kafka-native) and local / dev or QA environments (Docker Compose, Kubernetes: apache/kafka) can bring additional issues.

Thank you.

@strowk
Copy link
Author

strowk commented Nov 8, 2025

@mabrarov , if I understand correctly some earlier concerns from maintainers were that removing confluent image from existing module would be not backwards compatible change for users that rely on something confluent specific (I for sure am one of those, albeit I know how to transition).

I.e it would for those users look such that the new version is pulled by something like dependabot or renovate and then they have to figure out how to transition to new image and have to stop updating testcontainers until the solution is found, which is somewhat undesirable situation.
I base this line of thinking on the discussion in the other PR introducing kafka native that I linked in description.

#2683 (comment)

As to bitnami.. seeing what Broadcom did recently to images and how much the secured ones cost.. I sort of doubt it would find very many users TBH. This is just my opinion of course, but I would avoid bitnami as much as possible from now on.

@mabrarov
Copy link
Contributor

mabrarov commented Nov 8, 2025

Hi @strowk,

You are right about binami/kafka image (the reason I got back to this work).

As for confluentinc/confluent-local image - we can keep it too while adding support for apache/kafka and apache/kafka-native images to kafka module. Feel free to check feat/kafka_alt_images branch I referenced in my previous comment. Anyway, I'm happy (and appreciate) the work on kafka module is going on even if it will be a dedicated module. My need in that case is to support not just apache/kafka-native but apache/kafka image too.

Thank you.

@strowk
Copy link
Author

strowk commented Nov 8, 2025

@mabrarov

Ooh, thanks for clarification, I did not know that there separate apache/kafka is somehow significantly better than the native one.

This does mean that it would be better for users to have access to all three possible images -confluent/apache-not-native/apache-native via same module and pick between "flavors" by some sort of an option probably?
I feel like it should be more explicit than just giving different image and module generating different configs based on that image..
Though of course configs derived from image would be easier to use probably, assuming it will not break :)

@mabrarov
Copy link
Contributor

mabrarov commented Nov 8, 2025

@strowk,

it would be better for users to have access to all three possible images -confluent/apache-not-native/apache-native via same module and pick between "flavors" by some sort of an option probably?

It is a question I have too. Maybe maintainers of Testcontainers for Go can answer it?

IMHO: only limited set of docker images (including tags) can be supported because we cannot predict what changes will be introduced in new version of image. Considering this limitation I'd just recommend to use specific (including tag) image with Testcontainers.

Thank you.

@strowk
Copy link
Author

strowk commented Nov 8, 2025

@mabrarov , I suppose that deriving what to do from parsing the image is a common answer in codebase as I can see:

https://github.com/testcontainers/testcontainers-go/blob/main/modules/elasticsearch/version.go

func isMinimumVersion(image string, minVersion string) bool {

func isAtLeastVersion(image, major string) bool {

Though it is usually about version of same "flavor", but I dont see that much difference, except we probably would need to allow user to override whatever we define..

@mabrarov
Copy link
Contributor

mabrarov commented Nov 8, 2025

Hi @strowk,

Examples you referenced in #3249 (comment) cover only lower bound while I am worried about upper bound too. Anyway, we can start from:

  1. Check for the minimum version for each image repository/flavor.
  2. Use some specific images in tests to have them as recommendation for the users (maybe need to cover that explicitly in documentation).

I feel it will be still the "Testcontainers way".

Thank you.

@strowk
Copy link
Author

strowk commented Nov 8, 2025

@mabrarov , I have made an attempt at this based on a very simple logic that looks like this:

const (
	apacheKafkaImagePrefix  = "apache/kafka"
	confluentincImagePrefix = "confluentinc/"
	dockerIoPrefix          = "docker.io/"
)

func isApache(image string) bool {
	return strings.HasPrefix(image, apacheKafkaImagePrefix) || strings.HasPrefix(image, dockerIoPrefix+apacheKafkaImagePrefix)
}

func isConfluentinc(image string) bool {
	return strings.HasPrefix(image, confluentincImagePrefix) || strings.HasPrefix(image, dockerIoPrefix+confluentincImagePrefix)
}

func getStarterScriptContent(image string) string {
	if isApache(image) {
		return apacheStarterScriptContent
	} else if isConfluentinc(image) {
		return confluentincStarterScriptContent
	} else {
		// Default to confluentinc for backward compatibility
		// in situations when image was custom specified based on confluentinc
		return confluentincStarterScriptContent
	}
}

This does not care about specific version as such, only whether or not image is confluent vs apache. In this "apache/kafka-native" and "apache/kafka" would work the same (starter script has no issues with either so far as I can tell).

It seems to work on and I tried with confluent, native and usual apache with this times:

  • 14.77s for confluentinc
  • 2.13s for native
  • 5.65s for apache not native

This is just one run of course, so not super representative, but kind of interesting that apache/kafka shows good timing vs confluentinc one, though still not quite as good as native.

This should make it easier for users to start.
The change attempts to steer new users to
start with native image, which shows significant
performance improvement especially if many
containers need to be started during entire
test, due to GraalVM optimizations.
While new users should prefer using Kafka
Native, these changes are made in a non-breaking
fashion such that if image was not detected as
being from Apache, it is assumed to be from
Confluent, so that even custom images that
used to work before should continue to work,
in case if they were based on confluentinc images
@coderabbitai
Copy link

coderabbitai bot commented Nov 8, 2025

Warning

Rate limit exceeded

@strowk has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 17 minutes and 31 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 1fc9b85 and 3034eea.

📒 Files selected for processing (2)
  • docs/modules/kafka.md (5 hunks)
  • modules/kafka/options_test.go (1 hunks)

Summary by CodeRabbit

  • New Features

    • Added support for Apache Kafka and Apache Kafka Native image variants alongside Confluent images.
    • Introduced flavor selection options for Apache and Confluent Kafka configurations.
    • Added custom starter script configuration capability.
    • Added localhost listener configuration support.
  • Documentation

    • Updated Kafka module documentation with comprehensive guidance for multiple image types, flavor options, and KRaft mode requirements.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Detect Kafka image family at runtime and introduce RunOption-based configuration (WithApacheFlavor, WithConfluentFlavor, WithStarterScript, WithClusterID); select appropriate starter script during post-start; update Run flow, docs, examples, tests, and benchmarks to support multiple image flavors, localhost listener, and graceful shutdown.

Changes

Cohort / File(s) Summary
Documentation
docs/modules/kafka.md
Title/intro and examples updated; added Apache image support (apache/kafka, apache/kafka-native), starter-script notes, Kraft requirements, localhost listener, and Run signature showing testcontainers.ContainerCustomizer.
Core runtime & starter script
modules/kafka/kafka.go
Starter script refactor: separate Apache/Confluent starter scripts, use path-based copy; Run builds runOptions from image+opts; copyStarterScript now accepts *runOptions; validation uses image-family detection.
Options surface
modules/kafka/options.go
New RunOption type implementing ContainerCustomizer; added WithStarterScript, WithClusterID, WithApacheFlavor, WithConfluentFlavor; flavor conflict detection and starter-script precedence implemented.
Image detection & selection
modules/kafka/version.go
New image prefix constants and predicates (isApache, isConfluentinc) with docker.io handling; getStarterScriptContent(image) selects starter script based on image or opts.
Examples
modules/kafka/examples_test.go
Added examples for apache native/non-native, flavor-specific usage, and localhost-listener; previous example renamed to ExampleRun_confluentinc.
Unit tests (options/version)
modules/kafka/options_test.go, modules/kafka/version_test.go
Tests for starter-script selection, isApache/isConfluentinc predicates, and WithStarterScript override behavior.
Integration & behavior tests
modules/kafka/kafka_test.go
Converted to table-driven tests across image variants; added TestKafkaGracefulShutdown, TestKafkaLocalhostListener, TestFailOnBothFlavors, and helper runner.
Benchmarks
modules/kafka/benchmark_test.go
Added start/stop benchmarks for Confluent and Apache (native and non-native) images.
API/signature changes
modules/kafka/kafka.go, modules/kafka/options.go
copyStarterScript signature changed to accept (*runOptions, ...); Run/docs updated to accept ...testcontainers.ContainerCustomizer; new RunOption helpers added; WithClusterID moved/adjusted.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Caller (examples/tests)
    participant Run as kafka.Run
    participant Resolver as runOptions
    participant Post as post-start hook
    participant Copy as copyStarterScript
    participant Container as Container FS

    Note over Run,Resolver: build runOptions from image + supplied RunOption(s)
    Caller->>Run: Run(ctx, image, opts...)
    Run->>Resolver: build runOptions(image, opts)
    Run->>Post: register post-start(container, runOptions)
    Post->>Copy: copyStarterScript(ctx, runOptions, container)
    Copy->>Resolver: resolve starter script (getStarterScriptContent / opts)
    alt WithStarterScript supplied
        Resolver-->>Copy: custom starter script
    else Apache image detected
        Resolver-->>Copy: apache starter script
    else
        Resolver-->>Copy: confluent starter script (default)
    end
    Copy->>Container: write starter script path & set entrypoint
    Container-->>Copy: ack
    Post-->>Run: readiness & wait completion
    Run-->>Caller: container ready / error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Files needing extra attention:
    • modules/kafka/version.go — prefix matching and docker.io variants.
    • Propagation of RunOption/runOptions and updated copyStarterScript(ctx, opts, c) signature across call sites.
    • Precedence and conflict handling between WithStarterScript, WithApacheFlavor, and WithConfluentFlavor.
    • Tests relying on timing/waits (graceful shutdown, localhost listener) for flakiness and cleanup.
    • validateKRaftVersion change to image-family detection.

Possibly related PRs

Suggested reviewers

  • mdelapenya

Poem

🐇 I hopped through files with whiskers bright,
I pick a script by image, day or night,
Apache or Confluent — starter chosen right,
Brokers spin, listeners hum into light,
I leave a tiny carrot for CI's delight.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly and concisely describes the main change: adding support for apache/kafka and apache/kafka-native images to the existing kafka module.
Description check ✅ Passed The pull request description thoroughly explains what is being added (Apache Kafka image support), why it matters (significant performance improvements), how to test it (with specific commands and expected results), and related considerations.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@strowk strowk changed the title feat(kafka_native): new module feat(kafka): add apache/kafka and apache/kafka-native support Nov 8, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
modules/kafka/version.go (1)

19-29: Consider simplifying the conditional chain.

The else if isConfluentinc(image) on line 22 could be simplified to just else since the final else block already defaults to confluentincStarterScriptContent. However, the explicit check makes the logic self-documenting and clearer.

Optional refactor:

 func getStarterScriptContent(image string) string {
 	if isApache(image) {
 		return apacheStarterScriptContent
-	} else if isConfluentinc(image) {
-		return confluentincStarterScriptContent
 	} else {
 		// Default to confluentinc for backward compatibility
 		// in situations when image was custom specified based on confluentinc
 		return confluentincStarterScriptContent
 	}
 }
modules/kafka/examples_test.go (1)

12-109: Consider consolidating duplicate example code.

All three example functions (ExampleRun_confluentinc, ExampleRun_apacheNative, ExampleRun_apacheNotNative) are nearly identical, differing only in the image string. While separate examples may aid documentation clarity, this creates a maintenance burden.

Consider extracting common logic into a helper or documenting all variants in a single example with a table showing the different images. However, if separate examples are intentional for documentation purposes (to appear distinctly in godoc), the current approach is acceptable.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c100f88 and 0a80e8c.

📒 Files selected for processing (6)
  • docs/modules/kafka.md (4 hunks)
  • modules/kafka/examples_test.go (2 hunks)
  • modules/kafka/kafka.go (6 hunks)
  • modules/kafka/kafka_test.go (2 hunks)
  • modules/kafka/version.go (1 hunks)
  • modules/kafka/version_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
modules/kafka/examples_test.go (3)
modules/kafka/kafka.go (2)
  • Run (55-129)
  • WithClusterID (159-165)
cleanup.go (1)
  • TerminateContainer (97-108)
log/logger.go (1)
  • Printf (47-49)
modules/kafka/kafka.go (1)
container.go (1)
  • Container (41-73)
modules/kafka/version_test.go (1)
modules/kafka/kafka.go (1)
  • Run (55-129)
modules/kafka/kafka_test.go (1)
modules/kafka/kafka.go (2)
  • Run (55-129)
  • WithClusterID (159-165)
🪛 LanguageTool
docs/modules/kafka.md

[style] ~58-~58: Using many exclamation marks might seem excessive (in this case: 6 exclamation marks for a text that’s 3313 characters long)
Context: ...ound(), "apache/kafka-native:4.0.1")`. !!! warning Module expects that the ima...

(EN_EXCESSIVE_EXCLAMATION)

🔇 Additional comments (13)
modules/kafka/version.go (1)

11-17: LGTM! Image detection logic is correct.

The predicates correctly identify Apache and Confluent images, including handling for the docker.io/ prefix. The Apache check covers both apache/kafka and apache/kafka-native images as intended.

modules/kafka/version_test.go (2)

71-115: LGTM! Comprehensive test coverage.

The test thoroughly covers various image formats including tags, no tags, and the docker.io/ prefix for both Confluent and non-Confluent images.


117-171: LGTM! Good coverage of starter script selection.

The test validates the correct starter script content is returned for Apache, Confluent, and custom images across different tag formats.

modules/kafka/kafka_test.go (2)

15-67: LGTM! Good extraction of common test logic.

The testFor helper function effectively parameterizes the test by image, enabling consistent testing across multiple Kafka image variants.


69-93: LGTM! Effective use of table-driven tests.

The table-driven approach ensures all three Kafka image variants (Confluent, Apache native, Apache non-native) are tested with identical assertions, improving test coverage and maintainability.

modules/kafka/kafka.go (4)

86-94: LGTM! Correct integration of image-based script selection.

The copyStarterScript call now receives the image parameter (line 88), enabling dynamic selection of the appropriate starter script via getStarterScriptContent(img).


132-157: LGTM! Clean integration of dynamic script selection.

The function signature now accepts the image parameter (line 132) and uses getStarterScriptContent(img) (line 150) to select the appropriate starter script content. The rest of the logic remains unchanged.


200-227: Verify the version validation logic change is intentional.

The validation logic now only checks Confluent images (line 210) using isConfluentinc(image). Apache images and custom images bypass version validation entirely (lines 210-215).

This aligns with the documentation stating "All Apache images support Kraft mode," but it means custom images based on Confluent that don't match the confluentinc/ prefix will also skip validation.

Confirm this behavior is intentional:

  • Apache images: Skip validation (assuming all versions support KRaft)
  • Custom images: Skip validation (may or may not support KRaft)
  • Only confluentinc/* images: Validate version >= 7.4.0

Consider whether custom Confluent-based images should also be validated or if the current logic is acceptable.


22-40: Based on my web search findings, the official Apache Kafka Dockerfile copies Docker scripts to /etc/kafka/docker/, which confirms the startup script path used in the code is correct. The Apache starter script's reference to /etc/kafka/docker/run aligns with the official image structure.

No actionable issues found. The Apache starter script path is valid.

The code correctly uses exec /etc/kafka/docker/run, which is the proper entrypoint for Apache Kafka official Docker images. The exec command is intentional for correct process management, and the KAFKA_ADVERTISED_LISTENERS format matches the Apache image requirements.

docs/modules/kafka.md (4)

7-10: LGTM! Clear introduction reflecting multi-image support.

The introduction now clearly states the module supports both Apache Kafka and Confluent images, accurately reflecting the code changes.


22-33: LGTM! Comprehensive examples covering all image variants.

The documentation now references three distinct examples (Apache Native, Apache non-native, Confluent), with a helpful note about the native container's performance benefits. This provides clear guidance for users choosing between image types.


60-62: LGTM! Clear guidance on KRaft mode requirements.

The warning appropriately distinguishes between Confluent images (minimum version 7.4.0 required) and Apache images (all versions support KRaft), aligning with the validation logic in validateKRaftVersion.


74-87: LGTM! Clear explanation of starter script selection.

The Init script section effectively documents the image-based script selection logic, showing how the module varies the starter script based on the image prefix. The code references help users understand the implementation.

@mabrarov
Copy link
Contributor

mabrarov commented Nov 8, 2025

Hi @strowk,

Just to complete my work with some milestone I opened #3488. Please feel free to discuss with maintainers what way to proceed - copy some parts of that PR (e.g. links to GitHub issues, test for graceful shutdown of Kafka) into this PR (you was the first 😄) or just complete with this PR... or maybe complete/merge #3488 instead of this PR.

Thank you for your help and work.

@strowk
Copy link
Author

strowk commented Nov 8, 2025

Hey @mdelapenya , I have made a lot of changes to this:

  • new stuff is all added into existing "kafka" module, "kafka_native" is removed
  • user just needs to give apache/kafka-native or apache/kafka image (those are all explained in docs)
  • I had to merge from main, due to conflicts, tell me if you'd rather I made another PR (contributing doc says that force push is a no-no).

@mabrarov , as requested this should work for "apache/kafka" as well as for "apache/kafka-native" , there are tests and examples to confirm.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6f75b2 and ad56cd2.

📒 Files selected for processing (2)
  • docs/modules/kafka.md (5 hunks)
  • modules/kafka/benchmark_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-18T08:24:27.479Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3254
File: .github/dependabot.yml:21-21
Timestamp: 2025-09-18T08:24:27.479Z
Learning: In the testcontainers-go repository, submodules like atlaslocal that are part of a parent module (e.g., mongodb) share the same go.mod file and should not have separate Dependabot entries. They are already monitored through the parent module's Dependabot configuration entry.

Applied to files:

  • docs/modules/kafka.md
📚 Learning: 2025-09-29T13:57:14.636Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3319
File: modules/arangodb/arangodb.go:46-57
Timestamp: 2025-09-29T13:57:14.636Z
Learning: In testcontainers-go ArangoDB module, the wait strategy combines port listening check with HTTP readiness check using wait.ForAll - both strategies are required and complementary, not redundant.

Applied to files:

  • docs/modules/kafka.md
🧬 Code graph analysis (1)
modules/kafka/benchmark_test.go (2)
log/logger.go (1)
  • Printf (47-49)
cleanup.go (1)
  • TerminateContainer (97-108)
🪛 LanguageTool
docs/modules/kafka.md

[style] ~71-~71: Using many exclamation marks might seem excessive (in this case: 9 exclamation marks for a text that’s 5976 characters long)
Context: ...ound(), "apache/kafka-native:4.0.1")`. !!! warning Module expects that the ima...

(EN_EXCESSIVE_EXCLAMATION)

🔇 Additional comments (5)
modules/kafka/benchmark_test.go (1)

28-38: LGTM! Good coverage of different Kafka image flavors.

The three benchmark functions provide good coverage for measuring start/stop performance across Confluent, Apache, and Apache Native images, which aligns well with the PR's objectives and the comparison table in the documentation.

docs/modules/kafka.md (4)

22-47: Excellent documentation of the three Kafka image options.

The usage examples and comparison table provide clear guidance on the trade-offs between Apache Native, Apache, and Confluent images. The size/performance comparison and the note about missing CLI tools in apache/kafka-native are particularly helpful for users making an informed choice.


85-110: Clear explanation of starter script selection and override options.

The documentation clearly explains the automatic detection logic (with sensible defaults for backward compatibility) and provides appropriate warnings about custom scripts. The code examples effectively demonstrate the override options.


147-157: Useful addition documenting the localhost listener feature.

This new section effectively explains how to use the localhost listener for custom wait strategies and CLI commands. The note about incompatibility with apache/kafka-native images is important and consistent with earlier documentation.


71-71: Static analysis false positive - ignore LanguageTool hint.

The LanguageTool hint about excessive exclamation marks is a false positive. It's incorrectly counting the markdown admonition syntax (!!! warning) as punctuation rather than recognizing it as mkdocs-material directive syntax.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
docs/modules/kafka.md (2)

85-98: Verify starter script selection logic is complete.

The documentation describes the starter script selection logic (lines 85-98), but doesn't mention whether the default behavior is to auto-detect based on image prefix or if it requires explicit options. Clarify whether:

  1. Auto-detection happens when using Run() without WithApacheFlavor/WithConfluentFlavor?
  2. What happens if detection fails to match (e.g., custom registry image)?

The text states "otherwise: use Confluent starter script (for backward compatibility)" at line 93, which addresses the third case. This appears correct, but may benefit from a small example showing the auto-detection in action.


147-157: Clarify localhost listener availability across image types.

Line 149 states the Kafka container "would by default be configured with localhost:9095" but doesn't indicate whether this applies to all three supported image types (Apache Native, Apache, Confluent) or only some. Given that line 157 notes apache/kafka-native lacks CLI tools, it's unclear if localhost:9095 is available on that image or if the listener exists but cannot be used for CLI commands.

Recommend: Clarify whether localhost:9095 is configured for all images, and update the example or note to make the limitation(s) explicit per image type.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad56cd2 and fb876de.

📒 Files selected for processing (2)
  • docs/modules/kafka.md (5 hunks)
  • modules/kafka/benchmark_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • modules/kafka/benchmark_test.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-18T08:24:27.479Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3254
File: .github/dependabot.yml:21-21
Timestamp: 2025-09-18T08:24:27.479Z
Learning: In the testcontainers-go repository, submodules like atlaslocal that are part of a parent module (e.g., mongodb) share the same go.mod file and should not have separate Dependabot entries. They are already monitored through the parent module's Dependabot configuration entry.

Applied to files:

  • docs/modules/kafka.md
📚 Learning: 2025-09-29T13:57:14.636Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3319
File: modules/arangodb/arangodb.go:46-57
Timestamp: 2025-09-29T13:57:14.636Z
Learning: In testcontainers-go ArangoDB module, the wait strategy combines port listening check with HTTP readiness check using wait.ForAll - both strategies are required and complementary, not redundant.

Applied to files:

  • docs/modules/kafka.md
🪛 LanguageTool
docs/modules/kafka.md

[style] ~71-~71: Using many exclamation marks might seem excessive (in this case: 9 exclamation marks for a text that’s 6061 characters long)
Context: ...ound(), "apache/kafka-native:4.0.1")`. !!! warning Module expects that the ima...

(EN_EXCESSIVE_EXCLAMATION)

🔇 Additional comments (3)
docs/modules/kafka.md (3)

111-129: Verify all new options are documented.

The PR summary and AI-generated summary mention four new RunOption-based configuration options: WithApacheFlavor, WithConfluentFlavor, WithStarterScript, and WithClusterID. The documentation covers the first three (lines 115-129), but WithClusterID is not documented in this file. Either:

  1. Update the documentation to include WithClusterID usage and examples, or
  2. Confirm that WithClusterID is not part of the public API and should not be documented.

1-157: Overall documentation structure and quality look solid.

The updated documentation successfully covers the addition of Apache Kafka image support alongside the existing Confluent support. Key strengths:

  • Examples: Three concrete usage patterns covering all three image types (lines 22-31)
  • Guidance: Excellent comparison table (lines 39-43) with practical information about trade-offs (size, startup time, CLI tools, graceful shutdown)
  • API clarity: Run function signature and image selection logic are well-documented
  • Options: New flavor and starter script options are documented with examples
  • Transparency: Important caveats about CLI tools and graceful shutdown are highlighted

The documentation aligns well with the PR's goal of supporting multiple image families while preserving backward compatibility.


22-31: All codeinclude block references verified and correctly named.

All 10 code blocks referenced in the documentation have been confirmed to exist in the source files with proper markers:

  • examples_test.go: runKafkaContainerApacheNative, runKafkaContainerApacheNotNative, runKafkaContainerConfluentinc, runKafkaContainerWithApacheFlavor, runKafkaContainerWithConfluentFlavor, runKafkaContainerAndUseLocalhostListener
  • kafka.go: starterScriptApache, starterScriptConfluentinc, envVars
  • kafka_test.go: getBrokers

All blocks use the correct marker format (// blockName { ... // }) that the codeinclude plugin expects.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
docs/modules/kafka.md (2)

157-167: Clarify why localhost listener doesn't work with apache/kafka-native.

Line 167 states the localhost listener example "will not work with apache/kafka-native images, as they do not include CLI tools." This is accurate but could be strengthened by briefly explaining why (users cannot run kafka-topics.sh commands inside the container). Consider mentioning that apache/kafka (non-native) does include CLI tools and thus supports this pattern.

Consider revising lines 157-167 to:

Kafka container would by default be configured with `localhost:9095` as one of advertised listeners. This can be used when you need to run CLI commands inside the container, for example with custom wait strategies or to prepare test data.

Here is an example that uses custom wait strategy that checks if listing topics works:

<!--codeinclude-->
[Custom wait strategy](../../modules/kafka/examples_test.go) inside_block:runKafkaContainerAndUseLocalhostListener
<!--/codeinclude-->

Note: this will not work with `apache/kafka-native` images, as they do not include CLI tools like `kafka-topics.sh`. However, it works with `apache/kafka` and `confluentinc/confluent-local` images.

73-82: Minor: Consider softening absolute claims about Apache image compatibility.

While line 81 "All Apache images support Kraft mode." is likely accurate for current versions, consider whether future-proofing the documentation with language like "All currently maintained Apache Kafka images support Kraft mode" would be better for long-term clarity. This matches the pattern used elsewhere in documentation.

This is a minor stylistic suggestion; the current wording is acceptable if you're confident it will remain accurate.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fb876de and f83d07d.

📒 Files selected for processing (2)
  • docs/modules/kafka.md (5 hunks)
  • modules/kafka/benchmark_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • modules/kafka/benchmark_test.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-18T08:24:27.479Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3254
File: .github/dependabot.yml:21-21
Timestamp: 2025-09-18T08:24:27.479Z
Learning: In the testcontainers-go repository, submodules like atlaslocal that are part of a parent module (e.g., mongodb) share the same go.mod file and should not have separate Dependabot entries. They are already monitored through the parent module's Dependabot configuration entry.

Applied to files:

  • docs/modules/kafka.md
📚 Learning: 2025-09-29T13:57:14.636Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3319
File: modules/arangodb/arangodb.go:46-57
Timestamp: 2025-09-29T13:57:14.636Z
Learning: In testcontainers-go ArangoDB module, the wait strategy combines port listening check with HTTP readiness check using wait.ForAll - both strategies are required and complementary, not redundant.

Applied to files:

  • docs/modules/kafka.md
🔇 Additional comments (1)
docs/modules/kafka.md (1)

105-115: Code block references are valid and all markers exist.

The documentation references three code blocks using the inside_block: format:

  • starterScriptApache in kafka.go (line 34) ✓
  • starterScriptConfluentinc in kafka.go (line 22) ✓
  • runKafkaContainerWithApacheFlavor in examples_test.go (line 114) ✓

All blocks are properly marked with the codebase's marker format (// blockName { and // }), so the documentation include references will resolve correctly.

@strowk strowk requested review from mdelapenya and stevenh November 16, 2025 05:39
dockerIoPrefix = "docker.io/"
)

func isApache(image string) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: do we need both? If not each use would usually be a switch not an if which I saw above.

Alternatively it could be a imageType call returning an enum type

type flavour int
const (
    unknownFlavour flavour = iota
    apacheFlavour 
    confluentFlavour
    customFlavour
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: align filename with behaviour of the methods, type, flavour or other depending on the outcome of the other comments.

apacheStarterScriptContent = `#!/bin/bash
export KAFKA_ADVERTISED_LISTENERS=%s,BROKER://%s:9092
echo Starting Apache Kafka
exec /etc/kafka/docker/run`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mabrarov to confirm my understanding you're suggesting using the detail from inspect to identify the location of binary to exec, so that if that changed in the future it would remain compatible?

Copy link
Member

@mdelapenya mdelapenya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR looks good to me, and it comes with a lot of work, thank you so much for dedicating your time for this. We'll make sure to make it into the project the soonest 🙇

Let's address the existing review comments, and let's merge it on green CI.

[Get Kafka brokers](../../modules/kafka/kafka_test.go) inside_block:getBrokers
<!--/codeinclude-->
## Localhost listener
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Localhost listener
#### Localhost listener

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I've applied this without looking, but results do not seem correct to me..

This looks like "Localhost listener" section is under "Container Methods", but it does not actually describe container method, it just tells that there is a configuration that allows to do particular things from inside of container (via some options, but not via container methods).

image

Did you mean to put it under "Module Reference" maybe? I.e with three # symbols?

Co-authored-by: Manuel de la Peña <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f83d07d and 5f5e8fb.

📒 Files selected for processing (1)
  • docs/modules/kafka.md (5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-18T08:24:27.479Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3254
File: .github/dependabot.yml:21-21
Timestamp: 2025-09-18T08:24:27.479Z
Learning: In the testcontainers-go repository, submodules like atlaslocal that are part of a parent module (e.g., mongodb) share the same go.mod file and should not have separate Dependabot entries. They are already monitored through the parent module's Dependabot configuration entry.

Applied to files:

  • docs/modules/kafka.md
📚 Learning: 2025-09-29T13:57:14.636Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3319
File: modules/arangodb/arangodb.go:46-57
Timestamp: 2025-09-29T13:57:14.636Z
Learning: In testcontainers-go ArangoDB module, the wait strategy combines port listening check with HTTP readiness check using wait.ForAll - both strategies are required and complementary, not redundant.

Applied to files:

  • docs/modules/kafka.md
🪛 LanguageTool
docs/modules/kafka.md

[style] ~77-~77: Using many exclamation marks might seem excessive (in this case: 9 exclamation marks for a text that’s 6500 characters long)
Context: ...ound(), "apache/kafka-native:4.0.1")`. !!! warning Module expects that the ima...

(EN_EXCESSIVE_EXCLAMATION)

🔇 Additional comments (4)
docs/modules/kafka.md (4)

19-39: Content is accurate and well-structured.

The Apache Kafka images section correctly documents the three flavors, their trade-offs (size, startup time, CLI tools, graceful shutdown), and provides clear guidance to prefer Apache images. The comparison table and graceful shutdown callout (addressing issue #2206) are helpful for users.


155-166: Localhost listener documentation is clear and appropriately caveat-ed.

The explanation of the localhost listener feature (localhost:9095) for CLI commands inside the container is helpful. The caveat about incompatibility with native images (due to missing CLI tools) is important and well-placed at the end.


119-137: All example code blocks are properly defined and correctly referenced.

Verification confirms that all three code blocks referenced in the documentation exist and are properly marked in modules/kafka/examples_test.go:

  • runKafkaContainerWithApacheFlavor (line 114)
  • runKafkaContainerWithConfluentFlavor (line 154)
  • runKafkaContainerAndUseLocalhostListener (line 197)

All documentation references are valid.


42-52: All three example code blocks are properly defined and marked.

Verification confirms that modules/kafka/examples_test.go contains all three referenced blocks:

  • runKafkaContainerConfluentinc (lines 15–31)
  • runKafkaContainerApacheNative (lines 48–64)
  • runKafkaContainerApacheNotNative (lines 81–97)

Each block is properly marked with comment-style markers (// blockname { and // }), matching the inside_block: references in the documentation.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
modules/kafka/kafka_test.go (1)

174-212: Consider removing StopTimeout(0) for consistency.

The test correctly validates that the localhost listener (port 9095) is accessible using an exec-based wait strategy. However, line 208 uses testcontainers.CleanupContainer(t, kafkaContainer, testcontainers.StopTimeout(0)), which immediately stops the container without waiting. Other tests in this file (e.g., lines 25, 153) use CleanupContainer without an explicit stop timeout, allowing the default graceful shutdown.

For consistency and maintainability, consider using the default cleanup behavior unless there's a specific reason to force immediate shutdown.

Apply this diff to align with other tests:

-			testcontainers.CleanupContainer(t, kafkaContainer, testcontainers.StopTimeout(0))
+			testcontainers.CleanupContainer(t, kafkaContainer)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c6a2b1d and 34242df.

📒 Files selected for processing (3)
  • modules/kafka/benchmark_test.go (1 hunks)
  • modules/kafka/kafka_test.go (3 hunks)
  • modules/kafka/options.go (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • modules/kafka/benchmark_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • modules/kafka/options.go
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-18T08:24:27.479Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3254
File: .github/dependabot.yml:21-21
Timestamp: 2025-09-18T08:24:27.479Z
Learning: In the testcontainers-go repository, submodules like atlaslocal that are part of a parent module (e.g., mongodb) share the same go.mod file and should not have separate Dependabot entries. They are already monitored through the parent module's Dependabot configuration entry.

Applied to files:

  • modules/kafka/kafka_test.go
📚 Learning: 2025-09-29T13:57:14.636Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3319
File: modules/arangodb/arangodb.go:46-57
Timestamp: 2025-09-29T13:57:14.636Z
Learning: In testcontainers-go ArangoDB module, the wait strategy combines port listening check with HTTP readiness check using wait.ForAll - both strategies are required and complementary, not redundant.

Applied to files:

  • modules/kafka/kafka_test.go
🧬 Code graph analysis (1)
modules/kafka/kafka_test.go (6)
modules/kafka/kafka.go (1)
  • Run (55-140)
modules/kafka/options.go (4)
  • WithClusterID (54-58)
  • WithApacheFlavor (66-75)
  • WithConfluentFlavor (81-90)
  • WithStarterScript (30-39)
testing.go (1)
  • CleanupContainer (91-97)
options.go (1)
  • WithWaitStrategy (366-368)
wait/exec.go (1)
  • NewExecStrategy (30-37)
cleanup.go (1)
  • StopTimeout (76-80)
🔇 Additional comments (4)
modules/kafka/kafka_test.go (4)

17-71: LGTM!

The parameterized testFor helper cleanly extracts the core Kafka test logic and correctly uses t.Helper() for proper test failure attribution. The test flow (setup → broker interaction → produce/consume → assertions) is well-structured.


73-109: LGTM!

The table-driven approach provides excellent coverage across Confluent and Apache image variants (native and non-native, multiple versions). All test case names are unique and descriptive, addressing the earlier duplicate-name issue.


135-172: LGTM!

The graceful shutdown test correctly validates that Apache Kafka images (which use exec to replace the shell) handle SIGTERM properly. The test captures and checks the Stop() error and uses appropriate timeouts. Testing only Apache images is intentional, as this is where the signal-handling improvement applies.


214-234: LGTM!

The test correctly validates that specifying conflicting flavor options (WithApacheFlavor, WithConfluentFlavor, WithStarterScript) returns an error. The three test scenarios comprehensively cover all conflict cases, ensuring the mutual-exclusivity constraint is enforced at the API level.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
modules/kafka/version_test.go (1)

9-115: Consider adding edge case tests for defensive coverage.

The current tests comprehensively cover the documented prefix-matching behavior. To make the test suite more robust, consider adding test cases for edge conditions:

  • Empty string image name
  • Malformed image names (e.g., no slash, only tag)
  • Alternative registry prefixes (e.g., "registry.example.com/apache/kafka", "localhost:5000/confluentinc/cp-kafka")

These would verify that the detection logic handles unexpected inputs gracefully.

Example additional test cases:

{
    name:  "empty string",
    image: "",
    want:  false,
},
{
    name:  "malformed - no slash",
    image: "kafka",
    want:  false,
},
{
    name:  "custom registry with apache path",
    image: "registry.example.com/apache/kafka:latest",
    want:  false, // or true, depending on intended behavior
},
modules/kafka/options_test.go (1)

56-65: Consider testing error path for WithStarterScript.

The test verifies the happy path where WithStarterScript successfully overrides the starter script content. However, it doesn't test the error case where WithStarterScript is called when flavorWasSet is already true, which should return errFlavorAlreadySet according to the implementation in options.go. While the current coverage is adequate for basic functionality, adding an error-path test would improve robustness.

Example:

func TestWithStarterScript_flavorAlreadySet(t *testing.T) {
	opts := &runOptions{
		image:        "apache/kafka-native:latest",
		flavorWasSet: true,
	}
	err := WithStarterScript("custom")(opts)
	require.Error(t, err)
	require.Equal(t, errFlavorAlreadySet, err)
}
docs/modules/kafka.md (2)

159-171: Add a clarification note about CLI tools for apache/kafka-native in the Localhost listener section.

Line 171 notes that the localhost listener "will not work with apache/kafka-native images, as they do not include CLI tools." However, this note is somewhat cryptic—it should clarify that the localhost listener itself works, but executing CLI commands within the container (like kafka-topics.sh for custom wait strategies) will fail due to missing tools.

Consider rephrasing line 171 to:

Note: CLI commands (e.g., kafka-topics.sh) used in custom wait strategies will not work with apache/kafka-native images, as they do not include CLI tools.


27-28: Recommendation wording is strong; clarify that graceful shutdown is a known limitation.

Line 27 strongly recommends preferring Apache Kafka over Confluent due to the graceful shutdown issue. While this aligns with the PR objectives and prior discussion, the wording could benefit from a slight softening to indicate this is a known limitation rather than suggesting Confluent is unsuitable. The current wording is acceptable but consider whether "Apache Kafka images are recommended due to improved graceful shutdown support" might better balance the messaging.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34242df and 4627d1b.

📒 Files selected for processing (3)
  • docs/modules/kafka.md (5 hunks)
  • modules/kafka/options_test.go (1 hunks)
  • modules/kafka/version_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-18T08:24:27.479Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3254
File: .github/dependabot.yml:21-21
Timestamp: 2025-09-18T08:24:27.479Z
Learning: In the testcontainers-go repository, submodules like atlaslocal that are part of a parent module (e.g., mongodb) share the same go.mod file and should not have separate Dependabot entries. They are already monitored through the parent module's Dependabot configuration entry.

Applied to files:

  • docs/modules/kafka.md
📚 Learning: 2025-09-29T13:57:14.636Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3319
File: modules/arangodb/arangodb.go:46-57
Timestamp: 2025-09-29T13:57:14.636Z
Learning: In testcontainers-go ArangoDB module, the wait strategy combines port listening check with HTTP readiness check using wait.ForAll - both strategies are required and complementary, not redundant.

Applied to files:

  • docs/modules/kafka.md
🧬 Code graph analysis (1)
modules/kafka/options_test.go (2)
modules/kafka/kafka.go (1)
  • Run (55-140)
modules/kafka/options.go (1)
  • WithStarterScript (30-39)
🔇 Additional comments (5)
modules/kafka/version_test.go (2)

9-71: LGTM! Comprehensive test coverage for Apache image detection.

The test thoroughly covers both apache/kafka-native and apache/kafka images with various tag formats and the docker.io prefix, plus negative cases. The use of require.Equal is idiomatic and provides clear failure messages.


73-115: LGTM! Solid test coverage for Confluent image detection.

The test covers confluentinc/cp-kafka images with various tags and the docker.io prefix, plus negative cases. The structure mirrors Test_isApache and maintains consistency across the test file.

modules/kafka/options_test.go (1)

31-54: LGTM: Comprehensive Confluent and fallback coverage.

The test cases for Confluent images and the custom image fallback are well-structured and align with the backward compatibility goal mentioned in the PR objectives.

docs/modules/kafka.md (2)

31-35: Verify benchmark timings and image sizes are accurate and current.

The comparison table at lines 31–35 includes specific Docker image sizes and startup timings. Per the PR objectives, these are benchmarked values (e.g., Apache Native ~3.693s, Apache ~5.65s, Confluent ~14.77s in testing). However, Docker image sizes and performance can vary with image tags and environments. Ensure that:

  1. Sizes and timings match the specific image tags being recommended (e.g., apache/kafka:4.0.1, apache/kafka-native:4.0.1, confluentinc/confluent-local:7.5.0).
  2. These numbers remain reasonably accurate as images are updated.
  3. Consider adding a note that timings are representative and may vary by environment.

43-52: Code block references in kafka.md are correct and properly marked in examples_test.go.

Verification confirms all three block identifiers referenced in kafka.md (lines 43, 47, 51) are correctly marked in examples_test.go using comment-based markers:

  • runKafkaContainerApacheNative — marked at line 48
  • runKafkaContainerApacheNotNative — marked at line 81
  • runKafkaContainerConfluentinc — marked at line 15

All block names match exactly with no spelling inconsistencies or case sensitivity issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New functionality or new behaviors on the existing one

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants