Search code examples
pythonbashdockershelldockerfile

Assign ports to docker dynamically avoiding the ones used by running containers


Trying to find a creative solution to assign an unused host:container port while submitting docker run from a range of possible ports. I am very close to figuring it out and trying to see if below approach works smartly. So far, I have decided to do following:

  1. docker inspect and find ports already used by running containers .e.g.
    $ docker ps -a --format "{{.Ports}}"
    0.0.0.0:8780->8080/tcp
    0.0.0.0:4022->4022/tcp, 0.0.0.0:5022->5022/tcp
    0.0.0.0:4013->4013/tcp, 0.0.0.0:5013->5013/tcp, 0.0.0.0:6013->6013/tcp
  1. From above I was able to extract last 2 digits(UUID) of all ports ( since I will be mapping the same port )
$ docker ps -a --format "{{.Ports}}" | sed -re 's/^.*->[0-9][0-9]([0-9]+)\/tcp.*$/\1/'

80
13
  1. My docker run will have port mapping as below:
-p 40${UUID}:40${UUID} \
-p 50${UUID}:50${UUID} \
-p 60${UUID}:60${UUID} \
  1. Now I want to generate the UUID (in the range of 00-50) that do not exist in above output so that every time my script runs it assigns an unused port range to the container on the fly.

Is it possible for a bash one-liner to achieve what I am trying to achieve? python approach will also work. If there is any better way to achieve above, Im keen to learn as well. Expected output for UUID below will return 2 digit value between 0-50 but not 13,22,80.

UUID=`docker ps -a --format "{{.Ports}}" | sed -re 's/^.*->[0-9][0-9]([0-9]+)\/tcp.*$/\1/' | <additional parsing logic>`

Much thanks in advance. Interesting that docker does not have a way to dynamically manage port assignments based on range so have to go this path.

UPDATE: The list of ports on host and container need to configured in the above way due to firewall limitations. On host, only specific range is opened for tcp. While, on container the same ports are assigned to specific conf values. Hence both host/container ports cannot be dynamically assigned without setting on environment.


Solution

  • This should produce the expected result :

    UUID=$(docker ps -a --format "{{.Ports}}" | python -c 'import re,sys; last2 = set(int(m.group(2)) for m in (re.match(r"(\d+\.){3}\d+:\d*(\d{2})", line) for line in sys.stdin) if m); print(next((str(i).zfill(2) for i in range(51) if i not in last2), ""))')
    echo $UUID