Docker kapsayıcıları arasında "ana bilgisayar adı" aracılığıyla iletişim kurma


91

Monolthic sunucumu birçok küçük docker konteynerine bölmeyi planlıyorum, ancak henüz "konteynerler arası iletişim" için iyi bir çözüm bulamadım. Bu benim hedef senaryom:

Hedef senaryo

Kapları birbirine nasıl bağlayacağımı ve bağlantı noktalarını nasıl açığa çıkaracağımı biliyorum, ancak bu çözümlerin hiçbiri beni tatmin etmiyor.

Geleneksel bir sunucu ağında olduğu gibi kapsayıcılar arasında ana bilgisayar adları (kapsayıcı adları) aracılığıyla iletişim kurmanın herhangi bir çözümü var mı?


Son zamanlarda tam olarak aradığınızı yapan bir belge yazdım . Temel olarak birden çok konteynerin (işlem başına bir tane) nasıl kurulacağını ve bunların nasıl entegre edileceğini belgeler. "konteynerler arası iletişim" oyunun bir parçasıdır .
xuhdev

Tumtum Blogunu yeni buldum ve resmi Docker belgelerinde bu paragrafa rastladım . Bu paragrafı her zaman özledim mi yoksa yeni mi eklendi bilmiyorum ama tam olarak ihtiyacım olan şey bu olmalı :)
Patrick Gotthard

docker 1.10 çıktı ve docker bağlantısı harika ( github.com/docker/docker/blob/… ). Bkz aşağıda benim Düzenlenen cevabı
VonC

2
Bence docker-compose'u denemelisiniz . Çok iyi çalışıyor.
Suhas Chikkanna

Yanıtlar:


27

Düzenleme: Docker 1.9'dan sonra, docker networkkomut (aşağıya bakın https://stackoverflow.com/a/35184695/977939 ) bunu başarmanın önerilen yoludur.


Çözümüm, DNS kaydının otomatik olarak güncellenmesi için ana bilgisayarda bir dnsmasq kurmaktır: "A" kayıtları, kapsayıcıların adlarına sahiptir ve otomatik olarak kapsayıcıların IP adreslerini işaret eder (her 10 saniyede bir). Otomatik güncelleme komut burada yapıştırılır:

#!/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 hizmetinizin açık olduğundan emin olun docker0. Ardından, --dns HOST_ADDRESSbu mini dns hizmetini kullanmak için kapsayıcınızı ile başlatın .

Referans: http://docs.blowb.org/setup-host/dnsmasq.html


Bu ilginç ve -link cevabımdan çok daha dayanıklı görünüyor. +1
VonC

@VonC, yeni libnetwork bu geçici çözümün yerini alabilir gibi görünüyor. Yine de görelim.
xuhdev

@xuhdev docs.blowb.org/setup-host/dnsmasq.html'de olduğu gibi dnsmasq'ı kurdum . Ancak docker container'dan kazma kullanırken sorunlarla karşılaşıyorum, zaman aşımına uğradı. Ancak ana docker0 arabirimine ping işlemi ip çalışıyor. Ayrıca docker ana bilgisayar çalışmasından aynı docker0 ip ile kazın. Herhangi bir önerin var mı?
Satheesh

1
@Satheesh Belki de konteynerinizin ana bilgisayardan DNS sorgulamasını engelleyen güvenlik duvarı ayarlarınızdır?
xuhdev

@xuhdev teşekkürler, soruna neden olan ana makinemdeki güvenlik duvarı. Güvenlik duvarını
durdurduğumda

206

Yeni ağ özelliği, konteynerlere adlarına göre bağlanmanıza izin verir, böylece yeni bir ağ oluşturursanız, bu ağa bağlı herhangi bir konteyner diğer konteynerlere adlarına ulaşabilir. Misal:

1) Yeni ağ oluşturun

$ docker network create <network-name>       

2) Konteynerleri ağa bağlayın

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

veya

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

3) Konteynere ada göre ping atı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

Belgelerin bu bölümüne bakın ;

Not: farklı olarak eski linksyeni ağ olmayacak başka kaplarla çevre değişkenleri, ne de hisse ortam değişkenleri oluşturun.

Bu özellik şu anda takma adları desteklemiyor


4
Harika çalışıyor. Varsayılan ağ neden bunu varsayılan olarak etkinleştirmiyor?
Stéphane

Daha az belirgin olan kısım, farklı bir kapta çalışan bir uygulamayı yeniden başlatmanız gerektiğidir. Peki A kapsayıcısı, B kapsayıcısında çalışan bir uygulamayı yeniden başlatmak için nasıl yapabilir? Açıkça görülüyor ki bir tür iletişim veri yoluna ihtiyaç var. Aklımın başında, sinyalizasyon ve konteynerler arası iletişim için Redis kullanmak var .. Yani tüm konteynerler redis kanalına abone olurlar ve orada konuşacaklar ... Docker-compose'daki yayınlanmış portlardaki değişiklikler hakkında ne dersiniz? Tam bir .yml dosyası docker-compose down,up,restartmı gerekiyor?
eigenfield

bu tam olarak bütün gün aradığım şey! bir ağ düğümüne kapsayıcı adı / kimliği ile başvurabileceğinizi bilmiyordum. teşekkür ederim!
elliotwesoff

1
@ Stéphane Bu varsayılan engelli bridgeçünkü geriye dönük uyumluluk ağı ama evet, kabul ediyorum, o gerektiğini kesinlikle varsayılan olarak etkin!
helmesjo

