การสื่อสารระหว่างโครงการสร้างนักเทียบท่าหลายโครงการ


254

ฉันมีสองdocker-compose.ymlไฟล์แยกกันในสองโฟลเดอร์:

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

ฉันจะแน่ใจได้อย่างไรว่าคอนเทนเนอร์ในfrontสามารถส่งคำขอไปยังคอนเทนเนอร์ในได้apiอย่างไร

ฉันรู้ว่า--default-gatewayตัวเลือกที่สามารถตั้งค่าการใช้docker runสำหรับภาชนะแต่ละคนเพื่อให้ที่อยู่ที่ระบุ IP สามารถกำหนดให้กับคอนเทนเนอร์นี้ docker-composeแต่ดูเหมือนว่าตัวเลือกนี้ไม่สามารถใช้ได้เมื่อใช้

ขณะนี้ฉันสิ้นสุดการทำdocker inspect my_api_container_idและดูเกตเวย์ในผลลัพธ์ มันใช้งานได้ แต่ปัญหาก็คือว่า IP นี้มีการสุ่มมาดังนั้นฉันไม่สามารถวางใจได้

คำถามอีกรูปแบบหนึ่งอาจเป็นเช่นนี้:

  • ฉันสามารถกำหนดที่อยู่ IP คงที่ให้กับคอนเทนเนอร์เฉพาะโดยใช้นักเทียบท่าเขียนได้หรือไม่

แต่ในที่สุดสิ่งที่ฉันดูแลคือ:

  • โครงการนักแต่งเพลงที่แตกต่างกันสองโครงการสามารถสื่อสารกันได้อย่างไร

4
ฉันเพิ่งดูวันนี้อีกครั้ง ในที่สุด devs ก็ยอมอ่อนข้อและอนุญาตการตั้งชื่อเครือข่ายเอง การใช้ไฟล์เขียนเวอร์ชั่น 3.5 คุณสามารถระบุชื่อสำหรับเครือข่ายเริ่มต้นภายใต้คีย์ 'เครือข่าย' นี้จะสร้างเครือข่ายการตั้งชื่อโดยไม่มีคำนำหน้าชื่อโครงการปกติถ้ามันไม่ได้อยู่ ..
cstrutton

คำตอบ:


325

คุณต้องตรวจสอบให้แน่ใจว่าคอนเทนเนอร์ที่คุณต้องการคุยด้วยนั้นอยู่ในเครือข่ายเดียวกัน เครือข่ายเป็นโครงสร้างนักเทียบท่าชั้นหนึ่งและไม่เฉพาะเจาะจงในการเขียน

# 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

หมายเหตุ: เครือข่ายของแอปของคุณได้รับชื่อตาม“ ชื่อโครงการ” ซึ่งขึ้นอยู่กับชื่อของไดเรกทอรีที่ใช้งานอยู่ในกรณีนี้จะมีการfront_เพิ่มคำนำหน้า

จากนั้นพวกเขาสามารถพูดคุยกันโดยใช้ชื่อบริการ จากที่frontคุณสามารถทำได้ping apiและในทางกลับกัน


1
Jivan นั่นไม่ใช่วิธีแก้ปัญหา ตู้คอนเทนเนอร์ของคุณไม่จำเป็นต้องรู้อะไรเกี่ยวกับโฮสต์หรือถูกจัดการอย่างนั้น คำตอบของฉันค่อนข้างสั้น แต่ฉันได้อัปเดตพร้อมรายละเอียดเพิ่มเติม
johnharris85

3
Robert Moskal เฉพาะในกรณีที่คุณแฮ็คเพื่อรับ IP ของโฮสต์นักเทียบท่าของคุณลงในภาชนะ ดีกว่าที่จะให้พวกเขาสื่อสารบนเครือข่ายที่กำหนดโดยนักเทียบท่าทั่วไป
johnharris85

