Communication between multiple docker-compose proj

2020-01-23 06:01发布

问题:

I have two separate docker-compose.yml files in two different folders:

  • ~/front/docker-compose.yml
  • ~/api/docker-compose.yml

How can I make sure that a container in front can send requests to a container in api?

I know that --default-gateway option can be set using docker run for an individual container, so that a specific IP address can be assigned to this container, but it seems that this option is not available when using docker-compose.

Currently I end up doing a docker inspect my_api_container_id and look at the gateway in the output. It works but the problem is that this IP is randomly attributed, so I can't rely on it.

Another form of this question might thus be:

  • Can I attribute a fixed IP address to a particular container using docker-compose?

But in the end what I'm looking after is:

  • How can two different docker-compose projects communicate with each other?

回答1:

You just need to make sure that the containers you want to talk to each other are on the same network. Networks are a first-class docker construct, and not specific to compose.

# front/docker-compose.yml
version: '2'
services:
  front:
    ...
    networks:
      - some-net
networks:
  some-net:
    driver: bridge

...

# api/docker-compose.yml
version: '2'
services:
  api:
    ...
    networks:
      - front_some-net
networks:
  front_some-net:
    external: true

Note: Your app’s network is given a name based on the “project name”, which is based on the name of the directory it lives in, in this case a prefix front_ was added

They can then talk to each other using the service name. From front you can do ping api and vice versa.



回答2:

Just a small adittion to @johnharris85's great answer, when you are running a docker compose file, a "default" network is created so you can just add it to the other compose file as an external network:

# front/docker-compose.yml 
version: '2' 
  services:   
    front_service:
    ...

...

# api/docker-compose.yml
version: '2'
services:
  api_service:
    ...
    networks:
      - front_default
networks:
  front_default:
    external: true

For me this approach was more suited because I did not own the first docker-compose file and wanted to communicate with it.



回答3:

UPDATE: As of compose file version 3.5:

This now works:

version: "3.5"
services:
  proxy:
    image: hello-world
    ports:
      - "80:80"
    networks:
      - proxynet

networks:
  proxynet:
    name: custom_network

docker-compose up -d will join a network called 'custom_network'. If it doesn't exist, it will be created!

root@ubuntu-s-1vcpu-1gb-tor1-01:~# docker-compose up -d
Creating network "custom_network" with the default driver
Creating root_proxy_1 ... done

Now, you can do this:

version: "2"
services:
  web:
    image: hello-world
    networks:
      - my-proxy-net
networks:
  my-proxy-net:
    external:
      name: custom_network

This will create a container that will be on the external network.

I can't find any reference in the docs yet but it works!



回答4:

All containers from api can join the front default network with following config:

# api/docker-compose.yml

...

networks:
  default:
    external:
      name: front_default

See docker compose guide: using a pre existing network (see at the bottom)



回答5:

The previous posts information is correct, but it does not have details on how to link containers, which should be connected as "external_links".

Hope this example make more clear to you:

  • Suppose you have app1/docker-compose.yml, with two services (svc11 and svc12), and app2/docker-compose.yml with two more services (svc21 and svc22) and suppose you need to connect in a crossed fashion:

  • svc11 needs to connect to svc22's container

  • svc21 needs to connect to svc11's container.

So the configuration should be like this:

this is app1/docker-compose.yml:


version: '2'
services:
    svc11:
        container_name: container11
        [..]
        networks:
            - default # this network
            - app2_default # external network
        external_links:
            - container22:container22
        [..]
    svc12:
       container_name: container12
       [..]

networks:
    default: # this network (app1)
        driver: bridge
    app2_default: # external network (app2)
        external: true

this is app2/docker-compose.yml:


version: '2'
services:
    svc21:
        container_name: container21
        [..]
        networks:
            - default # this network (app2)
            - app1_default # external network (app1)
        external_links:
            - container11:container11
        [..]
    svc22:
       container_name: container22
       [..]

networks:
    default: # this network (app2)
        driver: bridge
    app1_default: # external network (app1)
        external: true


回答6:

Since Compose 1.18 (spec 3.5), you can just override the default network using your own custom name for all Compose YAML files you need. It is as simple as appending the following to them:

networks:
  default:
    name: my-app

The above assumes you have version set to 3.5 (or above if they don't deprecate it in 4+).

Other answers have pointed the same; this is a simplified summary.



回答7:

I would ensure all containers are docker-compose'd to the same network by composing them together at the same time, using:

docker compose --file ~/front/docker-compose.yml --file ~/api/docker-compose.yml up -d


回答8:

UPDATE: As of compose file version 3.5:

I came across the similar problem and I solved it by adding a small change in one of my docker-compose.yml project.

For instance we have two api's scoring and ner. Scoring api needs to send a request to the ner api for processing the input request. In order to do that they both are suppose to share the same network.

Note: Every container has its own network which is automatically created at the time of running the app inside docker. For example ner api network will be created like ner_default and scoring api network will named as scoring default. This solution will work for version: '3'.

As in the above scenario my scoring api wants to communicate with ner api then I will add the following lines. Which means Whenever I create the container for ner api then it automatically added to scoring_default network.

networks:
  default:
      external:
        name: scoring_default

ner/docker-compose.yml

version: '3'
services:
  ner:
    build: .
    ...

networks:
  default:
      external:
        name: scoring_default

scoring/docker-compose.yml

version: '3'
services:
  api:
    build: .
    ...

We can see this how the above containers are now a part of the same network called scoring_default using the command:

docker inspect scoring_default

{
    "Name": "scoring_default",
        ....
    "Containers": {
    "14a6...28bf": {
        "Name": "ner_api",
        "EndpointID": "83b7...d6291",
        "MacAddress": "0....",
        "IPv4Address": "0.0....",
        "IPv6Address": ""
    },
    "7b32...90d1": {
        "Name": "scoring_api",
        "EndpointID": "311...280d",
        "MacAddress": "0.....3",
        "IPv4Address": "1...0",
        "IPv6Address": ""
    },
    ...
}


回答9:

version: '2'
services:
  bot:
    build: .
    volumes:
      - '.:/home/node'
      - /home/node/node_modules
    networks:
      - my-rede
    mem_limit: 100m
    memswap_limit: 100m
    cpu_quota: 25000
    container_name: 236948199393329152_585042339404185600_bot
    command: node index.js
    environment:
      NODE_ENV: production
networks:
  my-rede:
    external:
      name: name_rede_externa


回答10:

For using another docker-compose network you just do these(to share networks between docker-compose):

  1. Run the first docker-compose project by up -d
  2. Find the network name of the first docker-compose by: docker network ls(It contains the name of the root directory project)
  3. Then use that name by this structure at below in the second docker-compose file.

second docker-compose.yml

version: '3'
services:
  service-on-second-compose:  # Define any names that you want.
    .
    .
    .
    networks:
      - <put it here(the network name that comes from "docker network ls")>

networks:
  - <put it here(the network name that comes from "docker network ls")>:
    external: true