Zied Hamdi
Zied Hamdi

Reputation: 2662

How to connect to named networks in docker-compose

I have an app that relies on 4 backend servers (redis, mongo, graphql-websockets-subscriptions, and graphql-http) and one front end

Not configuring networks, I am able to connect my different servers while I'm in the same container, but I cannot access the mongodb database from the front-end compose-container with the url: mongodb://weallyback_default:27017/weally

This is my front-end compose config

version: "3.8"

services:
  next_server:
    image: node:14.17.3-alpine
    volumes:
      - type: bind
        source: ./
        target: /front
      - type: volume
        source: nodemodules # name of the volume, see below
        target: /front/node_modules
        volume:
          nocopy: true
    working_dir: /front
    command: yarn dev
    ports:
      - "3000:3000"
    networks:
      - weallyback_default
    environment:
      - NODE_ENV=development
      - PORT=3000

volumes:
  nodemodules:

networks:
  weallyback_default:
    external: true

Knowing that my backend config exposes the default network weallyback_default

D:\Zied\work\WeAllyBack>docker network ls
NETWORK ID     NAME                 DRIVER    SCOPE
71d1c5f23159   bridge               bridge    local
cd980f642e7b   host                 host      local
4a50359ad823   none                 null      local
ecec643b2a2e   weallyback_default   bridge    local

That led me to attempt to configure networks, but that broke even connections between instances in the same container:

From what I understood, I have to declare networks as external if I want to use them in a different docker-compose file. So I started naming my networks, but I can't get it to work anyways:

So I appended these networks declarations to the front-end (weallyorg_next_server_1) server's config

networks:
  graphql_server:
    external: true
  graphql_pubsub_server:
    external: true
  mongo_server:
    external: true

This is the config for my 4 backend servers:

version: "3.8"

services:
  redis-server:
    container_name: redis-server
    image: 'redis:6.2-alpine'
    ports:
      - "6379:6379"
    networks:
      - redis_server
  mongo-server:
    container_name: mongo-server
    image: mongo:4.4.5
    ports:
      - "27001:27001"
    volumes:
      - mongodb:/data/db
      - mongodb_config:/data/configdb
    networks:
      - mongo_server
    restart: always
  graphql_server:
    container_name: graphql_server
    depends_on:
      - mongo-server
      - redis-server
    image: node:14.17.3-alpine
    volumes:
      - type: bind
        source: ./
        target: /app
      - type: volume
        source: nodemodules # name of the volume, see below
        target: /app/node_modules
        volume:
          nocopy: true
    working_dir: /app
    command: yarn dev
    ports:
      - "4000:4000"
    networks:
      - graphql_server
      - mongo_server
    environment:
      - NODE_ENV=development
      - PORT=4000
  graphql_pubsub_server:
    container_name: graphql_pubsub_server
    depends_on:
      - mongo-server
      - redis-server
    image: node:14.17.3-alpine
    volumes:
      - type: bind
        source: ./
        target: /app
      - type: volume
        source: nodemodules # name of the volume, see below
        target: /app/node_modules
        volume:
          nocopy: true
    working_dir: /app
    command: yarn dev-sub
    ports:
      - "4001:4001"
    networks:
      - graphql_pubsub_server
      - mongo_server
      - redis_server
    environment:
      - NODE_ENV=development
      - PORT=4000

volumes:
  nodemodules:
  mongodb:
  mongodb_config:

networks:
  graphql_server:
    name: graphql_server
    driver: bridge
  graphql_pubsub_server:
    name: graphql_pubsub_server
    driver: bridge
  mongo_server:
    name: mongo_server
    driver: bridge
  redis_server:
    name: redis_server
    driver: bridge

When I try to connect the graphql servers to mongo and redis, it doesn't work:

const DEV_URL_LOCAL = 'mongodb://mongo-server:27017/weally';

export const pubsub = new RedisPubSub({connection:{
        host: 'redis-server',
        port: 6379
    }});

Even though the networks seem to be ok when I run docker network inspect, I see the front-end instance weallyorg_next_server_1 associated in the containers list:

D:\Work\WeAllyBack>docker network ls
NETWORK ID     NAME                    DRIVER    SCOPE
2dbd93a99f96   bridge                  bridge    local
58c1d94a2f2e   graphql_pubsub_server   bridge    local
62d20fee3c3a   graphql_server          bridge    local
b16be840cbd1   host                    host      local
655197efa0d7   mongo_server            bridge    local
c2c845f1c14c   none                    null      local
0b95acfd581d   redis_server            bridge    local
ee7d85a80a09   weallyback              bridge    local