2
โปรดทราบว่าคำนำหน้า "front_" ไปยังเครือข่ายจะถูกสร้างขึ้นโดยอัตโนมัติจากโฟลเดอร์ที่ทำงานอยู่ ดังนั้นหากไฟล์นักเทียบท่าแรกของคุณจะอยู่ใน "example / docker-compose.yml" มันจะถูกเรียกว่า "example_default" แทน
AngryUbuntuNerd

7
คุณยังสามารถระบุชื่อให้กับเครือข่ายโดยใช้nameคุณสมบัติซึ่งจะปิดใช้งานการเติมอัตโนมัติด้วยชื่อโครงการ จากนั้นโครงการใดโครงการหนึ่งสามารถใช้เครือข่ายนั้นและสร้างขึ้นโดยอัตโนมัติหากยังไม่มีอยู่
SteveB

2
@SteveB - โปรดทราบว่าคุณสมบัติชื่อใช้ได้กับไฟล์นักเทียบท่าเขียนเฉพาะรุ่น 3.5 ขึ้นไป
kramer65

78

เป็นคำตอบที่ยอดเยี่ยมของ @ johnharris85 เพียงเล็กน้อยเมื่อคุณใช้งานเขียนไฟล์นักเทียบท่าdefaultเครือข่าย "" จะถูกสร้างขึ้นเพื่อให้คุณสามารถเพิ่มลงในไฟล์เขียนอื่นเป็นเครือข่ายภายนอก:

# 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

สำหรับฉันวิธีนี้เหมาะกว่าเพราะฉันไม่ได้เป็นเจ้าของไฟล์นักเทียบท่าแรกและต้องการสื่อสารกับมัน


เพียงหลงทางที่ถูกต้องเพื่อกำหนด IP แบบคงที่สำหรับเครือข่ายภายนอกนี้ ฉันจะทำมันภายในservices:แท็ก sintax จะnetworks:ซ้อนกันแล้วfront_default:(ลบ "-") แล้วเราก็ทำ IP แบบคงที่:ipv4_address: '172.20.0.44'
จูเนียร์Mayhé

77

UPDATE: ณ ไฟล์เขียนเวอร์ชัน 3.5:

ตอนนี้ใช้งานได้:

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

networks:
  proxynet:
    name: custom_network

docker-compose up -dจะเข้าร่วมเครือข่ายชื่อ 'custom_network' หากไม่มีอยู่มันจะถูกสร้างขึ้น!

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

ตอนนี้คุณสามารถทำสิ่งนี้:

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

สิ่งนี้จะสร้างคอนเทนเนอร์ที่จะอยู่บนเครือข่ายภายนอก

ฉันไม่พบการอ้างอิงใด ๆ ในเอกสาร แต่ใช้งานได้!


คุณต้องเริ่มต้นบริการทั้งสองตามลำดับที่ระบุหรือไม่ คุณสามารถเริ่มต้นหนึ่งและที่แรกจะสร้างเครือข่ายและที่สองจะเข้าร่วมได้หรือไม่
slashdottir

4
บริการแรก (พร็อกซีด้านบน) สร้างเครือข่าย ไวยากรณ์ในตัวอย่างที่สองเข้าร่วม
cstrutton

2
@slashdottir คุณไม่สามารถทำเครื่องหมายเครือข่ายเป็นภายนอกในบริการที่สองและจะถูกสร้างขึ้นหากยังไม่มีอยู่
SteveB

2
มันใช้งานได้ดี ฉันเพิ่งหมุนหยดทำด้วยนักเขียนล่าสุด ฉันได้แก้ไขตัวอย่างของตัวอย่างการทำงานจริง
cstrutton

1
ในกรณีของฉันนี่เป็นทางออกที่เหมาะสมกว่าคำตอบที่ยอมรับ ปัญหาเกี่ยวกับเครือข่ายภายนอกคือต้องเริ่มคอนเทนเนอร์ตามลำดับที่กำหนดไว้ล่วงหน้า สำหรับลูกค้าของฉันสิ่งนี้ไม่เป็นที่ยอมรับ เครือข่ายที่มีชื่อ (ตั้งแต่ 3.5) กลายเป็นโซลูชั่นที่สมบูรณ์แบบ ขอบคุณ
ygor

