Having trouble parameterizing a network

We are setting up an environment in which multiple developers need to develop and test their applications independently, where an application is a set of containers communicating with each other on an internal network. I had thought to do this by parameterizing the network name:

networks:
  mynet:
    driver: bridge
    name: ${NETWORK_NAME}

This works fine for a single application:

$ docker compose --env-file n1.env up

(where n1.env sets NETWORK_NAME). If I run try to run two instances of the application (using different .env files with unique network names) I get a “port is already allocated” error.

Any ideas? Here’s the complete docker-compose file (I’m a new user and am not permitted to upload attachments):

name: sr-${VERSION?Set the variables}

services:
  sender:
    image: sender:${VERSION}
    pull_policy: build
    container_name: cnps-${VERSION}
    build:
      context: sender
      args:
        version: ${VERSION}
        message: ${MESSAGE}
        receiver: reader-${VERSION}
    networks:
      - mynet

  reader:
    image: reader:${VERSION}
    pull_policy: build
    container_name: cnpr-${VERSION}
    hostname: reader-${VERSION}
    build:
      context: reader
      args:
        version: ${VERSION}
    ports:
      - "8000:8000"
    networks:
      - mynet

networks:
  mynet:
    driver: bridge
    name: ${NETWORK_NAME}

The issue arises because the reader service in your docker-compose.yml file is exposing port 8000 on the host machine. When you try to run multiple instances of the application, each instance attempts to bind to the same port 8000 on the host, which causes the “port is already allocated” error.

To resolve this, you can parameterize the exposed port in your .env files so that each instance uses a unique port on the host. Here’s how you can modify your setup:


Updated docker-compose.yml

name: sr-${VERSION?Set the variables}

services:
  sender:
    image: sender:${VERSION}
    pull_policy: build
    container_name: cnps-${VERSION}
    build:
      context: sender
      args:
        version: ${VERSION}
        message: ${MESSAGE}
        receiver: reader-${VERSION}
    networks:
      - mynet

  reader:
    image: reader:${VERSION}
    pull_policy: build
    container_name: cnpr-${VERSION}
    hostname: reader-${VERSION}
    build:
      context: reader
      args:
        version: ${VERSION}
    ports:
      - "${HOST_PORT}:8000" # Parameterize the host port
    networks:
      - mynet

networks:
  mynet:
    driver: bridge
    name: ${NETWORK_NAME}

I should have stated that I can run two instances of the application by building the images:

$ docker compose --env-file n1.env build
$ docker compose --env-file n2.env build

and then, in 4 separate xterm windows, running the two service pairs. I create the containers for one pair using --network=network1 and using --network=network2 for the other. I haven’t (knowingly) used any port other than 8000.

Your solution would work, but I’d prefer not to use ports other than the actual ones. Perhaps I should ask the question another way: how do I convince docker-compose to make a network purely internal to a set of containers?

I’m confused about your goal. If you have a port forward using the same host port, it doesn’t matter what image you are using and whether you build an image or not. You cannot use the same port twice on the same host IP.

Docker networks will not change it. Each container has its own network namespace so the process in it can listen on any port. You either chose different host ports whe using port forward, or you remove port forwards from the compose file and use the container IPs directly (wouldn’t workk with Docker Desktop) or use a reverese proxy and different domains for each project so the proy can forward requests to the right service behind it.

It turned out I was trying to do what the “internal: true” attribute achieves. I should have been more explicit about not wanting host ports.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.