Search code examples
dockerdocker-composedocker-network

How ports notation in docker compose service works?


in docker-compose.yml,

What is the difference between in following ports notations?

ports:
   - "5000:5000"

resp:

ports:
   - "8080"

or no ports at all.

For example in following docker-compose.yml, the mongodb service must be exposing a port to communicate with node service, but no port is specified

services:

  node:
    build:
      context: .
      dockerfile: node.dockerfile
    ports:
      - "3000:3000"
    networks:
      - nodeapp-network
    depends_on: 
      - mongodb

  mongodb:
    image: mongo
    networks:
      - nodeapp-network

networks:
  nodeapp-network:
    driver: bridge

source: https://github.com/DanWahlin/NodeExpressMongoDBDockerApp

However in these docker-compose.yml, there are ports awlays specified with either 27017:27017 or 8080 notation.

services:
    nginx:
      container_name: nginx
      image: ${DOCKER_ACCT}/nginx
      build: 
        context: .
        dockerfile: .docker/nginx.${APP_ENV}.dockerfile
      links:
        - node1:node1
        - node2:node2
        - node3:node3
      ports:
        - "80:80"
        - "443:443"
      networks:
        - codewithdan-network

    node1:
      container_name: node-codewithdan-1
      image: ${DOCKER_ACCT}/node-codewithdan
      build: 
        context: .
        dockerfile: .docker/node-codewithdan.${APP_ENV}.dockerfile
      ports:
      - "8080"
      volumes:
        - .:/var/www/codewithdan
      working_dir: /var/www/codewithdan
      env_file:
        - ./.docker/env/app.${APP_ENV}.env
      depends_on:
        - mongo
        - redis
      networks:
        - codewithdan-network

    node2:
      container_name: node-codewithdan-2
      image: ${DOCKER_ACCT}/node-codewithdan
      build: 
        context: .
        dockerfile: .docker/node-codewithdan.${APP_ENV}.dockerfile
      ports:
      - "8080"
      volumes:
        - .:/var/www/codewithdan
      working_dir: /var/www/codewithdan
      env_file:
        - ./.docker/env/app.${APP_ENV}.env
      depends_on:
        - mongo
        - redis
      networks:
        - codewithdan-network

    node3:
      container_name: node-codewithdan-3
      image: ${DOCKER_ACCT}/node-codewithdan
      build: 
        context: .
        dockerfile: .docker/node-codewithdan.${APP_ENV}.dockerfile
      ports:
      - "8080"
      volumes:
        - .:/var/www/codewithdan
      working_dir: /var/www/codewithdan
      env_file:
        - ./.docker/env/app.${APP_ENV}.env
      depends_on:
        - mongo
        - redis
      networks:
        - codewithdan-network

    mongo:
      container_name: mongo
      image: ${DOCKER_ACCT}/mongo
      build:
        context: .
        dockerfile: .docker/mongo.dockerfile
      ports:
      - "27017:27017"
      env_file:
        - ./.docker/env/mongo.${APP_ENV}.env
      networks:
        - codewithdan-network

    redis:
      container_name: redis
      image: ${DOCKER_ACCT}/redis
      build: 
        context: .
        dockerfile: .docker/redis.${APP_ENV}.dockerfile
      ports:
        - "6379"
      networks:
        - codewithdan-network

networks:
    codewithdan-network:
      driver: bridge

source: https://github.com/DanWahlin/CodeWithDanDockerServices

Can you explain the difference?


Solution

  • Typical Docker containers run a long-running server listening on some TCP port. Other containers on the same Docker network can reach that container using the container’s name (docker run --name, container_name: directive) as a DNS name and the port the server is running on. In Docker Compose, Compose creates a Docker network per Compose YAML file, and also makes services available under their key in the YAML file. This works even if no ports: are specified.

    So, for instance, if your docker-compose.yml file says

    services:
      mongo:
        image: mongo
      others:
        env:
          MONGODB_HOST: mongo
          MONGODB_PORT: 27017
    

    then the MongoDB container will be reachable on that host name and (default) port, even though it doesn’t explicitly have a ports:.

    If you do declare a ports: then the container will be reachable from outside Docker space. If you only have one port it’s the port number of the server, and Docker picks the host port; this isn’t useful in most cases (but it’s guaranteed to not hit a port conflict). If you have two ports they’re the host port and internal service port. You can also specify a host IP address to bind(2) to.

    Presence or absence of ports: doesn’t affect inter-dontainer communication. Always use the container’s name (or Docker-compose.yml service name) and the “internal” port number the server is listening on.