Cách giao tiếp giữa các vùng chứa Docker qua “tên máy chủ”


91

Tôi dự định chia máy chủ đơn sắc của mình thành nhiều bộ chứa docker nhỏ nhưng vẫn chưa tìm ra giải pháp tốt cho "giao tiếp giữa các bộ chứa". Đây là kịch bản mục tiêu của tôi:

Kịch bản mục tiêu

Tôi biết cách liên kết các container với nhau và cách sắp xếp các cổng, nhưng không có giải pháp nào trong số này làm tôi hài lòng.

Có giải pháp nào để giao tiếp qua hostnames (tên vùng chứa) giữa các vùng chứa như trong mạng máy chủ truyền thống không?


Tôi đã viết một tài liệu gần đây làm chính xác những gì bạn đang tìm kiếm. Về cơ bản, nó ghi lại cách cài đặt nhiều vùng chứa (một vùng chứa cho mỗi quá trình) và làm cho chúng được tích hợp. "giao tiếp giữa các vùng chứa" là một phần của trò chơi .
xuhdev

Tôi vừa tìm thấy Blog Tumtum và tình cờ tìm thấy đoạn này trong tài liệu chính thức của Docker . Tôi không biết liệu tôi đã bỏ lỡ đoạn này tất cả các thời gian hoặc cho dù đó là mới được bổ sung nhưng đó phải là chính xác những gì tôi cần :)
Patrick Gotthard

docker 1.10 đã ra mắt và kết nối docker thật tuyệt vời ( github.com/docker/docker/blob/… ). Xem câu trả lời đã chỉnh sửa của tôi bên dưới
VonC

2
Tôi nghĩ bạn nên thử trình soạn nhạc . Hoạt động rất tốt.
Suhas Chikkanna

Câu trả lời:


27

Chỉnh sửa: Sau Docker 1.9, docker networklệnh (xem bên dưới https://stackoverflow.com/a/35184695/977939 ) là cách được khuyến nghị để đạt được điều này.


Giải pháp của tôi là thiết lập một dnsmasq trên máy chủ lưu trữ để bản ghi DNS tự động cập nhật: Bản ghi "A" có tên của các vùng chứa và tự động trỏ đến địa chỉ IP của các vùng chứa (cứ sau 10 giây). Tập lệnh cập nhật tự động được dán ở đây:

#!/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

Đảm bảo rằng dịch vụ dnsmasq của bạn có sẵn trên docker0. Sau đó, khởi động vùng chứa của bạn với --dns HOST_ADDRESSđể sử dụng dịch vụ dns mini này.

Tham khảo: http://docs.blowb.org/setup-host/dnsmasq.html


Điều đó có vẻ thú vị, linh hoạt hơn câu trả lời --link của tôi +1
VonC

@VonC có vẻ như libnetwork mới có thể thay thế cách giải quyết này. Hãy xem mặc dù.
xuhdev

@xuhdev Tôi thiết lập dnsmasq như trong docs.blowb.org/setup-host/dnsmasq.html . Nhưng tôi gặp phải vấn đề khi sử dụng đào từ thùng chứa docker, đã hết thời gian. Nhưng ping đến ip của giao diện docker0 máy chủ hoạt động. Cũng đào bằng ip docker0 tương tự từ docker host hoạt động. Bạn có bất kỳ sự kiện?
Satheesh

1
@Satheesh Có thể do cài đặt tường lửa của bạn ngăn vùng chứa của bạn truy vấn DNS từ máy chủ?
xuhdev

@xuhdev cảm ơn nó là firewalld trong máy chủ của tôi, đã gây ra sự cố. Khi tôi cúi firewalld, giao container của tôi với dnsmasq trên máy chủ
Satheesh

205

Tính năng mạng mới cho phép bạn kết nối với các vùng chứa theo tên của chúng, vì vậy nếu bạn tạo một mạng mới, bất kỳ vùng chứa nào được kết nối với mạng đó đều có thể đến các vùng chứa khác theo tên của chúng. Thí dụ:

1) Tạo mạng mới

$ docker network create <network-name>       

2) Kết nối vùng chứa với mạng

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

hoặc là

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

3) Ping container theo tên

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

Xem này phần của tài liệu;

Lưu ý: Không giống như kế thừa links, mạng mới sẽ không tạo các biến môi trường cũng như chia sẻ các biến môi trường với các vùng chứa khác.

Tính năng này hiện không hỗ trợ bí danh


4
Hoạt động tuyệt vời. Tại sao mạng mặc định không kích hoạt tính năng này theo mặc định ??
Stéphane

Phần ít rõ ràng hơn là bạn cần khởi động lại một ứng dụng đang chạy trong một vùng chứa khác. Vậy làm cách nào vùng chứa A có thể khiến một ứng dụng đang chạy trong vùng chứa B khởi động lại? Rõ ràng, dường như cần có một loại xe buýt truyền thông nào đó. Điều quan trọng nhất trong đầu tôi là sử dụng Redis để truyền tín hiệu và giao tiếp giữa các container .. Vì vậy, tất cả các container đăng ký kênh redis và tại đó họ sẽ nói chuyện ... Còn về những thay đổi trong các cổng đã xuất bản trong docker -omp .yml tệp yêu cầu hoàn chỉnh docker-compose down,up,restart?
eigenfield

đây chính xác là những gì tôi đã tìm kiếm cả ngày! không biết rằng bạn có thể tham chiếu đến một nút mạng bằng tên / id vùng chứa của nó. cảm ơn bạn!
elliotwesoff

