Hello all,
the networking page is quite barebone.
Can you please improve it to include instructions on how to start containers with a fixed port using host networking mode?
So far to make it work I had to do exactly this:
````
new FixedHostPortGenericContainer<>(
"myimage")
.withNetworkMode("host")
.withFixedExposedPort(port, port);
container.setPortBindings(Arrays.asList(port + ":" + port));
````
And port is a random free HOST port obtained with Java logic beforehand.
Any other approach will generate some error.
If this is indeed the intended approach, could you please update the documentation as it is not immediately clear this is the way to go.
Also, why would this approach be needed, for example: start a Confluent Kafka image.
As part of the Kafka configuration (environment parameter) one must specify the hostname:port for clients to connect to. This means the port must be decided before starting the container. If it is chosen properly at random, there is no harm with this approach at all.
Thanks and cheers
Hi @steghio,
Fixed ports is something we do not want to advertise, hence no docs.
FYI there is a module for Confluent Kafka already:
https://github.com/testcontainers/testcontainers-java/tree/master/modules/kafka
This means the port must be decided before starting the container
This does not mean however that the port must be fixed. For instance in Kafka, we obtain the assigned port and only then start the process inside the container:
https://github.com/testcontainers/testcontainers-java/blob/ca8a35dc5ccf31142919c5fb5635c664d4f89302/modules/kafka/src/main/java/org/testcontainers/containers/KafkaContainer.java#L83-L105
Even more advanced cases like the Couchbase one can be implemented without using the fixed ports:
https://github.com/testcontainers/testcontainers-java/blob/ca8a35dc5ccf31142919c5fb5635c664d4f89302/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java#L133-L141
Hello,
yes I am aware of the specialized containers you provide and they are a cool thing. I also agree fixed host ports are a bad practice.
I gave you the short example before and of course you want me to do the right thing and avoid this, I agree, so here is the long version.
In my workplace some things are set in stone and cannot be changed. For us, docker images are provided as custom images with a completely different way of configuring and starting them. Should this change? Yes. Can it change? Not in a million years.
My specific case is the Confluent image is configurable only by mounting a properties file in a specific container location. The property file contains the listeners and advertised.listeners values so the port has to be known BEFORE the container is started.
Additionally, the container startup command is a forced script that only allows us to specify start and a value among kafka, zookeeper and schema-registry.
Invoking container.start() will run whatever command I put in withCommand, BUT if I put anything else than start kafka for example, I will get an error, decided by whoever gave me the image.
So clearly I need a workaround for this issue that is 100% internal to my company. I am using a GenericContainer with a fixed host port, which I choose at random (Java socket to find a free port) BEFORE passing it as configuration, then I generate the file, tell testcontainers to mount it on the container and finally start it. This is an easy solution to the problem and works ok. I am happy.
Since the container start command is fixed for me, if I start the container and then copy the file on it later, it fails as Kafka already started using a default template configuration because my file is missing. The only time I can put it there is in the mount command before the startup command is invoked.
I could maybe create my own container definition and such, but with those 3 lines I solved my problem, it just took a bit to figure out I needed those 3 lines.
Now, we all agree fixed port is dangerous etc.
Sometimes life gives us lemons, please do not give me more lemons too, I have enough lemonade already.
For others in a similar scenarios this might be helpful. You could place a red flashing banner on it saying it is bad and we should feel bad, but still help us since it is a valid configuration, simply not recommended.
Thank you and have a nice day
Thanks for the answer! I would like to iterate over it to give you a different PoV on the problem:
Invoking container.start() will run whatever command I put in withCommand, BUT if I put anything else than start kafka for example, I will get an error, decided by whoever gave me the image.
You can override both command and entrypoint, so that you control the command that will be executed in the container. You just need to then call the original entry point and the command.
So far, we haven't discovered an image that cannot be used with random ports, just sometimes you need to overcome some of their limitations.
Now, on this one:
with a fixed host port, which I choose at random (Java socket to find a free port)
When you run docker-in-docker, or when your Docker daemon is deployed on some other machine (remote Docker setup), this solution may not work reliably, because you will detect a free port on your machine, while asking to expose it on some other host that may not have it available (not to mention the race conditions).
And this is one of the most dangerous problems you may have - when it works sometimes, but other times it doesn't, due to random. Russian Roulette at its best :)
please do not give me more lemons too
The whole idea of Testcontainers is to give you a tasty lemonade, and we (Testcontainers' developers) deal with the lemons (and knifes, and many other things) for you :)
You could place a red flashing banner on it saying it is bad and we should feel bad, but still help us since it is a valid configuration
The problem is that it is not really a valid configuration, not always.
We do not prevent using it (although we could, by checking the port mappings before starting the container... hmmm =P), but we do not want to make any effort making it easier to use something that we think is dangerous.
We do provide other means for that, and I even planned to implement some sort of a helper for running NAT-unfriendly containers like Kafka, Couchbase and others. That's the direction we took and would like to follow.
P.S. I am happy to help you in case you need some guidance on how to do this with your custom container, just ping me in Slack
You can override both command and entrypoint, so that you control the command that will be executed in the container. You just need to then call the original entry point and the command.
This is the answer. I wish I found it before :)
Yes I am not running docker in docker, but I see your point and I agree using fixed port is not the best, I was unaware of the workaround you mentioned.
I will try with it then so that I can start the container, find the random port it got assigned, create the file, put it in the container and finally start the application inside it and my issue would be solved.
Cool, it was easier than expected, many thanks for the lemonade
I am glad that it works for you! :)
The pattern is not rare and I created https://github.com/testcontainers/testcontainers-java/issues/1940 to keep track of the progress in case you want to "subscribe" on it.
It may not be easy to make it fully generic, but at least we can reuse some bits from Kafka and Couchbase
Most helpful comment
This is the answer. I wish I found it before :)
Yes I am not running docker in docker, but I see your point and I agree using fixed port is not the best, I was unaware of the workaround you mentioned.
I will try with it then so that I can start the container, find the random port it got assigned, create the file, put it in the container and finally start the application inside it and my issue would be solved.
Cool, it was easier than expected, many thanks for the lemonade