วิธีสื่อสารระหว่าง Docker container ผ่าน“ hostname”


91

ฉันวางแผนที่จะแยกเซิร์ฟเวอร์ monolthic ของฉันออกเป็นคอนเทนเนอร์ Docker ขนาดเล็กจำนวนมาก แต่ยังไม่พบวิธีแก้ปัญหาที่ดีสำหรับ "การสื่อสารระหว่างคอนเทนเนอร์" นี่คือสถานการณ์เป้าหมายของฉัน:

สถานการณ์เป้าหมาย

ฉันรู้วิธีเชื่อมโยงคอนเทนเนอร์เข้าด้วยกันและวิธีแสดงพอร์ต แต่ไม่มีวิธีใดที่ฉันพอใจ

มีวิธีใดในการสื่อสารผ่านชื่อโฮสต์ (ชื่อคอนเทนเนอร์) ระหว่างคอนเทนเนอร์เช่นเดียวกับในเครือข่ายเซิร์ฟเวอร์แบบเดิมหรือไม่


ฉันเพิ่งเขียนเอกสารเพื่อทำสิ่งที่คุณกำลังมองหา โดยพื้นฐานแล้วจะบันทึกวิธีการติดตั้งหลายคอนเทนเนอร์ (หนึ่งต่อกระบวนการ) และทำให้รวมเข้าด้วยกัน "การสื่อสารระหว่างตู้คอนเทนเนอร์" เป็นส่วนหนึ่งของเกม
xuhdev

ฉันเพิ่งพบบล็อก Tumtumและสะดุดวรรคนี้ในเอกสารประกอบเทียบท่าอย่างเป็นทางการ ฉันไม่รู้ว่าฉันพลาดย่อหน้านี้มาตลอดหรือว่ามันถูกเพิ่มเข้ามาใหม่ แต่นั่นควรจะเป็นสิ่งที่ฉันต้องการ :)
Patrick Gotthard

นักเทียบท่า 1.10 หมดและการเชื่อมต่อนักเทียบท่านั้นยอดเยี่ยมมาก ( github.com/docker/docker/blob/… ) ดูคำตอบที่แก้ไขของฉันด้านล่าง
VonC

2
ฉันคิดว่าคุณควรจะลองนักเทียบท่า-เขียน ทำงานได้ดีมาก
Suhas Chikkanna

คำตอบ:


27