1
@ Stéphane Nó của người khuyết tật trong mặc định bridgemạng vì tính tương thích ngược nhưng có, tôi đồng ý, nó nên chắc chắn được kích hoạt theo mặc định!
helmesjo,

15

Đó phải là những gì --linkdành cho , ít nhất là đối với phần tên máy chủ.
Với docker 1.10 và PR 19242 , đó sẽ là:

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

(xem phần cuối bên dưới)

Đó là những gì Cập nhật/etc/hosts chi tiết tệp

Ngoài các biến môi trường, Docker thêm một mục nhập máy chủ cho vùng chứa nguồn vào /etc/hoststệp.

Ví dụ: khởi chạy máy chủ LDAP:

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

Và xác định một hình ảnh để kiểm tra máy chủ 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

Bạn có thể hiển thị ' openldap' vùng chứa dưới dạng ' internalopenldap' trong hình ảnh thử nghiệm với - liên kết:

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

Sau đó, nếu bạn nhập 'lds', bí danh đó sẽ hoạt động:

ldapsearch -H ldap://internalopenldap ...

Điều đó sẽ trả lại mọi người. Ý nghĩa internalopenldapđạt được chính xác từ ldaptesthình ảnh.


Tất nhiên, docker 1.7 sẽ bổ sung libnetwork, cung cấp triển khai Go gốc để kết nối các vùng chứa. Xem bài đăng trên blog .
Nó giới thiệu một kiến ​​trúc hoàn chỉnh hơn, với Mô hình mạng vùng chứa (CNM)

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

Điều đó sẽ Cập nhật Docker CLI với các lệnh "mạng" mới và ghi lại cách -netcờ "" được sử dụng để gán vùng chứa cho mạng.


docker 1.10 có một phần mới Bí danh phạm vi mạng , hiện đã được ghi nhận chính thức trongnetwork connect :

Trong khi các liên kết cung cấp độ phân giải tên riêng được bản địa hóa trong vùng chứa, thì bí danh phạm vi mạng cung cấp cách để vùng chứa được phát hiện bằng tên thay thế bởi bất kỳ vùng chứa nào khác trong phạm vi của một mạng cụ thể.
Không giống như bí danh liên kết, được xác định bởi người tiêu dùng dịch vụ, bí danh trong phạm vi mạng được xác định bởi vùng chứa đang cung cấp dịch vụ cho mạng.

Tiếp tục với ví dụ trên, tạo một vùng chứa khác isolated_nwvới bí danh mạng.

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

--alias=[]         

Thêm bí danh phạm vi mạng cho vùng chứa

Bạn có thể sử dụng --linktùy chọn để liên kết vùng chứa khác với bí danh ưu tiên

Bạn có thể tạm dừng, khởi động lại và dừng các vùng chứa được kết nối với mạng. Các vùng chứa bị tạm dừng vẫn được kết nối và có thể được phát hiện khi kiểm tra mạng. Khi vùng chứa bị dừng, vùng chứa sẽ không xuất hiện trên mạng cho đến khi bạn khởi động lại.

Nếu được chỉ định, (các) địa chỉ IP của vùng chứa sẽ được áp dụng lại khi khởi động lại vùng chứa đã dừng. Nếu địa chỉ IP không còn nữa, vùng chứa không thể khởi động.

Một cách để đảm bảo rằng địa chỉ IP có sẵn là chỉ định --ip-rangekhi tạo mạng và chọn (các) địa chỉ IP tĩnh từ bên ngoài phạm vi đó. Điều này đảm bảo rằng địa chỉ IP không được cấp cho một vùng chứa khác trong khi vùng chứa này không có trên mạng.

$ 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
Vấn đề của --link là bạn không thể khởi động lại vùng chứa mà không khởi động lại vùng chứa được liên kết. Khi bạn nhìn vào đồ họa của tôi, việc khởi động lại vùng chứa MySQL sẽ dẫn đến một loạt các lần khởi động lại vùng chứa khác.
Patrick Gotthard

3

CHỈNH SỬA : Nó không còn chảy máu mép nữa: http://blog.docker.com/2016/02/docker-1-10/

Câu trả lời gốc
Tôi đã chiến đấu với nó cả đêm. Nếu bạn không sợ bị chảy máu, phiên bản mới nhất của công cụ DockerDocker soạn cả hai đều triển khai libnetwork.

Với tệp cấu hình phù hợp (cần được đặt trong phiên bản 2), bạn sẽ tạo ra các dịch vụ mà tất cả sẽ nhìn thấy nhau. Và, phần thưởng, bạn cũng có thể mở rộng quy mô chúng bằng docker-soạn (bạn có thể mở rộng bất kỳ dịch vụ nào bạn muốn mà không ràng buộc cổng trên máy chủ)

Đây là một tệp ví dụ

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

Và tài liệu tham khảo cho phiên bản mới của tệp soạn thảo này: https://github.com/docker/compose/blob/1.6.0-rc1/docs/networking.md


1

Theo như tôi biết, bằng cách chỉ sử dụng Docker, điều này là không thể. Bạn cần một số DNS để ánh xạ ip: s vùng chứa với tên máy chủ.

Nếu bạn muốn giải pháp ra khỏi hộp. Một giải pháp là sử dụng ví dụ Kontena . Nó đi kèm với công nghệ lớp phủ mạng từ Weave và công nghệ này được sử dụng để tạo mạng LAN riêng ảo cho từng dịch vụ và mọi dịch vụ đều có thể truy cập được service_name.kontena.local-address.

Đây là ví dụ đơn giản về tệp YAML của ứng dụng Wordpress trong đó dịch vụ Wordpress kết nối với máy chủ MySQL bằng địa chỉ 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
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.