25

คอนเทนเนอร์ทั้งหมดจากapiสามารถเข้าร่วมเครือข่ายfront เริ่มต้นด้วยการกำหนดค่าต่อไปนี้:

# api/docker-compose.yml

...

networks:
  default:
    external:
      name: front_default

ดูคำแนะนำในการเขียนนักเทียบท่า: ใช้เครือข่ายที่มีอยู่ก่อน (ดูที่ด้านล่าง)


12

ข้อมูลโพสต์ก่อนหน้านี้ถูกต้อง แต่ไม่มีรายละเอียดเกี่ยวกับวิธีลิงก์คอนเทนเนอร์ซึ่งควรเชื่อมต่อเป็น "external_links"

หวังว่าตัวอย่างนี้จะทำให้คุณชัดเจนยิ่งขึ้น:

  • สมมติว่าคุณมี app1 / docker-compose.yml ที่มีสองบริการ (svc11 และ svc12) และ app2 / docker-compose.yml ที่มีอีกสองบริการ (svc21 และ svc22) และสมมติว่าคุณต้องเชื่อมต่อแบบไขว้:

  • svc11 จำเป็นต้องเชื่อมต่อกับคอนเทนเนอร์ของ svc22

  • svc21 จำเป็นต้องเชื่อมต่อกับคอนเทนเนอร์ของ svc11

ดังนั้นการกำหนดค่าควรเป็นดังนี้:

นี่คือ 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

นี่คือ 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

ตั้งแต่เขียน 1.18 (ข้อมูลจำเพาะ 3.5) คุณสามารถแทนที่เครือข่ายเริ่มต้นโดยใช้ชื่อที่กำหนดเองของคุณเองสำหรับไฟล์เขียน YAML ทั้งหมดที่คุณต้องการ มันง่ายเหมือนการต่อท้ายสิ่งต่อไปนี้:

networks:
  default:
    name: my-app

ข้างต้นจะถือว่าคุณได้versionตั้งค่าเป็น3.5(หรือสูงกว่าหากไม่ได้คัดค้านใน 4+)

คำตอบอื่น ๆ ก็เหมือนกัน นี่เป็นบทสรุปที่ง่าย


2

ฉันจะให้แน่ใจว่าคอนเทนเนอร์ทั้งหมดจะdocker-compose'ไปยังเครือข่ายเดียวกันโดยเขียนไว้ในเวลาเดียวกันโดยใช้:

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

ที่จะอนุญาตให้ฉันตัวอย่างเพื่อสร้างหนึ่งlinkหรือdepends_onจากภาชนะด้านหน้าหนึ่งไปยังหนึ่งภาชนะ API?
Jivan

จริงเมื่อฉันทำในสิ่งที่คุณแนะนำตอบกลับนักเทียบท่า-เขียนอย่างใดอย่างหนึ่งbuild path ~/front/api either does not exist or is not accessibleหรือมีวิธีอื่น ๆbuild path ~/api/front either does not exist or is not accessible
Jivan

1
หากคุณกำลังเขียนพวกเขาในเวลาเดียวกันคุณไม่จำเป็นต้อง เครือข่ายจะถูกสร้างขึ้นด้วยคอนเทนเนอร์ทั้งหมดของคุณบนเครือข่ายพวกเขาทั้งหมดจะสามารถสื่อสารผ่านชื่อบริการจากไฟล์เขียน ( ไม่ใช่ชื่อคอนเทนเนอร์)
Nauraushaun

มันอาจจะง่ายกว่าถ้าไฟล์เขียนสองไฟล์อยู่ในโฟลเดอร์เดียวกัน แต่ฉันไม่คิดว่ามันจำเป็น - ฉันคิดว่ามันควรจะใช้ได้เหมือนกัน
Nauraushaun

2
วิธีการแก้ปัญหานี้ไม่ทำงานดูความคิดเห็นของฉันในหัวข้อนี้: github.com/docker/compose/issues/3530#issuecomment-222490501
johnharris85

