Giao tiếp giữa nhiều dự án soạn thảo docker


253

Tôi có hai docker-compose.ymltệp riêng biệt trong hai thư mục khác nhau:

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

Làm thế nào tôi có thể chắc chắn rằng một container trong frontcó thể gửi yêu cầu đến một container trong api?

Tôi biết rằng --default-gatewaytùy chọn này có thể được đặt bằng cách sử dụng docker runcho một vùng chứa riêng lẻ, do đó có thể gán địa chỉ IP cụ thể cho vùng chứa này, nhưng dường như tùy chọn này không khả dụng khi sử dụng docker-compose.

Hiện tại tôi kết thúc việc làm docker inspect my_api_container_idvà nhìn vào cổng ở đầu ra. Nó hoạt động nhưng vấn đề là IP này được gán ngẫu nhiên, vì vậy tôi không thể dựa vào nó.

Một dạng khác của câu hỏi này có thể là:

  • Tôi có thể gán một địa chỉ IP cố định cho một vùng chứa cụ thể bằng cách sử dụng docker-compose không?

Nhưng cuối cùng, thứ tôi đang chăm sóc là:

  • Làm thế nào hai dự án soạn thảo docker khác nhau có thể giao tiếp với nhau?

4
Tôi chỉ nhìn vào điều này ngày hôm nay một lần nữa. Các nhà phát triển cuối cùng đã đồng ý và cho phép đặt tên mạng tùy ý. Sử dụng soạn thảo tệp phiên bản 3.5, bạn có thể chỉ định tên cho mạng mặc định trong khóa 'mạng'. Điều này sẽ tạo ra một mạng được đặt tên mà không có tiền tố tên dự án thông thường nếu nó không tồn tại ..
cstrutton

Câu trả lời:


325

Bạn chỉ cần đảm bảo rằng các thùng chứa bạn muốn nói chuyện với nhau nằm trên cùng một mạng. Mạng là một cấu trúc docker hạng nhất và không cụ thể để soạn.

# 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

Lưu ý: Mạng của ứng dụng của bạn được đặt tên dựa trên tên dự án của Cameron, dựa trên tên của thư mục mà nó sống, trong trường hợp này, tiền tố front_đã được thêm vào

Sau đó, họ có thể nói chuyện với nhau bằng tên dịch vụ. Từ frontbạn có thể làm ping apivà ngược lại.


1
Jivan đó là một giải pháp không. Container của bạn không cần biết gì về máy chủ hoặc bị thao túng như thế. Câu trả lời của tôi khá ngắn, mặc dù vậy, tôi đã cập nhật với nhiều chi tiết hơn.
johnharris85

3
Robert Moskal chỉ khi bạn hack xung quanh để lấy ip của máy chủ docker của bạn vào container. Tốt hơn là để chúng giao tiếp trên một mạng xác định docker chung.
johnharris85

2
Xin lưu ý rằng tiền tố "front_" vào mạng được tạo tự động từ thư mục mà nó đang chạy. Vì vậy, nếu tập tin docker-compose đầu tiên của bạn sẽ nằm trong "example / docker-compose.yml" thì nó sẽ được gọi là "example_default".
AngryUb UbuntuNerd

7
Bạn cũng có thể cung cấp tên cho một mạng bằng cách sử dụng thuộc nametính, điều này sẽ vô hiệu hóa việc nạp trước tự động với tên dự án. Sau đó, một trong hai dự án có thể sử dụng mạng đó và tạo nó tự động nếu nó chưa tồn tại.
SteveB

2
@SteveB - Lưu ý rằng thuộc tính tên chỉ hoạt động từ các tệp soạn thảo
docker

78

Chỉ cần một lời quảng cáo nhỏ cho câu trả lời tuyệt vời của @ johnharris85, khi bạn đang chạy tệp soạn thảo docker, một defaultmạng "" được tạo để bạn có thể thêm nó vào tệp soạn thảo khác dưới dạng mạng bên ngoài:

# 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

Đối với tôi cách tiếp cận này phù hợp hơn vì tôi không sở hữu tệp soạn thảo docker đầu tiên và muốn giao tiếp với nó.


chỉ cần đi lang thang đúng cách để gán IP tĩnh cho mạng bên ngoài này. Tôi đã thực hiện để làm điều đó trong services:thẻ, sintax sẽ được networks:lồng vào nhau front_default:(loại bỏ "-") và sau đó chúng ta lồng một IP tĩnh:ipv4_address: '172.20.0.44'
Junior Mayhé

76

CẬP NHẬT: Kể từ khi soạn tập tin phiên bản 3.5:

Điều này bây giờ hoạt động:

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

networks:
  proxynet:
    name: custom_network

docker-compose up -dsẽ tham gia một mạng gọi là 'custom_network'. Nếu nó không tồn tại, nó sẽ được tạo ra!

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

Bây giờ, bạn có thể làm điều này:

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

Điều này sẽ tạo ra một container sẽ nằm trên mạng bên ngoài.

Tôi không thể tìm thấy bất kỳ tài liệu tham khảo nào trong các tài liệu nhưng nó hoạt động!


Bạn có phải bắt đầu hai dịch vụ theo một thứ tự cụ thể không? Bạn có thể bắt đầu một trong hai, và cái đầu tiên sẽ tạo ra mạng và cái thứ hai sẽ tham gia nó?
slashdottir

4
Dịch vụ đầu tiên (proxy ở trên) tạo ra mạng. Cú pháp trong ví dụ thứ hai tham gia nó.
cstrutton

2
@slashdottir Bạn không thể đánh dấu mạng là bên ngoài trong dịch vụ thứ hai và nó sẽ được tạo nếu nó chưa tồn tại.
SteveB

2
Nó không hoạt động. Tôi chỉ tạo ra một giọt DO với docker mới nhất sáng tác. Tôi đã chỉnh sửa ví dụ thành một ví dụ làm việc thực tế.
cstrutton

1
Trong trường hợp của tôi, điều này hóa ra là một giải pháp phù hợp hơn câu trả lời được chấp nhận. Vấn đề với mạng bên ngoài là, nó bắt buộc phải khởi động các container theo thứ tự được xác định trước. Đối với khách hàng của tôi, điều này không được chấp nhận. Một mạng được đặt tên (kể từ 3.5) hóa ra là giải pháp hoàn hảo. Cảm ơn.
ygor

24

Tất cả các container từ apicó thể tham gia mạng front mặc định với cấu hình sau:

# api/docker-compose.yml

...

networks:
  default:
    external:
      name: front_default

Xem hướng dẫn soạn thảo docker: sử dụng mạng hiện có (xem ở phía dưới)


12

Thông tin bài viết trước là chính xác, nhưng nó không có chi tiết về cách liên kết các thùng chứa, nên được kết nối dưới dạng "bên ngoài_links".

Hy vọng ví dụ này làm rõ hơn cho bạn:

  • Giả sử bạn có app1 / docker-compose.yml, với hai dịch vụ (svc11 và svc12) và app2 / docker-compose.yml với hai dịch vụ khác (svc21 và svc22) và giả sử bạn cần kết nối theo kiểu chéo:

  • svc11 cần kết nối với container của svc22

  • svc21 cần kết nối với container của svc11.

Vì vậy, cấu hình nên như thế này:

đây là 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

đây là 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

Kể từ Soạn 1.18 (thông số 3.5), bạn chỉ có thể ghi đè mạng mặc định bằng tên tùy chỉnh của riêng bạn cho tất cả các tệp YAML bạn cần. Nó đơn giản như việc nối thêm các phần sau vào chúng:

networks:
  default:
    name: my-app

Giả định ở trên bạn đã versionđặt thành 3.5(hoặc ở trên nếu họ không phản đối trong 4+).