แก้ไข: หลังจาก Docker 1.9 docker networkคำสั่ง (ดูด้านล่าง https://stackoverflow.com/a/35184695/977939 ) เป็นวิธีที่แนะนำเพื่อให้บรรลุสิ่งนี้


วิธีแก้ปัญหาของฉันคือตั้งค่า dnsmasq บนโฮสต์ให้มีการอัปเดตระเบียน DNS โดยอัตโนมัติ: ระเบียน "A" จะมีชื่อของคอนเทนเนอร์และชี้ไปที่ที่อยู่ IP ของคอนเทนเนอร์โดยอัตโนมัติ (ทุกๆ 10 วินาที) สคริปต์การปรับปรุงอัตโนมัติจะถูกวางที่นี่:

#!/bin/bash

# 10 seconds interval time by default
INTERVAL=${INTERVAL:-10}

# dnsmasq config directory
DNSMASQ_CONFIG=${DNSMASQ_CONFIG:-.}

# commands used in this script
DOCKER=${DOCKER:-docker}
SLEEP=${SLEEP:-sleep}
TAIL=${TAIL:-tail}

declare -A service_map

while true
do
    changed=false
    while read line
    do
        name=${line##* }
        ip=$(${DOCKER} inspect --format '{{.NetworkSettings.IPAddress}}' $name)
        if [ -z ${service_map[$name]} ] || [ ${service_map[$name]} != $ip ] # IP addr changed
        then
            service_map[$name]=$ip
            # write to file
            echo $name has a new IP Address $ip >&2
            echo "host-record=$name,$ip"  > "${DNSMASQ_CONFIG}/docker-$name"
            changed=true
        fi
    done < <(${DOCKER} ps | ${TAIL} -n +2)

    # a change of IP address occured, restart dnsmasq
    if [ $changed = true ]
    then
        systemctl restart dnsmasq
    fi

    ${SLEEP} $INTERVAL
done

ตรวจสอบให้แน่ใจบริการ dnsmasq docker0ของคุณที่มีอยู่ใน จากนั้นเริ่มคอนเทนเนอร์ของคุณ--dns HOST_ADDRESSเพื่อใช้บริการ mini dns นี้

อ้างอิง: http://docs.blowb.org/setup-host/dnsmasq.html


มันดูน่าสนใจและยืดหยุ่นกว่าคำตอบ - ลิงค์ของฉันมาก +1
VonC

@VonC ดูเหมือนว่า libnetwork ใหม่อาจแทนที่วิธีแก้ปัญหานี้ มาดูกันว่า
xuhdev

@xuhdev ฉันจะตั้งค่า dnsmasq เช่นเดียวกับในdocs.blowb.org/setup-host/dnsmasq.html แต่ฉันประสบปัญหาเมื่อใช้ขุดจากคอนเทนเนอร์นักเทียบท่าหมดเวลา แต่การ ping ไปยัง ip อินเตอร์เฟส docker0 ของโฮสต์ใช้งานได้ ขุดด้วย ip docker0 เดียวกันจากโฮสต์นักเทียบท่าทำงาน คุณมีความสุขหรือไม่?
เสาร์

1
@Satheesh อาจเป็นการตั้งค่าไฟร์วอลล์ของคุณที่ป้องกันไม่ให้คอนเทนเนอร์ของคุณสืบค้น DNS จากโฮสต์?
xuhdev

@xuhdev ขอบคุณมันเป็น firewalld ในเครื่องโฮสต์ของฉันซึ่งทำให้เกิดปัญหา เมื่อฉันก้มลง firewalld คอนเทนเนอร์ของฉันจะสื่อสารกับ dnsmasq บนโฮสต์
Satheesh

209

คุณลักษณะเครือข่ายใหม่ช่วยให้คุณสามารถเชื่อมต่อกับคอนเทนเนอร์ตามชื่อดังนั้นหากคุณสร้างเครือข่ายใหม่คอนเทนเนอร์ใด ๆ ที่เชื่อมต่อกับเครือข่ายนั้นจะสามารถเข้าถึงคอนเทนเนอร์อื่น ๆ ได้โดยใช้ชื่อ ตัวอย่าง:

1) สร้างเครือข่ายใหม่

$ docker network create <network-name>       

2) เชื่อมต่อคอนเทนเนอร์กับเครือข่าย

$ docker run --net=<network-name> ...

หรือ

$ docker network connect <network-name> <container-name>

3) Ping container ตามชื่อ

docker exec -ti <container-name-A> ping <container-name-B> 

64 bytes from c1 (172.18.0.4): icmp_seq=1 ttl=64 time=0.137 ms
64 bytes from c1 (172.18.0.4): icmp_seq=2 ttl=64 time=0.073 ms
64 bytes from c1 (172.18.0.4): icmp_seq=3 ttl=64 time=0.074 ms
64 bytes from c1 (172.18.0.4): icmp_seq=4 ttl=64 time=0.074 ms

ดู ส่วนนี้ของเอกสาร

หมายเหตุ:ไม่เหมือนแบบเดิมlinksเครือข่ายใหม่จะไม่สร้างตัวแปรสภาพแวดล้อมหรือแชร์ตัวแปรสภาพแวดล้อมกับคอนเทนเนอร์อื่น

ปัจจุบันคุณลักษณะนี้ไม่รองรับนามแฝง


4
ใช้งานได้ดี ทำไมเครือข่ายเริ่มต้นไม่เปิดใช้งานตามค่าเริ่มต้น ??
Stéphane

ส่วนที่ชัดเจนน้อยกว่าคือคุณต้องรีสตาร์ทแอปที่ทำงานในคอนเทนเนอร์อื่น คอนเทนเนอร์ A จะทำให้แอปที่ทำงานในคอนเทนเนอร์ B เริ่มต้นใหม่ได้อย่างไร เห็นได้ชัดว่าจำเป็นต้องมีรถบัสสื่อสารบางประเภท สิ่งที่สำคัญที่สุดของฉันคือการใช้ Redis สำหรับการส่งสัญญาณและการสื่อสารระหว่างคอนเทนเนอร์ .. ดังนั้นคอนเทนเนอร์ทั้งหมดสมัครสมาชิก redis chanel และจะมีการพูดคุย ... เกี่ยวกับการเปลี่ยนแปลงของพอร์ตที่เผยแพร่ในนักเทียบท่า ไฟล์ .yml ต้องการไฟล์ที่สมบูรณ์docker-compose down,up,restart?
eigenfield