2

UPDATE: ณ ไฟล์เขียนเวอร์ชัน 3.5:

ฉันเจอปัญหาที่คล้ายกันและฉันแก้ไขมันโดยการเพิ่มการเปลี่ยนแปลงเล็กน้อยในหนึ่งในโครงการนักเทียบท่า-compose.yml ของฉัน

ยกตัวอย่างเช่นเรามีสองของ API และscoring API ต้องส่งคำขอไปยังAPI เพื่อประมวลผลคำขออินพุต ในการที่จะทำเช่นนั้นพวกเขาทั้งสองควรจะแบ่งปันเครือข่ายเดียวกันnerScoringner

หมายเหตุ:ทุกคอนเทนเนอร์มีเครือข่ายของตัวเองซึ่งถูกสร้างขึ้นโดยอัตโนมัติในขณะที่เรียกใช้แอพภายในตัวเชื่อมต่อ ตัวอย่างเช่นเครือข่าย ner API จะถูกสร้างขึ้นเหมือนner_defaultและเครือข่ายการให้คะแนน API scoring defaultจะตั้งชื่อเป็น โซลูชันนี้จะใช้งานได้กับเวอร์ชัน: '3'

ในสถานการณ์ข้างต้น API ที่ให้คะแนนของฉันต้องการสื่อสารกับ ner api จากนั้นฉันจะเพิ่มบรรทัดต่อไปนี้ ซึ่งหมายความว่าเมื่อใดก็ตามที่ฉันสร้างที่เก็บสำหรับ ner api มันจะถูกเพิ่มไปยังเครือข่ายให้คะแนนอัตโนมัติ

networks:
  default:
      external:
        name: scoring_default

ner / นักเทียบท่า-compose.yml

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

networks:
  default:
      external:
        name: scoring_default

เกณฑ์การให้คะแนน / นักเทียบท่า-compose.yml

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

เราสามารถเห็นสิ่งนี้ว่าคอนเทนเนอร์ข้างต้นตอนนี้เป็นส่วนหนึ่งของเครือข่ายเดียวกันที่เรียกว่าการ 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": ""
    },
    ...
}

1

คุณสามารถเพิ่มไฟล์ในโครงการของคุณทั้งหมดที่มี.envCOMPOSE_PROJECT_NAME=somename

COMPOSE_PROJECT_NAMEจะแทนที่ส่วนนำหน้าที่ใช้เพื่อตั้งชื่อทรัพยากรเช่นโครงการทั้งหมดของคุณจะใช้somename_defaultเป็นเครือข่ายทำให้เป็นไปได้ที่บริการต่างๆจะสื่อสารซึ่งกันและกันเหมือนอยู่ในโครงการเดียวกัน

หมายเหตุ: คุณจะได้รับคำเตือนเกี่ยวกับคอนเทนเนอร์ "orphaned" ที่สร้างจากโครงการอื่น


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

สำหรับการใช้เครือข่ายนักเขียนที่มีนักเทียบท่าอื่นคุณเพียงแค่ทำสิ่งเหล่านี้ (เพื่อแบ่งปันเครือข่ายระหว่างนักเขียนที่มีนักเทียบท่า):

  1. เรียกใช้โครงการนักเทียบท่าแรกที่เขียนโดย up -d
  2. ค้นหาชื่อเครือข่ายของนักเทียบท่าแรกที่เขียนโดย: docker network ls(ประกอบด้วยชื่อของโครงการไดเรกทอรีราก)
  3. จากนั้นใช้ชื่อนั้นตามโครงสร้างนี้ที่ด้านล่างในไฟล์เขียนนักเทียบท่าที่สอง

นักเทียบท่าที่สอง-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

0

อีกทางเลือกหนึ่งคือเรียกใช้โมดูลแรกโดยใช้ 'นักเทียบท่าเขียน' ตรวจสอบ IP ที่เกี่ยวข้องกับโมดูลและเชื่อมต่อโมดูลที่สองกับเน็ตก่อนหน้าเช่นภายนอกและชี้ IP ภายใน

