Artigo original: How to Get A Docker Container IP Address - Explained with Examples

O Docker fornece a capacidade e "empacotar" e executar uma aplicação em um ambiente relativamente isolado, chamado de contêiner.

Eu sei o que você está pensando – ah, não, outro artigo explicando o que é o Docker! A gente encontra isso em todo lugar agora!

docker-i-see

Mas não se preocupe. Pularemos a parte introdutória. O público alvo desse artigo já deve ter um conhecimento básico sobre o Docker e sobre contêineres.

Mas você já se perguntou sobre como obter o endereço IP de um contêiner do Docker?

Rede do Docker explicada


Primeiro, vamos entender como a rede do Docker funciona. Para isso, vamos nos concentrar na rede bridge padrão. Ao usar o Docker, se você não especificar um driver, este é o tipo de rede que você usará.

docker-network
Rede do Docker em: understanding-docker-networking-drivers-use-cases

A rede bridge funciona como uma rede interna privada para o host de modo que os contêineres dentro dele possam se comunicar. O acesso externo é garantido ao expor portas para os contêineres.

As redes bridge são usadas quando suas aplicações rodam em contêineres autônomos que precisam se comunicar.

Na figura acima, db e web podem se comunicar entre eles em uma rede bridge criada pelo usuário, chamada mybridge.

Se você nunca adicionou uma rede no Docker, deverá ver algo semelhante a isso:

$ docker network ls

NETWORK ID          NAME                  DRIVER              SCOPE
c3cd46f397ce        bridge                bridge              local
ad4e4c24568e        host                  host                local
1c69593fc6ac        none                  null                local

A rede bridge padrão está listada, junto com host e none.  Ignoraremos as outras duas e usaremos a rede bridge ao chegar aos exemplos.

Endereço IP do contêiner do Docker


Por padrão, o contêiner recebe um endereço IP para cada rede do Docker a qual ele se conecta. Cada rede é criada com uma máscara de sub-rede padrão, usando-a como um pool posteriormente para fornecer o endereço IP.

Em geral, o Docker usa a sub-rede padrão 172.17. 0.0/16 para colocar o contêiner em rede.

Para entender isso melhor, vamos executar um caso de uso real.

flamenco-done

Exemplo do Docker


Para ilustrar, usaremos um ambiente de Hive e Hadoop, contendo 5 contêineres do Docker.

Confira o arquivo docker-compose.yml que estamos prestes a executar:

version: "3"

services:
  namenode:
    image: bde2020/hadoop-namenode:2.0.0-hadoop2.7.4-java8
    volumes:
      - namenode:/hadoop/dfs/name
    environment:
      - CLUSTER_NAME=test
    env_file:
      - ./hadoop-hive.env
    ports:
      - "50070:50070"
  datanode:
    image: bde2020/hadoop-datanode:2.0.0-hadoop2.7.4-java8
    volumes:
      - datanode:/hadoop/dfs/data
    env_file:
      - ./hadoop-hive.env
    environment:
      SERVICE_PRECONDITION: "namenode:50070"
    ports:
      - "50075:50075"
  hive-server:
    image: bde2020/hive:2.3.2-postgresql-metastore
    env_file:
      - ./hadoop-hive.env
    environment:
      HIVE_CORE_CONF_javax_jdo_option_ConnectionURL: "jdbc:postgresql://hive-metastore/metastore"
      SERVICE_PRECONDITION: "hive-metastore:9083"
    ports:
      - "10000:10000"
  hive-metastore:
    image: bde2020/hive:2.3.2-postgresql-metastore
    env_file:
      - ./hadoop-hive.env
    command: /opt/hive/bin/hive --service metastore
    environment:
      SERVICE_PRECONDITION: "namenode:50070 datanode:50075 hive-metastore-postgresql:5432"
    ports:
      - "9083:9083"
  hive-metastore-postgresql:
    image: bde2020/hive-metastore-postgresql:2.3.0

volumes:
  namenode:
  datanode:

Do GitHub docker-hive

Ninguém quer ler um arquivo de configuração ENORME, certo? Então, aí vai uma imagem:

Screen-Shot-2020-06-21-at-2.48.18-PM

Melhor assim! Vamos começar com os contêineres:

docker-compose up -d

Podemos ver 5 contêineres:

$ docker ps --format \
"table {{.ID}}\t{{.Status}}\t{{.Names}}"

CONTAINER ID        STATUS                   NAMES
158741ba0339        Up 1 minutes             dockerhive_hive-metastore-postgresql
607b00c25f29        Up 1 minutes             dockerhive_namenode
2a2247e49046        Up 1 minutes             dockerhive_hive-metastore
7f653d83f5d0        Up 1 minutes (healthy)   dockerhive_hive-server
75000c343eb7        Up 1 minutes (healthy)   dockerhive_datanode

