How do I avoid 'port collision' when using docker?

Stop binding to local ports and let docker-compose pick an ephemeral port for you. In your case, your application can get to the default ports without any help. If you are following the 12 Factor App approach, then use environment variables like in the following snippet.

version: "3.3"
services:
  app:
    restart: always
    build: .
    volumes:
      - ./:/app
    ports:
      - 3000  # will be bound to an ephemeral port
    environment:
      MONGODB_URL: mongodb://mongo/db  # can reach port 27017 without help
  mongo:
    image: mongo
    ports:
      - 27017

This is the primary reason to make your applications configurable via environment variables or command-line flags.

You can use docker-compose port to get the ephemeral port if you need to access a docker application from the host. I routinely use a shell function like the following:

get_exposed_port() {  # SERVICE PORT
    docker-compose port $1 $2 | cut -d: -f2
}

Another option available as of version 3 of docker compose files is to specify a different port exposed on the host via environment variables.

So one way to do it might be like this:

version: "3.3"
services:
  mysql:
    container_name: mysql
    image: mysql
    ports:
      - "${MYSQL_PORT_NUMBER:-3306}:3306"

Then, if the environment variable is defined, that value will be used. Otherwise, the default 3306 will be used.

A second feature of version 3 docker compose files that they will read environment variables from a .env file if one exists. The .env file must be in the directory where you run docker-compose from.

Finally, to debug all of this, one can use docker-compose config to emit the variable expanded docker compose file. Doing so with a .env that looks like this:

MYSQL_PORT_NUMBER=3307

gives this result:

$ docker-compose -f mysql-port-conflict.yaml config
services:
  mysql:
    container_name: mysql
    image: mysql
    ports:
    - published: 3307
      target: 3306
version: '3.3'

which shows that MySQL will be made available on port 3307 of the host. Of course, any apps that want to connect to MySQL will also need to know about ${MYSQL_PORT_NUMBER}.

HTH

Tags:

Docker

Mysql

Port