Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Eureka despite having random external port of docker containers

I am writing an application that is composed of a few spring boot based microservices with a zuul based reverse proxy in the front-

It works when I start the services on my machine, but for server rollout I'd like to use docker for the services, but this seems not to be possible right now.

Normally you would have a fixed "internal" port and randomized ports at the outside of the container. But the app in the container doesn't know the outside port (and IP).

The Netflix tools match what I would want to write an efficient microservice architecture and conceptually I really like docker. As far as I can see it would be very troublesome to start the container, gather the outside port on the host and pass it to the app, because you can't simply change the port after the app is started.

Is there any way to use eureka with docker based clients?

[Update] I guess I did a poor job explaining the problem. So maybe this clarifies it a bit more:

The eureka server itself can run in docker, as I have only one and the outside port doesn't matter. I can use the link feature to access it from the clients.

The problem is the URL that the clients register themselves with. This is for example https://localhost:8080/ but due to dynamic port assignment it is really only accessible via https://localhost:54321/

So eureka will return the wrong URL for the services.

UPDATE I have updated my answer below, so have a look there.

like image 644
Patrick Cornelissen Avatar asked Apr 30 '15 15:04

Patrick Cornelissen


People also ask

Do Docker containers have their own ports?

By default, when you create or run a container using docker create or docker run , it does not publish any of its ports to the outside world. To make a port available to services outside of Docker, or to Docker containers which are not connected to the container's network, use the --publish or -p flag.

Can Docker containers use the same port?

Surprisingly or not, neither Docker nor Podman support exposing multiple containers on the same host's port right out of the box. Example: docker-compose failing scenario with "Service specifies a port on the host. If multiple containers for this service are created on a single host, the port will clash."

Should I expose Docker port?

Some standard ports are 80 for webservers, 443 for webservers running over encryption (TLS/SSL), and 25 for mail. So when you want to allow applications to connect to your container, you need to expose one or more ports to the outside world.


2 Answers

I have found a solution myself, which is maybe not the best solution, but it fits for me...

When you start docker with "--net=host" (host networking), then you use the hosts network stack directly. Then I just use 0 as port for spring-boot and spring randomizes the port for me and as it's using the hosts networking stack there is no translation to a different port (and IP).

There are some drawbacks though:

  • When you use host networking you can't use the link-feature for these containers as link source or target.
  • Using the hosts network stack leads to less encapsulation of the instance, which maybe a problem depending on your project.

I hope it helps

A lot of time has passed and I think I should elaborate this a little bit further:

  1. If you use docker to host your spring application, just don't use a random port! Use a fixed port because every container gets his own IP anyway so every service can use the same port. This makes life a lot easier.

  2. If you have a public facing service then you would use a fixed port anyway.

  3. For local starts via maven or for example the command line have a dedicated profile that uses randomized ports so you don't have conflicts (but be aware that there are or have been a few bugs surrounding random ports and service registration)

  4. if for whatever reason you want to or need to use host networking you can use randomized ports of course, but most of the time you shouldn't!

like image 142
Patrick Cornelissen Avatar answered Oct 12 '22 10:10

Patrick Cornelissen


You can set up a directory for each docker instance and share it between the host and the instance and then write the port and IP address to a file in that directory.

$ instanceName=$(generate random instance name)
$ dirName=/var/lib/docker/metadata/$instanceName
$ mkdir -p $dirName
$ docker run -name $instanceName -v ${dirName}:/mnt/metadata ...
$ echo $(get port number and host IP) > ${dirName}/external-address

Then you just read /mnt/metadata/external-address from your application and use that information with Eureka.

like image 43
Raniz Avatar answered Oct 12 '22 10:10

Raniz