Agora, vamos conferir as redes do Docker:

$ docker network ls

NETWORK ID          NAME                  DRIVER              SCOPE
c3cd46f397ce        bridge                bridge              local
9f6bc3c15568        docker-hive_default   bridge              local
ad4e4c24568e        host                  host                local
1c69593fc6ac        none                  null                local

Espere aí... tem uma nova rede chamada docker-hive_default!

Por padrão, o comando docker compose configura uma única rede para seu app. E a rede do app recebe seu nome com base no “nome do projeto”, originário do nome do diretório em que ele está.

Como o nome do nosso diretório é docker-hive, isso explica a nova rede.

Em seguida, veremos exemplos de como obter o endereço IP do contêiner do Docker.

Como obter o endereço IP do contêiner do Docker - exemplos

Agora que eu já tenho sua atenção, vamos revelar o mistério.

bermuda-logged-out-1

1. Usando docker inspect


O comando docker inspect é uma ótima forma de obter informações de baixo nível sobre os objetos do Docker. Você pode pegar qualquer campo do JSON retornado de maneira bastante direta.

Vamos usá-lo para obter o endereço IP de dockerhive_datanode?

$ docker inspect -f \
'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
75000c343eb7

172.18.0.5

Você não disse que o Docker usa a sub-rede 172.17. 0.0/16 padrão para colocar o contêiner em rede? Por que o endereço IP retornado é 172.18.0.5  fora dele?

Screen-Shot-2020-06-22-at-3.25.07-PM
Imagem criada em ip-address-in-cidr-range

Para responder isso, temos que olhar para nossas configurações de rede:

$ docker network inspect -f \
'{{range .IPAM.Config}}{{.Subnet}}{{end}}'  9f6bc3c15568

172.18.0.0/16

Executamos esse exemplo em uma máquina virtual do Compute Engine. Neste teste, a rede do Docker foi atribuída a uma sub-rede diferente: 172.18.0.0/16. Isso explica a questão!

Além disso, podemos procurar os endereços IP na rede docker-hive_default.

Assim, não precisamos procurar o IP de cada contêiner individualmente:

$ docker network inspect -f \
'{{json .Containers}}' 9f6bc3c15568 | \
jq '.[] | .Name + ":" + .IPv4Address'

"dockerhive_hive-metastore-postgresql:172.18.0.6/16"
"dockerhive_hive-metastore:172.18.0.2/16"
"dockerhive_namenode:172.18.0.3/16"
"dockerhive_datanode:172.18.0.5/16"
"dockerhive_hive-server:172.18.0.4/16"
cherry-success

Caso não tenha percebido, usamos a ajuda do jq para analisar o objeto de mapa Containers.

2. Usando docker exec

No exemplo a seguir, trabalharemos com o dockerhive_namenode.

$ docker exec dockerhive_namenode cat /etc/hosts

127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3      607b00c25f29

3. Dentro do contêiner do Docker

$ docker exec -it dockerhive_namenode /bin/bash

# rodando dentro do contêiner dockerhive_namenode
ip -4 -o address

7: eth0    inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0

Podemos até encontrar os endereços IP de outros contêineres que estão dentro da mesma rede:

Nó dos dados (data node)

# rodando dentro do contêiner dockerhive_namenode
ping dockerhive_datanode

PING dockerhive_datanode (172.18.0.5): 56 data bytes
64 bytes from 172.18.0.5: icmp_seq=0 ttl=64 time=0.092 ms

Metastore do Hive

# rodando dentro do contêiner dockerhive_namenode
ping dockerhive_hive-metastore

PING dockerhive_hive-metastore_1 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.087 ms

Servidor do Hive

# rodando dentro do contêiner
ping dockerhive_hive-server

PING dockerhive_hive-server (172.18.0.4): 56 data bytes
64 bytes from 172.18.0.4: icmp_seq=0 ttl=64 time=0.172 ms

Para encerrar

Todos os exemplos foram executados em uma VM de uma distribuição Linux no Compute Engine. Se você executar os exemplos nos ambientes macOS ou Windows, os comandos dos exemplos podem mudar um pouco.

Lembre-se, também, de que esses endereços IP dos exemplos dados são internos à rede docker-hive_default usada na amostra. Por isso, se você tiver um caso de uso para conectar esses contêineres externamente, precisará usar o IP externo da máquina do host (levando em conta que você estará expondo as portas dos contêineres corretamente).

Se estiver usando kubernetes, por exemplo, para gerenciar seus contêineres do Docker, permita que ele trate dos endereços IP para você.

* Ilustrações de icons8.com feitas por Murat Kalkavan.