Acceda al contenedor docker desde el host utilizando el nombre de los contenedores


Estoy desarrollando un servicio y usando allí docker compose para girar servicios como postgres, redis, elasticsearch. Tengo una aplicación web que se basa en RubyOnRails y escribe y lee de todos esos servicios.

Aquí está mi docker-compose.yml

version: '2'

services:
  redis:
    image: redis:2.8
    networks:
      - frontapp

  elasticsearch:
    image: elasticsearch:2.2
    networks:
      - frontapp

  postgres:  
    image: postgres:9.5
    environment:
      POSTGRES_USER: elephant
      POSTGRES_PASSWORD: smarty_pants
      POSTGRES_DB: elephant
    volumes:
      - /var/lib/postgresql/data
    networks:
      - frontapp

networks:
  frontapp:
    driver: bridge

Y puedo hacer ping a contenedores dentro de esta red

$ docker-compose run redis /bin/bash
root@777501e06c03:/data# ping postgres
PING postgres (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: icmp_seq=0 ttl=64 time=0.346 ms
64 bytes from 172.20.0.2: icmp_seq=1 ttl=64 time=0.047 ms
...

Hasta ahora todo bien. Ahora quiero ejecutar la aplicación ruby on rails en mi máquina host pero poder acceder a la instancia de postgres con url como postgresql://username:password@postgres/database actualmente que no es posible

$ ping postgres
ping: unknown host postgres

Puedo ver mi red en docker

$ docker network ls
NETWORK ID          NAME                DRIVER
ac394b85ce09        bridge              bridge              
0189d7e86b33        elephant_default    bridge              
7e00c70bde3b        elephant_frontapp   bridge              
a648554a72fa        host                host                
4ad9f0f41b36        none                null 

Y puedo ver una interfaz con él

$ ifconfig 
br-0189d7e86b33 Link encap:Ethernet  HWaddr 02:42:76:72:bb:c2  
          inet addr:172.18.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:76ff:fe72:bbc2/64 Scope:Link
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:36 errors:0 dropped:0 overruns:0 frame:0
          TX packets:60 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:2000 (2.0 KB)  TX bytes:8792 (8.7 KB)

br-7e00c70bde3b Link encap:Ethernet  HWaddr 02:42:e7:d1:fe:29  
          inet addr:172.20.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:e7ff:fed1:fe29/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1584 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1597 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:407137 (407.1 KB)  TX bytes:292299 (292.2 KB)
...

Pero no estoy seguro de qué debo hacer a continuación. Traté de jugar un poco con /etc/resolv.conf, principalmente con nameserver directiva, pero eso no tuvo ningún efecto.

Agradecería cualquier ayuda de sugerencias sobre cómo configurar esta configuración correctamente.

UPDATE

Después de navegar a través de los recursos de Internet logré asignar direcciones IP estáticas a las cajas. Para ahora es suficiente para mí continuar el desarrollo. Aquí está mi corriente docker-compose.yml

version: '2'

services:
  redis:
    image: redis:2.8
    networks:
      frontapp:
        ipv4_address: 172.25.0.11

  elasticsearch:
    image: elasticsearch:2.2
    networks:
      frontapp:
        ipv4_address: 172.25.0.12

  postgres:  
    image: postgres:9.5
    environment:
      POSTGRES_USER: elephant
      POSTGRES_PASSWORD: smarty_pants
      POSTGRES_DB: elephant
    volumes:
      - /var/lib/postgresql/data
    networks:
      frontapp:
        ipv4_address: 172.25.0.10

networks:
  frontapp:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.25.0.0/16
          gateway: 172.25.0.1
Author: Max, 2016-05-15

5 answers

Hay una aplicación de código abierto que resuelve este problema, se llama Servidor Proxy DNS

Es un servidor DNS que resuelve los nombres de host de los contenedores, si no se pudo encontrar un nombre de host que coincida, entonces soluciónelo desde Internet también

Inicie el servidor DNS

$ docker run --hostname dns.mageddo --name dns-proxy-server -p 5380:5380 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /etc/resolv.conf:/etc/resolv.conf \
defreitas/dns-proxy-server

Se establecerá como DNS predeterminado automáticamente (y se recuperará al original cuando se detenga)

Inicie su contenedor para la prueba

docker-compose up

Docker-compose.yml

version: '2'
services:
  redis:
    container_name: redis
    image: redis:2.8
    hostname: redis.dev.intranet
    network_mode: bridge # that way he can solve others containers names even inside, solve elasticsearch, for example
  elasticsearch:
    container_name: elasticsearch
    image: elasticsearch:2.2
    hostname: elasticsearch.dev.intranet

Ahora resolver su contenedores hostnames

De host

$ nslookup redis.dev.intranet
Server:     172.17.0.2
Address:    172.17.0.2#53

Non-authoritative answer:
Name:   redis.dev.intranet
Address: 172.21.0.3

De otro contenedor

$ docker exec -it redis ping elasticsearch.dev.intranet
PING elasticsearch.dev.intranet (172.21.0.2): 56 data bytes

También resuelve nombres de hosts de Internet

$ nslookup google.com
Server:     172.17.0.2
Address:    172.17.0.2#53

Non-authoritative answer:
Name:   google.com
Address: 216.58.202.78
 13
Author: deFreitas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-26 14:13:42

El nombre de host del contenedor docker no se puede ver desde fuera. Lo que puede hacer es asignar un nombre al contenedor y acceder al contenedor a través del nombre. Si enlaza 2 contenedores digamos container1 y container2 entonces docker se encarga de escribir la IP y el nombre de host de container2 en el container1. Sin embargo, en su caso, su aplicación se está ejecutando en el hostmachine.

O

Conoce la IP del contenedor. Así que en el / etc / hosts de su máquina host puede agregar $IP host hostanameof container

 2
Author: Aditya C S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-15 19:16:32

Si solo está utilizando la configuración de docker-compose localmente, podría asignar los puertos de sus contenedores a su host con

elasticsearch:
  image: elasticsearch:2.2
  ports:
    - 9300:9300
    - 9200:9200

Luego use localhost:9300 (o 9200 dependiendo del protocolo) desde su aplicación web para acceder a Elasticsearch.

Una solución más compleja es ejecutar su propio dns que resuelva los nombres de los contenedores. Creo que esta solución está mucho más cerca de lo que estás pidiendo. Previsiblemente he usado skydns al ejecutar kubernetes localmente.

Hay algunas opciones ahi. Echa un vistazo a https://github.com/gliderlabs/registrator y https://github.com/jderusse/docker-dns-gen. No lo probé, pero podría asignar el puerto dns a su host de la misma manera que con los puertos elásticos en el ejemplo anterior y luego agregar localhost a su resolución.conf para poder resolver los nombres de los contenedores desde el host.

 2
Author: Johan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-14 09:36:27

Hay dos soluciones (excepto /etc/hosts) describe aquí y aquí

Escribí mi propia solución en Python y la implementé como servicio para proporcionar mapeo desde el nombre de host del contenedor a su IP. Aquí está: https://github.com/nicolai-budico/dockerhosts

Inicia dnsmasq con el parámetro --hostsdir=/var/run/docker-hosts y actualiza el archivo /var/run/docker-hosts/hosts cada vez que se cambia una lista de contenedores en ejecución. Una vez que se cambia el archivo /var/run/docker-hosts/hosts, dnsmasq actualiza automáticamente su asignación y el contenedor estará disponible por nombre de host en un segundo.

$ docker run -d --hostname=myapp.local.com --rm -it ubuntu:17.10
9af0b6a89feee747151007214b4e24b8ec7c9b2858badff6d584110bed45b740

$ nslookup myapp.local.com
Server:         127.0.0.53
Address:        127.0.0.53#53

Non-authoritative answer:
Name:   myapp.local.com
Address: 172.17.0.2

Hay scripts de instalación y desinstalación. Solo necesita permitir que su sistema interactúe con esta instancia de dnsmasq. Me registré en systemd-resuelto:

$ cat /etc/systemd/resolved.conf

[Resolve]
DNS=127.0.0.54
#FallbackDNS=
#Domains=
#LLMNR=yes
#MulticastDNS=yes
#DNSSEC=no
#Cache=yes
#DNSStubListener=udp
 2
Author: Nicolai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-08 14:47:33

Aditya es correcto. En su caso, lo más simple es codificar su nombre de host / mapeo de IP en /etc/hosts

El problema con este enfoque, sin embargo, es que no controla la dirección IP privada que tendrá su máquina postgres. La dirección IP cambiará cada vez que inicie un nuevo contenedor, por lo que deberá actualizar su archivo /etc/hosts.

Si eso es un problema, te recomendaría que leas esta publicación de blog que explica cómo hacer cumplir que un contenedor obtenga una IP específica dirección:

Https://xand.es/2016/05/09/docker-with-known-ip /

 1
Author: Christophe Schmitz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-16 03:56:40