D:\Work\WeAllyBack>docker network inspect mongo_server
[
    {
        "Name": "mongo_server",
        "Id": "655197efa0d7c0070ea3a5e2fba565c117bde72efaf4e5952fe6e2c1499199a0",
        "Created": "2021-08-02T12:05:15.397633Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.20.0.0/16",
                    "Gateway": "172.20.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "438cdfa8fc24ef3c2a537c3746f2a82e29bdb29e6c925e34587531819f96cfa3": {
                "Name": "graphql_pubsub_server",
                "EndpointID": "05ce92ae14016d6144c97748e5a1718a62ab4fc14d6518d2b33bd2f2077fb229",
                "MacAddress": "02:42:ac:14:00:05",
                "IPv4Address": "172.20.0.5/16",
                "IPv6Address": ""
            },
            "b71e428de30e01b13c1cc83ecc083baac88fdb7f01a0385a0984000e24dc2f52": {
                "Name": "mongo-server",
                "EndpointID": "cac16e9c451f24a708d5b678b69beb54358f49960700e240975c4634bb90b9ac",
                "MacAddress": "02:42:ac:14:00:02",
                "IPv4Address": "172.20.0.2/16",
                "IPv6Address": ""
            },
            "ee8ef82c6751946d68a7ec295d266306ef992bc30f3314eeb432080db42db877": {
                "Name": "graphql_server",
                "EndpointID": "5a198664afc78c8f8b23682288f4ea42f0253e448b4968c0af3e2f878d8835a8",
                "MacAddress": "02:42:ac:14:00:04",
                "IPv4Address": "172.20.0.4/16",
                "IPv6Address": ""
            },
            "f2405fe94eb5c7638b8cad062665a35b224b86b887822ed384c9a840d1eab622": {
                "Name": "weallyorg_next_server_1",
                "EndpointID": "df8930f6e5bc141cf2992fd81c552ee58944e9c5036a64f0a09ca9206e2808c0",
                "MacAddress": "02:42:ac:14:00:03",
                "IPv4Address": "172.20.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "mongo_server",
            "com.docker.compose.project": "weallyback",
            "com.docker.compose.version": "1.29.2"
        }
    }
]

I'm new to Docker, so I'm really confused about whet to do next...

Please note that if I remove the network specific settings everything works fine, I just want to have my front end server configuration in a different docker-compose file, so I want to name the networks to access them from the other (front end) container. This config works for redis-server:6379 and mongodb://mongo-server:27017/weally urls:

version: "3.8"

services:
  redis-server:
    image: 'redis:6.2-alpine'
    ports:
    - "6379:6379"
  mongo-server:
    image: mongo:4.4.5
    ports:
    - "27001:27001"
    volumes:
    - mongodb:/data/db
    - mongodb_config:/data/configdb
    restart: always
  graphql_server:
    depends_on:
      - mongo-server
      - redis-server
    image: node:14.17.3-alpine
    volumes:
      - type: bind
        source: ./
        target: /app
      - type: volume
        source: nodemodules # name of the volume, see below
        target: /app/node_modules
        volume:
          nocopy: true
    working_dir: /app
    command: yarn dev
    ports:
      - "4000:4000"
    environment:
      - NODE_ENV=development
      - PORT=4000
  graphql_pubsub_server:
    depends_on:
      - mongo-server
      - redis-server
    image: node:14.17.3-alpine
    volumes:
      - type: bind
        source: ./
        target: /app
      - type: volume
        source: nodemodules # name of the volume, see below
        target: /app/node_modules
        volume:
          nocopy: true
    working_dir: /app
    command: yarn dev-sub
    ports:
      - "4001:4001"
    environment:
      - NODE_ENV=development
      - PORT=4000

volumes:
  nodemodules:
  mongodb:
  mongodb_config:

This gives theses networks after pruning

> docker network ls
NETWORK ID     NAME                 DRIVER    SCOPE
71d1c5f23159   bridge               bridge    local
cd980f642e7b   host                 host      local
4a50359ad823   none                 null      local
e4cf4a71d49a   weallyback_default   bridge    local

I suspect the format of my connection url to be wrong but I can't find the info to set it right. I've red some tutorials like this one, and my urls should be correct, I can't figure out what is missing

Upvotes: 1

Views: 13815

Answers (2)

Zied Hamdi
Zied Hamdi

Reputation: 2662

Ok!!!

So it seems bridge doesn't resolve names

The downside with the bridge driver is that it’s not recommended for production; the containers communicate via IP address instead of automatic service discovery to resolve an IP address to the container name.

https://earthly.dev/blog/docker-networking/

more details are available here: https://docs.docker.com/network/network-tutorial-standalone/

Upvotes: 1

Ids van der Zee
Ids van der Zee

Reputation: 882

You can setup a single network for your application reusing the same network in all containers. This way you can resolve all applications by name.

Under the services add the following for each service:

services:
  serviceName:
    networks:
      - myNetwork

Then at the bottom of the yaml compose file (in all different compose files):

networks:
  myNetwork:
    external:
      name: myNetwork

Then you can resolve all applications based on container name.

Edit

When using a front-end and you also want to make requests from the browser to the different containers you need to setup some sort of reverse proxy. Using e.g. Nginx to pass requests from the front end to the specified docker container. Using a configuration similar to:

server {
    listen 80;
    listen [::]:80;

    location /api/graphql {
        proxy_set_header        Host $host;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto $scheme;
        proxy_pass              http://graphql_server:6379;
    }
    location /api/graphql-pubsub {
        proxy_set_header        Host $host;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto $scheme;
        proxy_pass              http://graphql_pubsub_server:27001;
    }

# Add configuration for other services if you need to access them from the front end

    error_page 404 /404.html;
    location = /404.html {
    }

    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    } 
}

Then in this example a request to the graphql server would be achieved from the browser by calling /api/graphql using the base url of your front end application.

This would require you to use the nginx base container, this can be done with a docker file like:

FROM node:15.8.0-alpine as build
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package.json ./
COPY yarn.lock ./
RUN yarn install
RUN yarn add [email protected] -g --silent
COPY . ./
RUN yarn build

FROM nginx:stable-alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY --from=build /app/nginx.proxy.conf /etc/nginx/conf.d/nginx.proxy.conf
EXPOSE 443
CMD ["nginx", "-g", "daemon off;"]

Adjust where needed, this is just Dockerfile an example of a React application.

Upvotes: 4

Related Questions