ตัวอย่าง app1 - เครือข่ายใหม่ที่สร้างขึ้นในสายการบริการทำเครื่องหมายเป็นภายนอก: จริงที่ด้านล่าง app2 - ระบุ "เครือข่ายใหม่" ที่สร้างขึ้นโดย app1 เมื่อขึ้นไปทำเครื่องหมายเป็นภายนอก: จริงที่ด้านล่างและตั้งค่าในการกำหนดค่า เพื่อเชื่อมต่อ, ip ที่ app1 มีในเน็ตนี้

ด้วยสิ่งนี้คุณควรจะสามารถพูดคุยกันได้

* วิธีนี้ใช้สำหรับการทดสอบเฉพาะจุดเพื่อไม่ทำการกำหนดค่าที่ซับซ้อนมากเกินไป ** ฉันรู้ว่าเป็น 'วิธีการแก้ไข' แต่ใช้งานได้สำหรับฉันและฉันคิดว่ามันง่ายมากที่ผู้อื่นสามารถใช้ประโยชน์จากสิ่งนี้ได้


0

ถ้าคุณคือ

  • พยายามสื่อสารระหว่างสองคอนเทนเนอร์จากโปรเจ็กต์นักเทียบท่าที่แตกต่างกันและไม่ต้องการใช้เครือข่ายเดียวกัน (เพราะสมมติว่าพวกเขาจะมีคอนเทนเนอร์ PostgreSQL หรือ Redis บนพอร์ตเดียวกันและคุณไม่ต้องการเปลี่ยนพอร์ตเหล่านี้และไม่ใช้มัน ที่เครือข่ายเดียวกัน)
  • การพัฒนาในประเทศและต้องการเลียนแบบการสื่อสารระหว่างนักเทียบท่าสองคนเขียนโครงการ
  • รันสองนักเทียบท่าเขียนโครงการบน localhost
  • การพัฒนาแอพ Django โดยเฉพาะหรือ Django Rest Framework (drf) API และเรียกใช้แอพภายในคอนเทนเนอร์บนพอร์ตที่เปิดเผย
  • รับConnection refusedในขณะที่พยายามสื่อสารระหว่างสองตู้คอนเทนเนอร์

และคุณต้องการที่จะ

  • คอนเทนเนอร์api_aสื่อสารกับapi_b(หรือกลับกัน) โดยไม่มี "เครือข่ายนักเทียบท่า" เดียวกัน

(ตัวอย่างด้านล่าง)

คุณสามารถใช้ "โฮสต์" ของคอนเทนเนอร์ที่สองเป็น IP ของคอมพิวเตอร์และพอร์ตที่แมปจากภายในคอนเทนเนอร์ Docker คุณสามารถรับ IP ของคอมพิวเตอร์ของคุณด้วยสคริปต์นี้ (จาก: การค้นหาที่อยู่ IP ในเครื่องโดยใช้ Stythl ของ 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

ตัวอย่าง:

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

ในapi_aคอนเทนเนอร์ที่คุณใช้งานแอพ Django: manage.py runserver 0.0.0.0:8000

และนักเทียบท่าที่สอง - compose.yml จากโครงการอื่น ๆ :

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

ในapi_bคอนเทนเนอร์ที่คุณใช้งานแอพ Django: manage.py runserver 0.0.0.0:8001

และพยายามเชื่อมต่อจากคอนเทนเนอร์api_aไปยังapi_bURL ของapi_bคอนเทนเนอร์จะเป็น: http://<get_ip_from_script_above>:8001/

มันจะมีค่ามากเป็นพิเศษหากคุณใช้มากกว่าสอง (สามหรือมากกว่า) นักแต่งเพลงประกอบโครงการและมันยากที่จะให้เครือข่ายร่วมกันสำหรับทั้งหมด - ดีแก้ปัญหาและวิธีแก้ปัญหา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.