Các câu trả lời khác đã chỉ ra tương tự; đây là một bản tóm tắt đơn giản hóa


2

Tôi sẽ đảm bảo tất cả các container được docker-composekết nối vào cùng một mạng bằng cách kết hợp chúng cùng một lúc, bằng cách sử dụng:

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

Điều đó có cho phép tôi, ví dụ, tạo một linkhoặc depends_ontừ một thùng chứa phía trước sang một thùng chứa api không?
Jivan

thực sự khi tôi làm những gì bạn đề xuất, hãy trả lời docker-compose build path ~/front/api either does not exist or is not accessiblehoặc bằng cách khác,build path ~/api/front either does not exist or is not accessible
Jivan

1
Nếu bạn đang soạn chúng cùng một lúc, bạn không cần phải làm vậy. Một mạng sẽ được tạo với tất cả các container của bạn trên đó, tất cả chúng sẽ có thể giao tiếp thông qua tên dịch vụ từ tệp soạn thảo ( không phải tên container).
Nauraushaun

Có thể dễ dàng hơn nếu hai tệp soạn thảo nằm trong cùng một thư mục. Nhưng tôi không nghĩ điều đó là cần thiết - tôi nghĩ nó cũng nên hoạt động.
Nauraushaun

2
Giải pháp này không hoạt động, hãy xem nhận xét của tôi về chủ đề này: github.com/docker/compose/issues35330#issuecomment-222490501
johnharris85

2

CẬP NHẬT: Kể từ khi soạn tập tin phiên bản 3.5:

Tôi đã gặp vấn đề tương tự và tôi đã giải quyết nó bằng cách thêm một thay đổi nhỏ vào một trong dự án docker-compose.yml của tôi.

Ví dụ, chúng tôi có hai api scoringner. Scoringapi cần gửi yêu cầu đến nerapi để xử lý yêu cầu đầu vào. Để làm điều đó, cả hai đều giả sử chia sẻ cùng một mạng.

Lưu ý: Mỗi container có mạng riêng được tạo tự động tại thời điểm chạy ứng dụng bên trong docker. Ví dụ, mạng api ner sẽ được tạo như thế ner_defaultvà mạng api sẽ được đặt tên là scoring default. Giải pháp này sẽ hoạt động cho phiên bản: '3'.

Như trong kịch bản trên, api ghi điểm của tôi muốn liên lạc với ner api sau đó tôi sẽ thêm các dòng sau. Điều đó có nghĩa là Bất cứ khi nào tôi tạo vùng chứa cho ner api thì nó sẽ tự động thêm vào mạng points_default.

networks:
  default:
      external:
        name: scoring_default

ner / docker-compose.yml

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

networks:
  default:
      external:
        name: scoring_default

chấm điểm / docker-compose.yml

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

Chúng ta có thể thấy điều này làm thế nào các container ở trên bây giờ là một phần của cùng một mạng được gọi scoring_defaultbằng lệnh:

docker kiểm tra points_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": ""
    },
    ...
}

1

Bạn có thể thêm một .envtập tin trong tất cả các dự án của bạn có chứa COMPOSE_PROJECT_NAME=somename.

COMPOSE_PROJECT_NAME ghi đè tiền tố được sử dụng để đặt tên tài nguyên, vì vậy tất cả các dự án của bạn sẽ sử dụng somename_defaultlàm mạng của họ, giúp các dịch vụ có thể giao tiếp với nhau như trong cùng một dự án.

Lưu ý: Bạn sẽ nhận được cảnh báo cho các container "mồ côi" được tạo từ các dự án khác.


0
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

0