15

Yani olması gerektiği neyi --linkiçindir hostname bölümü için en azından.
İle docker 1.10 ve PR 19242 , olurdu:

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

(aşağıdaki son bölüme bakın)

Dosya ayrıntılarını güncellemek/etc/hosts budur

Ortam değişkenlerine ek olarak Docker, /etc/hostsdosyaya kaynak kapsayıcı için bir ana bilgisayar girişi ekler .

Örneğin, bir LDAP sunucusu başlatın:

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

Ve bu LDAP sunucusunu test etmek için bir resim tanımlayın:

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

--Link ile test görüntüsündeki ' openldap' kapsayıcıyı ' internalopenldap' gösterebilirsiniz:

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

Ardından, 'lds' yazarsanız, bu takma ad çalışacaktır:

ldapsearch -H ldap://internalopenldap ...

Bu insanları geri döndürür. Anlam internalopenldap, ldaptestgörüntüden doğru bir şekilde elde edilir .


Elbette, libnetworkkapsayıcıları bağlamak için yerel bir Go uygulaması sağlayan docker 1.7 ekleyecektir . Blog gönderisine bakın .
Kapsayıcı Ağ Modeli (CNM) ile daha eksiksiz bir mimari sundu

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

Bu Docker CLI'yi yeni "ağ" komutlarıyla güncelleyecek ve " -net" bayrağının ağlara kapsayıcılar atamak için nasıl kullanıldığını belgeleyecektir .


docker 1.10 , şimdi resmi olarak şu belgelerde belgelenen yeni bir Ağ kapsamlı takma ad bölümüne sahiptir :network connect

Bağlantılar, bir kapsayıcı içinde yerelleştirilmiş özel ad çözümlemesi sağlarken, ağ kapsamlı takma ad, bir kapsayıcının belirli bir ağ kapsamındaki başka herhangi bir kap tarafından alternatif bir adla keşfedilmesi için bir yol sağlar.
Bir hizmetin tüketicisi tarafından tanımlanan bağlantı takma adından farklı olarak, ağ kapsamlı diğer ad, hizmeti ağa sunan kapsayıcı tarafından tanımlanır.

Yukarıdaki örnekten devam ederek, içinde isolated_nwbir ağ takma adıyla başka bir kapsayıcı oluşturun .

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

--alias=[]         

Kapsayıcı için ağ kapsamlı takma ad ekleyin

--linkBaşka bir kapsayıcıyı tercih edilen bir takma ada bağlamak için seçeneği kullanabilirsiniz.

Bir ağa bağlı kapsayıcıları duraklatabilir, yeniden başlatabilir ve durdurabilirsiniz. Duraklatılmış konteynerler bağlı kalır ve bir ağ incelemesi ile ortaya çıkarılabilir. Kapsayıcı durdurulduğunda, siz yeniden başlatana kadar ağda görünmez.

Belirtilirse, durdurulmuş bir konteyner yeniden başlatıldığında kapsayıcının IP adresi / adresleri yeniden uygulanır. IP adresi artık mevcut değilse, kapsayıcı başlatılamaz.

IP adresinin mevcut olduğunu garanti etmenin bir yolu --ip-range, ağı oluştururken bir belirtmek ve bu aralığın dışından statik IP adreslerini seçmektir. Bu, bu kapsayıcı ağda değilken IP adresinin başka bir kaba verilmemesini sağlar.

$ 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'in sorunu, bağlantılı kapsayıcıları da yeniden başlatmadan bir kapsayıcıyı yeniden başlatamamanızdır. Grafiğime baktığınızda, MySQL kapsayıcısının yeniden başlatılması, diğer kapsayıcı yeniden başlatmalarının artmasıyla sonuçlanacaktır.
Patrick Gotthard

3

DÜZENLEME : Artık kanayan bir kenar değil: http://blog.docker.com/2016/02/docker-1-10/

Orijinal Cevap
Bütün gece onunla savaştım. Kanayan uçtan korkmuyorsanız, Docker motorunun en son sürümü ve Docker, libnetwork'ü uygular.

Doğru yapılandırma dosyasıyla (sürüm 2'ye yerleştirilmesi gereken), birbirini görecek hizmetler oluşturacaksınız. Ve bonus, bunları docker-compose ile de ölçeklendirebilirsiniz (ana bilgisayardaki bağlantı noktasını bağlamayan istediğiniz herhangi bir hizmeti ölçekleyebilirsiniz)

İşte örnek bir dosya

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

Ve oluşturma dosyasının bu yeni sürümü için referans: https://github.com/docker/compose/blob/1.6.0-rc1/docs/networking.md


1

Bildiğim kadarıyla sadece Docker kullanarak bu mümkün değil. Kapsayıcı ip: lerini ana bilgisayar adlarına eşlemek için bazı DNS’lere ihtiyacınız vardır.

Kutunun dışında çözüm istiyorsanız. Bir çözüm, örneğin Kontena kullanmaktır . Weave'in ağ katmanı teknolojisi ile birlikte gelir ve bu teknoloji, her hizmet için sanal özel LAN ağları oluşturmak için kullanılır ve her hizmete erişim sağlanabilir service_name.kontena.local-address.

İşte Wordpress uygulamasının YAML dosyasının, Wordpress hizmetinin wordpress-mysql.kontena.local adresiyle MySQL sunucusuna bağlandığı basit bir örnek:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.