After the container is deleted, why is the port mapped to the container by the host not recycled immediately?

  docker, question

Map some ports when creating a new container, as follows:

docker run -d -p 22 -p 80 ubuntu /usr/sbin/sshd -D

The host will automatically map two ports to containers 22 and 80, such as:
0.0.0.0:49155->22/tcp, 0.0.0.0:49156->80/tcp
When the container is stopped and deleted, the host ports 49155 and 49156 should be released for use by the new container. However, when the new container mapping port is actually created at this time, it is found that the two ports are not used, but the system automatically allocates the new ports after the two ports, such as 49157 …
Only ports that were previously empty after the docker service was restarted will be allocated. This is the case for experiments on three different docker hosts. It seems that it is not my configuration problem. I wonder what your environment is like. Solve!

By looking at the source codedocker / runtime / networkdriver / portallocator / portallocator.goIt can be known that
Docker’s dynamic range port is 49153-65535

const (
 BeginPortRange = 49153
 EndPortRange   = 65535
 )

The ports are allocated in ascending order, and after reaching the maximum value, the cycle starts from the beginning.

func nextPort(proto string) int {
 c := currentDynamicPort[proto] + 1
 if c > EndPortRange {
 c = BeginPortRange
 }
 currentDynamicPort[proto] = c
 return c
 }

When the container is destroyed, the port is released

func ReleasePort(ip net.IP, proto string, port int) error {
 .......
 
 allocated := defaultAllocatedPorts[proto]
 allocated.Remove(port)
 
 .......
 }

findNextPortMethods FromnexPortThe method returns a value that has not been used. If it is not found in a circle, it is thrownErrAllPortsAllocatedAbnormal.

func findNextPort(proto string, allocated *collections.OrderedIntSet) (int, error) {
 port := nextPort(proto)
 startSearchPort := port
 for allocated.Exists(port) {
 port = nextPort(proto)
 if startSearchPort == port {
 return 0, ErrAllPortsAllocated
 }
 }
 return port, nil
 }

To sum up, the port has actually been released, but it will not be reused immediately unless the port resources are very tight.
So what you see is the normal situation, you don’t have to worry about it (provided you need to use v0.10 or above).
This feature of recycling ports is added to v0.10. If lower than this version, port number toEndPortRangeAfter that, you can only restart Docker.

Reference:https://github.com/dotcloud/docker/pull/4949