นี่คือสิ่งที่ฉันมองหามาตลอดทั้งวัน! ไม่ทราบว่าคุณสามารถอ้างถึงโหนดเครือข่ายโดยใช้ชื่อคอนเทนเนอร์ / id ขอขอบคุณ!
elliotwesoff

1
@ Stéphaneมันถูกปิดใช้งานในbridgeเครือข่ายเริ่มต้นเนื่องจากความเข้ากันได้แบบย้อนกลับ แต่ใช่ฉันเห็นด้วยควรเปิดใช้งานโดยค่าเริ่มต้นอย่างแน่นอน!
helmesjo

15

นั่นควรเป็นสิ่งที่--linkมีไว้สำหรับอย่างน้อยก็สำหรับส่วนชื่อโฮสต์
ด้วยDocker 1.10 และ PR 19242นั่นจะเป็น:

docker network create --net-alias=[]: Add network-scoped alias for the container

(ดูหัวข้อสุดท้ายด้านล่าง)

นั่นคือสิ่งที่อัปเดต/etc/hostsรายละเอียดไฟล์

นอกเหนือจากตัวแปรสภาพแวดล้อม Docker ยังเพิ่มรายการโฮสต์สำหรับคอนเทนเนอร์ต้นทางไปยัง/etc/hostsไฟล์

ตัวอย่างเช่นเปิดเซิร์ฟเวอร์ LDAP:

docker run -t  --name openldap -d -p 389:389 larrycai/openldap

และกำหนดอิมเมจเพื่อทดสอบเซิร์ฟเวอร์ LDAP นั้น:

FROM ubuntu
RUN apt-get -y install ldap-utils
RUN touch /root/.bash_aliases
RUN echo "alias lds='ldapsearch -H ldap://internalopenldap -LL -b
ou=Users,dc=openstack,dc=org -D cn=admin,dc=openstack,dc=org -w
password'" > /root/.bash_aliases
ENTRYPOINT bash

คุณสามารถแสดง ' openldap' container as ' internalopenldap' ภายในภาพทดสอบด้วย --link:

 docker run -it --rm --name ldp --link openldap:internalopenldap ldaptest

จากนั้นหากคุณพิมพ์ 'lds' นามแฝงนั้นจะใช้งานได้:

ldapsearch -H ldap://internalopenldap ...

ที่จะส่งคืนผู้คน เข้าถึงความหมายinternalopenldapได้อย่างถูกต้องจากldaptestภาพ


แน่นอนว่านักเทียบท่า 1.7 จะเพิ่มlibnetworkซึ่งให้การใช้งาน Go แบบเนทีฟสำหรับการเชื่อมต่อคอนเทนเนอร์ ดูโพสต์บล็อก
ได้นำเสนอสถาปัตยกรรมที่สมบูรณ์ยิ่งขึ้นด้วย Container Network Model (CNM)

https://blog.docker.com/media/2015/04/cnm-model.jpg

ซึ่งจะอัปเดต Docker CLI ด้วยคำสั่ง "เครือข่าย" ใหม่และบันทึกวิธีใช้-netแฟล็ก "" เพื่อกำหนดคอนเทนเนอร์ให้กับเครือข่าย


นักเทียบท่า 1.10 มีส่วนใหม่นามแฝงขอบเขตเครือข่ายซึ่งตอนนี้ได้รับการบันทึกอย่างเป็นทางการในnetwork connect :

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

ดำเนินการต่อด้วยตัวอย่างข้างต้นสร้างคอนเทนเนอร์อื่นisolated_nwด้วยนามแฝงเครือข่าย

$ docker run --net=isolated_nw -itd --name=container6 -alias app busybox
8ebe6767c1e0361f27433090060b33200aac054a68476c3be87ef4005eb1df17

--alias=[]         

เพิ่มนามแฝงที่กำหนดขอบเขตเครือข่ายสำหรับคอนเทนเนอร์

คุณสามารถใช้--linkตัวเลือกเพื่อเชื่อมโยงคอนเทนเนอร์อื่นกับนามแฝงที่ต้องการ