Để sử dụng một mạng soạn thảo docker khác, bạn chỉ cần thực hiện những điều này (để chia sẻ các mạng giữa docker-compose):

  1. Chạy dự án soạn thảo docker đầu tiên bằng cách up -d
  2. Tìm tên mạng của docker-compose đầu tiên bằng cách: docker network ls(Nó chứa tên của dự án thư mục gốc)
  3. Sau đó sử dụng tên đó theo cấu trúc này ở bên dưới trong tệp soạn thảo docker thứ hai.

docker-compose.yml thứ hai

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

0

Một tùy chọn khác là chạy mô-đun đầu tiên với 'docker-compose' kiểm tra ip liên quan đến mô-đun và kết nối mô-đun thứ hai với mạng trước như bên ngoài và trỏ ip bên trong

ví dụ app1 - mạng mới được tạo trong các dòng dịch vụ, đánh dấu là bên ngoài: true ở phía dưới app2 - cho biết "mạng mới" được tạo bởi app1 khi đi lên, đánh dấu là bên ngoài: true ở dưới cùng và đặt trong cấu hình để kết nối, ip mà app1 có trong mạng này.

Với điều này, bạn sẽ có thể nói chuyện với nhau

* cách này chỉ dành cho tập trung kiểm tra cục bộ, để không thực hiện cấu hình quá phức tạp ** Tôi biết là rất 'cách vá' nhưng hoạt động với tôi và tôi nghĩ rất đơn giản, một số khác có thể tận dụng lợi thế này


0

Nếu bạn là

  • cố gắng giao tiếp giữa hai container từ các dự án soạn thảo docker khác nhaukhông muốn sử dụng cùng một mạng (vì giả sử họ sẽ có container PostgreQuery hoặc Redis trên cùng một cổng và bạn không muốn thay đổi các cổng này và không sử dụng nó ở cùng một mạng)
  • phát triển cục bộ và muốn bắt chước giao tiếp giữa hai dự án soạn thảo docker
  • chạy hai dự án soạn thảo docker trên localhost
  • đặc biệt là phát triển ứng dụng Django hoặc API Django Rest Framework (drf) và chạy ứng dụng bên trong container trên một số cổng bị lộ
  • nhận được Connection refusedtrong khi cố gắng giao tiếp giữa hai container

Và bạn muốn

  • container api_agiao tiếp với api_b(hoặc ngược lại) mà không có cùng "mạng docker"

(ví dụ dưới đây)

bạn có thể sử dụng "máy chủ" của bộ chứa thứ hai làm IP của máy tính và cổng được ánh xạ từ bên trong bộ chứa Docker. Bạn có thể lấy IP của máy tính của mình bằng tập lệnh này (từ: Tìm địa chỉ IP cục bộ bằng stdlib của Python ):

import socket
def get_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        # doesn't even have to be reachable
        s.connect(('10.255.255.255', 1))
        IP = s.getsockname()[0]
    except:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP

Thí dụ:

project_api_a/docker-compose.yml:

networks:
  app-tier:
    driver: bridge

services:
  api:
    container_name: api_a
    image: api_a:latest
    depends_on:
      - postgresql
    networks:
      - app-tier

bên trong api_acontainer bạn đang chạy ứng dụng Django: manage.py runserver 0.0.0.0:8000

và docker-compose.yml thứ hai từ dự án khác:

project_api_b/docker-compose-yml :

networks:
  app-tier:
    driver: bridge

services:
  api:
    container_name: api_b
    image: api_b:latest
    depends_on:
      - postgresql
    networks:
      - app-tier

bên trong api_bcontainer bạn đang chạy ứng dụng Django: manage.py runserver 0.0.0.0:8001

Và cố gắng kết nối từ container api_ađến api_bURL của api_bcontainer sẽ là: http://<get_ip_from_script_above>:8001/

Nó có thể đặc biệt có giá trị nếu bạn đang sử dụng thậm chí nhiều hơn hai (ba hoặc nhiều) dự án soạn thảo docker và thật khó để cung cấp mạng chung cho tất cả các dự án - đó là cách giải quyết và giải pháp tốt

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.