คุณสามารถหยุดชั่วคราวรีสตาร์ทและหยุดคอนเทนเนอร์ที่เชื่อมต่อกับเครือข่ายได้ คอนเทนเนอร์ที่หยุดชั่วคราวยังคงเชื่อมต่ออยู่และสามารถเปิดเผยได้โดยการตรวจสอบเครือข่าย เมื่อคอนเทนเนอร์หยุดทำงานคอนเทนเนอร์จะไม่ปรากฏบนเครือข่ายจนกว่าคุณจะรีสตาร์ท

หากระบุไว้ที่อยู่ IP ของคอนเทนเนอร์จะถูกนำไปใช้ใหม่เมื่อรีสตาร์ทคอนเทนเนอร์ที่หยุดทำงาน หากไม่มีที่อยู่ IP อีกต่อไปคอนเทนเนอร์จะไม่สามารถเริ่มทำงานได้

วิธีหนึ่งในการรับประกันว่าที่อยู่ IP พร้อมใช้งานคือการระบุ--ip-rangeเมื่อสร้างเครือข่ายและเลือกที่อยู่ IP แบบคงที่จากนอกช่วงนั้น เพื่อให้แน่ใจว่าที่อยู่ IP จะไม่ถูกกำหนดให้กับคอนเทนเนอร์อื่นในขณะที่คอนเทนเนอร์นี้ไม่ได้อยู่บนเครือข่าย

$ docker network create --subnet 172.20.0.0/16 --ip-range 172.20.240.0/20 multi-host-network

$ docker network connect --ip 172.20.128.2 multi-host-network container2
$ docker network connect --link container1:c1 multi-host-network container2

3
ปัญหาของ --link คือคุณไม่สามารถรีสตาร์ทคอนเทนเนอร์ได้โดยไม่ต้องรีสตาร์ทคอนเทนเนอร์ที่ลิงก์ด้วย เมื่อคุณดูกราฟิกของฉันการรีสตาร์ทคอนเทนเนอร์ MySQL จะส่งผลให้คอนเทนเนอร์อื่น ๆ รีสตาร์ท
Patrick Gotthard

3

แก้ไข : ไม่มีเลือดออกอีกต่อไป: http://blog.docker.com/2016/02/docker-1-10/

คำตอบเดิม
ฉันต่อสู้กับมันทั้งคืน หากคุณไม่กลัวขอบเลือดออกเวอร์ชันล่าสุดของDocker engineและDocker จะเขียนขึ้นทั้ง libnetwork

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

นี่คือไฟล์ตัวอย่าง

version: "2"
services:
  router:
    build: services/router/
    ports:
      - "8080:8080"
  auth:
    build: services/auth/
  todo:
    build: services/todo/
  data:
    build: services/data/

และข้อมูลอ้างอิงสำหรับไฟล์เขียนเวอร์ชันใหม่นี้: https://github.com/docker/compose/blob/1.6.0-rc1/docs/networking.md


1

เท่าที่ฉันรู้การใช้ Docker เพียงอย่างเดียวนั้นไม่สามารถทำได้ คุณต้องมี DNS เพื่อแมปคอนเทนเนอร์ ip: s กับชื่อโฮสต์

หากคุณต้องการแก้ปัญหานอกกรอบ ทางออกหนึ่งคือการใช้ตัวอย่างเช่นKontena มาพร้อมกับเทคโนโลยีการซ้อนทับเครือข่ายจาก Weave และเทคโนโลยีนี้ใช้เพื่อสร้างเครือข่าย LAN ส่วนตัวเสมือนสำหรับแต่ละบริการและทุกบริการสามารถเข้าถึงservice_name.kontena.local-addressได้

นี่คือตัวอย่างง่ายๆของไฟล์ YAML ของแอปพลิเคชัน Wordpress ที่บริการ Wordpress เชื่อมต่อกับเซิร์ฟเวอร์ MySQL ด้วยที่อยู่ wordpress-mysql.kontena.local:

wordpress:                                                                         
  image: wordpress:4.1                                                             
  stateful: true                                                                   
  ports:                                                                           
    - 80:80                                                                      
  links:                                                                           
    - mysql:wordpress-mysql                                                        
  environment:                                                                     
    - WORDPRESS_DB_HOST=wordpress-mysql.kontena.local                              
    - WORDPRESS_DB_PASSWORD=secret                                                 
mysql:                                                                             
  image: mariadb:5.5                                                               
  stateful: true                                                                   
  environment:                                                                     
    - MYSQL_ROOT_PASSWORD=secret
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.