Como obter o endereço IP do host da docker de dentro de um contêiner de docker

358

Como o título diz. Preciso recuperar o endereço IP que o docker hospeda e os mapas de porta do host para o contêiner, e fazer isso dentro do contêiner.

xiamx
fonte
Você poderia elaborar como gostaria de usar essas informações? Você disse "hosts do docker" - você está executando o Docker em mais de um host? Depois que o contêiner souber o endereço IP do host e dos mapas de porta, o que fará?
Andy
A maneira mais simples de passar os endereços IP do host do docker para o contêiner do docker, acho que você deve fazer uma chamada dentro do contêiner usando 'docker container exec'. Suponha que você deseja executar ping no host de dentro do container do busybox, use, por exemplo: $ IP = '8.8.8.8' && docker container do busybox ping $ IP 'A maneira de descobrir o IP do host, use o que você mais gosta.
SauloAlessandre 14/01

Respostas:

314
/sbin/ip route|awk '/default/ { print $3 }'

Como @MichaelNeale notou, não faz sentido usar esse método Dockerfile(exceto quando precisamos desse IP apenas durante o tempo de compilação), porque esse IP será codificado durante o tempo de compilação.

spinus
fonte
49
Quando você estiver usando a ponte de encaixe (padrão) para os contêineres, isso produzirá o IP das pontes como 172.17.42.1, em vez do IP do host, como 192.168.1.x (suponho que seu host esteja em um NAT doméstico). Usar a resposta do @Magno Torres é provavelmente o que as pessoas desejam em tais situações, se você deseja o endereço 192.168.1.x.
Programster
2
esse RUN não funcionará conforme o esperado - apenas calculará o IP no tempo de compilação - e ficará para sempre estático depois disso, e não será útil. Será o IP do host de construção.
Michael Neale
7
@Programster, posso presumir que as pessoas desejam a conexão entre o host do docker e o contêiner, é isso que o IP da ponte pode oferecer (é claro na instalação padrão "doméstica"). Por que alguém precisaria de um IP de host "real" se ele pode estar fora da ponte de encaixe e pode ser inacessível? Esta é a solução para todas as pessoas que acabaram de instalar o docker e querem brincar com ele em pouco tempo.
Spinus #
11
@ MichaelNeale, como antes, eu diria que a maioria das pessoas que estão começando com o docker precisa de uma conexão entre o host e o contêiner, é isso. Se alguém estiver fazendo implantações "apropriadas", provavelmente ele não está usando a ponte docker, de qualquer maneira, ele está usando rede personalizada e, provavelmente, está ciente de todas as peculiaridades da rede ou se o DNS (ou qualquer descoberta) foi configurado.
Spinus #
11
@spinus - mas isso só será válido se for executado no host em que foi construído - nesse caso - você pode codificá-lo com firmeza - ou procurar - acho que não é uma resposta útil e enganará muito de pessoas - recomendamos que você o remova. (O bit RUN)
Michael Neale
182

A partir da versão 18.03, você pode usar host.docker.internalcomo o IP do host.

Funciona no Docker para Mac , no Docker para Windows e talvez em outras plataformas também.

Esta é uma atualização específica do Mac docker.for.mac.localhost, disponível desde a versão 17.06 e docker.for.mac.host.internaldisponível desde a versão 17.12, que também pode ainda funcionar nessa plataforma.

Observe que, como na documentação do Mac e Windows , isso é apenas para fins de desenvolvimento.

Por exemplo, tenho variáveis ​​de ambiente definidas no meu host:

MONGO_SERVER=host.docker.internal

No meu docker-compose.ymlarquivo, eu tenho o seguinte:

version: '3'

services:
  api:
    build: ./api
    volumes:
      - ./api:/usr/src/app:ro
    ports:
      - "8000"
    environment:
      - MONGO_SERVER
    command: /usr/local/bin/gunicorn -c /usr/src/app/gunicorn_config.py -w 1 -b :8000 wsgi
allanberry
fonte
2
@allanberry infelizmente as pessoas Docker preferem não dar-nos uma maneira independente de plataforma para fazer isso porque eles preferem não para abraçar casos de uso não intencionais (como acesso a qualquer serviço na máquina local de um recipiente janela de encaixe)
Andy
21
Fui apresentado ao Docker como Build it once, execute-o em qualquer lugar. Mas isso é totalmente falso, já que você sempre precisa configurar o sistema host também. Isso docker.for.mac..é inútil, pois na maioria dos casos você não possui um ambiente somente Linux ou Mac em sua empresa. É misto, você tem desenvolvedores usando Linux, Mac e Windows. Esse domínio não faz sentido, já que em 99% é um ambiente misto do sistema operacional host. Não desenvolvo um contêiner no macOS e o implanto em um servidor macOS. Eu o implanto no Linux. É isso que todo mundo faz. Então, qual é o objetivo docker.for.mac..?
TheFox 16/03/19
11
O @allanberry docker.for.mac.host.internalnão importa se você está usando o Docker com ou sem docker-compose. Eu quero usar um host fixo nos arquivos de configuração. IDK, por exemplo, docker.host.internalque sempre aponta para o endereço IP do host. Independentemente de qual sistema host eu estou usando. Esse é o objetivo de usar o Docker: quero ser autônomo. Entendo que é ainda mais complicado no macOS porque você tem outra camada entre o sistema host e o contêiner. Mas de qualquer maneira, na minha opinião, docker.for.mac.host.internalé inútil se você puder usá-lo apenas para o macOS.
TheFox 16/03/19
11
host.docker.internal também funciona no Docker for Windows , pelo menos no momento da redação deste comentário.
joanlofe
11
isso funciona perfeitamente, eu tenho dockerCe para windows e executando jenkins em um dos contêineres. Eu queria executar o comando docker no jenkins, mas o docker não conseguiu se conectar na etapa adicionar uma nuvem, usei este tcp: //host.docker.internal: 2375 e habilitei 'expor daemon no localhost: 2375' e ele funciona. economizou muito tempo. Obrigado!
Vikash
84

Atualização: No Docker para Mac , a partir da versão 18.03, você pode usar host.docker.internal como o IP do host. Veja a resposta de allanberry . Para versões anteriores do Docker for Mac, a seguinte resposta ainda pode ser útil:

No Docker para Mac, a docker0ponte não existe, portanto outras respostas aqui podem não funcionar. Todo o tráfego de saída, no entanto, é roteado através do host pai; portanto, enquanto você tenta se conectar a um IP, ele reconhece como ele próprio (e o contêiner do docker não pensa que é ele próprio), você deve conseguir se conectar. Por exemplo, se você executar isso na máquina pai, execute:

ipconfig getifaddr en0

Isso deve mostrar o IP do seu Mac na rede atual e o contêiner do docker também deve se conectar a esse endereço. Obviamente, isso é problemático se esse endereço IP mudar, mas você pode adicionar um IP de loopback personalizado ao seu Mac que o contêiner não pense ser ele mesmo, fazendo algo assim na máquina pai:

sudo ifconfig lo0 alias 192.168.46.49

Em seguida, você pode testar a conexão no contêiner do docker com telnet. No meu caso, eu queria conectar-me a um servidor xdebug remoto:

telnet 192.168.46.49 9000

Agora, quando o tráfego chegar ao seu Mac endereçado a 192.168.46.49 (e todo o tráfego que sai do contêiner passa pelo Mac), o seu Mac assume que o IP é ele próprio. Quando você terminar de usar esse IP, poderá remover o alias de loopback assim:

sudo ifconfig lo0 -alias 192.168.46.49

Uma coisa a ter cuidado é que o contêiner do docker não enviará tráfego para o host pai se achar que o destino do tráfego é ele próprio. Portanto, verifique a interface de loopback dentro do contêiner se tiver problemas:

sudo ip addr show lo

No meu caso, isso mostrou o inet 127.0.0.1/8que significa que eu não poderia usar nenhum IP no 127.*intervalo. Por isso eu usei 192.168.*no exemplo acima. Verifique se o IP que você usa não entra em conflito com algo em sua própria rede.

Code Commander
fonte
limpará essas configurações de loopback após a reinicialização do sistema?
Robbo_UK
@Robbo_UK Sim, o alias de loopback desaparecerá depois que você reiniciar o seu mac.
Code Commander
11
O uso desse nome de host não faz sentido, pois não funciona no Docker for Linux. Por que eles não o adicionaram também para Linux?
TheFox 28/08/19
Eles estão investigando isso neste momento @TheFox: github.com/docker/libnetwork/pull/2348
Ivo Pereira
46

Para aqueles que executam o Docker na AWS, os metadados da instância para o host ainda estão disponíveis no contêiner.

curl http://169.254.169.254/latest/meta-data/local-ipv4

Por exemplo:

$ docker run alpine /bin/sh -c "apk update ; apk add curl ; curl -s http://169.254.169.254/latest/meta-data/local-ipv4 ; echo"
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/community/x86_64/APKINDEX.tar.gz
v3.3.1-119-gb247c0a [http://dl-cdn.alpinelinux.org/alpine/v3.3/main]
v3.3.1-59-g48b0368 [http://dl-cdn.alpinelinux.org/alpine/v3.3/community]
OK: 5855 distinct packages available
(1/4) Installing openssl (1.0.2g-r0)
(2/4) Installing ca-certificates (20160104-r2)
(3/4) Installing libssh2 (1.6.0-r1)
(4/4) Installing curl (7.47.0-r0)
Executing busybox-1.24.1-r7.trigger
Executing ca-certificates-20160104-r2.trigger
OK: 7 MiB in 15 packages
172.31.27.238

$ ifconfig eth0 | grep -oP 'inet addr:\K\S+'
172.31.27.238
Nate Fox
fonte
Esse é um método super conveniente para quem usa a AWS. Eu uso isso para configurar o cliente dos agentes do Consul e vincular endereços. É ideal quando você está em situações em que não pode usar a rede host (como implantar contêineres no Elastic Beanstalk e ECS).
Richard Clayton
Este é um salva-vidas, obrigado. Eu estava tendo problemas para descobrir como lidar com a comunicação entre contêineres no meu cluster ECS.
Brennan
No basimage do Phusion (baseado no ubuntu), tive que mudar um pouco o seu comando:ifconfig eth0 | grep -oP 'inet \K\S+'
Meuoi
25

A única maneira de passar as informações do host como ambiente quando você cria um contêiner

run --env <key>=<value>
Magno Torres
fonte
19
Mais especificamente, o endereço IP da ponte pode ser passado em usar uma opção de linha de comando como: -e "DOCKER_HOST=$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+')"(usando a resposta aceita de unix.stackexchange.com/questions/87468/... )
ncoghlan
7
Eu acho que não funciona no Docker para Mac / Windows. (the bridge IP)
zx1986
22

A --add-hostpoderia ser uma solução mais líquido de limpeza (mas sem a parte da porta, apenas o hospedeiro pode ser tratado com esta solução). Então, no seu docker runcomando, faça algo como:

docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ { print  $3}'` [my container]

(De https://stackoverflow.com/a/26864854/127400 )

Augunrik
fonte
Eu disse "feito para isso" quando alguém queria uma entrada no / etc / hosts; nesta questão não é realmente verdade. O OP também solicitou "host e portmaps" e você cobriu apenas o host.
Bryan
Está bem. Fiquei um pouco confuso, pois a solução aceita apenas cobre a parte do host também. E acho que sua solução é superior à do spinus.
Augunrik
isso não funciona se você deseja usar o dind - docker-in-docker. Docker interno terá ip diferente
noisy
12

A prática recomendada padrão para a maioria dos aplicativos que desejam fazer isso automaticamente é: você não precisa . Em vez disso, a pessoa que está executando o contêiner injeta um nome de host / endereço IP externo como configuração, por exemplo, como uma variável de ambiente ou arquivo de configuração. Permitir que o usuário injete isso fornece o design mais portátil.

Por que isso seria tão difícil? Como os contêineres isolarão o aplicativo do ambiente host. A rede está no namespace apenas para esse contêiner por padrão, e os detalhes do host são protegidos do processo em execução no contêiner, que pode não ser totalmente confiável.


Existem opções diferentes, dependendo da sua situação específica:

Se o seu contêiner estiver sendo executado com a rede do host, você poderá olhar diretamente para a tabela de roteamento no host para ver a rota padrão. A partir desta pergunta, o seguinte funciona para mim, por exemplo:

ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'

Um exemplo mostrando isso com a rede do host em um contêiner é semelhante a:

docker run --rm --net host busybox /bin/sh -c \
  "ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'"

Para algumas versões do Docker Desktop, eles injetaram uma entrada DNS na VM incorporada:

getent hosts host.docker.internal | awk '{print $1}'

Se você estiver executando em um ambiente de nuvem, poderá verificar o serviço de metadados do provedor de nuvem, por exemplo, o da AWS:

curl http://169.254.169.254/latest/meta-data/local-ipv4

Se você deseja seu endereço externo / Internet, pode consultar um serviço remoto como:

curl ifconfig.co

Cada um desses possui limitações e funciona apenas em cenários específicos. A opção mais portátil ainda é executar o contêiner com o endereço IP injetado como configuração, por exemplo, aqui está uma opção executando o ipcomando anterior no host e injetando-o como uma variável de ambiente:

export HOST_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
docker run --rm -e HOST_IP busybox printenv HOST_IP
BMitch
fonte
curl ifconfig.coComando realmente útil .. Obrigado :)
MadAboutProgramming
8

Se você deseja um IPendereço real (não uma ponte IP) Windowse possui uma janela de encaixe 18.03(ou mais recente), faça o seguinte:

Execute o bash no contêiner do host em que o nome da imagem está nginx(funciona Alpine Linux distribution):

 docker run -it nginx /bin/ash

Em seguida, execute dentro do contêiner

/ # nslookup host.docker.internal

Name:      host.docker.internal
Address 1: 192.168.65.2

192.168.65.2é o IP do host - não o IP da ponte, como na spinusresposta aceita.

Estou usando aqui host.docker.internal :

O host tem um endereço IP alterado (ou nenhum, se você não tiver acesso à rede). A partir de 18.03, nossa recomendação é conectar-se ao nome DNS especial host.docker.internal, que resolve o endereço IP interno usado pelo host. Isso é para fins de desenvolvimento e não funcionará em um ambiente de produção fora do Docker for Windows.

Kamil Witkowski
fonte
2
Tentei lhe a solução e parece que o comando nslookup não pode ser encontrado
Sergey
@Sergey A sua imagem é baseada Alpine Linux? Caso contrário, verifique o equivalente para o seu específico linux distribution.
Kamil Witkowski
Não, eu uso exatamente o seu comando - docker run -it nginx / bin / ash
Sergey
Ok - se você estiver no Windows, mudei para linux containerse não estou usando windows containers. Você pode fazer isso clicando com o botão direito do mouse docker icone selecionando Switch to Linux containers. Eu acho que isso pode ser importante quando você está baixando uma imagem. Se você tiver windows containerverificado se a exclusão da nginximagem antiga e o download novamente, você obterá outro contêiner. Se ainda assim não funcionar para você - você pode tentar instalar nslookupno ash.
Kamil Witkowski
Se você não pode fazer a pesquisa, basta executar ping. Ele mostrará o IP resolvido. Para mim esta resposta funciona, e eu estou apenas usando esse nome de host ( host.docker.internal) de dentro do recipiente
Dmitry Minkovsky
7

TLDR para Mac e Windows

docker run -it --rm alpine nslookup host.docker.internal

... imprime o endereço IP do host ...

nslookup: can't resolve '(null)': Name does not resolve

Name:      host.docker.internal
Address 1: 192.168.65.2

Detalhes

No Mac e Windows , você pode usar o nome DNS especial host.docker.internal.

O host tem um endereço IP alterado (ou nenhum, se você não tiver acesso à rede). A partir de 18.03, nossa recomendação é conectar-se ao nome DNS especial host.docker.internal, que resolve o endereço IP interno usado pelo host. Isso é para fins de desenvolvimento e não funcionará em um ambiente de produção fora do Docker Desktop for Mac.

Nick Grealy
fonte
11
Não adicione a mesma resposta a várias perguntas . Responda à melhor e sinalize o restante como duplicado, depois de ganhar reputação suficiente. Se não for uma duplicata, adapte a postagem à pergunta e sinalize a exclusão.
Bhargav Rao
6

Docker para Mac Desejo conectar-me de um contêiner a um serviço no host

O host tem um endereço IP alterado (ou nenhum, se você não tiver acesso à rede). A partir de 18.03, nossa recomendação é conectar-se ao nome DNS especial host.docker.internal, que resolve o endereço IP interno usado pelo host.

O gateway também pode ser acessado como gateway.docker.internal. https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

BSCheshir
fonte
5

Se você ativou a API remota do docker (via, por exemplo) e sabe o nome do host ou o endereço IP da máquina host, isso pode ser feito com muito bash.-Htcp://0.0.0.0:4243

Dentro do usuário do meu contêiner bashrc:

export hostIP=$(ip r | awk '/default/{print $3}')
export containerID=$(awk -F/ '/docker/{print $NF;exit;}' /proc/self/cgroup)
export proxyPort=$(
  curl -s http://$hostIP:4243/containers/$containerID/json |
  node -pe 'JSON.parse(require("fs").readFileSync("/dev/stdin").toString()).NetworkSettings.Ports["DESIRED_PORT/tcp"][0].HostPort'
)

A segunda linha pega o ID do contêiner do /proc/self/cgrouparquivo local .

A terceira linha se desloca para a máquina host (supondo que você esteja usando 4243 como porta do docker) e depois usa o nó para analisar o JSON retornado para o DESIRED_PORT.

ICas
fonte
Isso se aplica somente quando você usa o encaminhamento de porta. Na verdade HostPortpode ser uma informação útil aqui, infelizmente o HostIppoderia ser0.0.0.0
Arnout Engelen
4

Eu tenho o Ubuntu 16.03. Para mim

docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ { print  $3}'` [image]

se não trabalhar (ip errado estava gerando)

Minha solução de trabalho foi a seguinte:

docker run --add-host dockerhost:`docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' bridge` [image]
ilya_direct
fonte
3

Aqui está outra opção para aqueles que executam o Docker na AWS. Essa opção evita o uso de apk para adicionar o pacote curl e economiza os preciosos 7 MB de espaço. Use o wget interno (parte do binário monolítico do BusyBox):

wget -q -O - http://169.254.169.254/latest/meta-data/local-ipv4
Kenn
fonte
3

AFAIK, no caso do Docker for Linux (distribuição padrão), o endereço IP do host sempre será 172.17.0.1 .

A maneira mais fácil de obtê-lo é via ifconfig(interface docker0) do host:

ifconfig

De dentro de uma janela de encaixe, o seguinte comando de uma janela de encaixe: ip -4 route show default | cut -d" " -f3

Você pode executá-lo rapidamente em uma janela de encaixe com a seguinte linha de comando:

# 1. Run an ubuntu docker
# 2. Updates dependencies (quietly)
# 3. Install ip package   (quietly)
# 4. Shows (nicely) the ip of the host
# 5. Removes the docker (thanks to `--rm` arg)
docker run -it --rm ubuntu:19.10 bash -c "apt-get update && apt-get install iproute2 -y && ip -4 route show default | cut -d' ' -f3"

Espero que ajude.

Nek
fonte
2

No linux você pode executar

HOST_IP=`hostname -I | awk '{print $1}'`

No macOS, sua máquina host não é o host do Docker. O Docker instalará seu sistema operacional host no VirtualBox.

HOST_IP=`docker run busybox ping -c 1 docker.for.mac.localhost | awk 'FNR==2 {print $4}' | sed s'/.$//'`
Aref Aslani
fonte
11
Primeiro bloco de código vai pegar o contêiner IP e não o IP do host
Ari
mandoc de hostname -Iadverte para não "fazer suposições sobre a ordem da saída".
cannot_mutably_borrow
1

Esta é uma implementação minimalista no Node.js para quem está executando o host nas instâncias do AWS EC2 , usando a instância de metadados do EC2 mencionada anteriormente .

const cp = require('child_process');
const ec2 = function (callback) {
    const URL = 'http://169.254.169.254/latest/meta-data/local-ipv4';
    // we make it silent and timeout to 1 sec
    const args = [URL, '-s', '--max-time', '1'];
    const opts = {};
    cp.execFile('curl', args, opts, (error, stdout) => {
        if (error) return callback(new Error('ec2 ip error'));
        else return callback(null, stdout);
    })
        .on('error', (error) => callback(new Error('ec2 ip error')));
}//ec2

e usado como

ec2(function(err, ip) {
        if(err) console.log(err)
        else console.log(ip);
    })
Loretoparisi
fonte
0

Aqui está como eu faço isso. Nesse caso, ele adiciona uma entrada de hosts em / etc / hosts na imagem do docker, apontando taurus-host para o IP da minha máquina local:

TAURUS_HOST=`ipconfig getifaddr en0`
docker run -it --rm -e MY_ENVIRONMENT='local' --add-host "taurus-host:${TAURUS_HOST}" ...

Em seguida, no contêiner do Docker, o script pode usar o nome do host taurus-host para chegar à minha máquina local que hospeda o contêiner do Docker.

djangofan
fonte
0

A solução usada é baseada em um "servidor" que retorna o endereço externo do host do Docker quando recebe uma solicitação http.

No "servidor":

1) Inicie o jwilder / nginx-proxy

# docker run -d -p <external server port>:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy

2) Inicie o recipiente ipify

# docker run -e VIRTUAL_HOST=<external server name/address> --detach --name ipify osixia/ipify-api:0.1.0

Agora, quando um contêiner envia uma solicitação http para o servidor, por exemplo,

# curl http://<external server name/address>:<external server port>

o endereço IP do host do Docker é retornado por ipify via cabeçalho http "X-Forwarded-For"

Exemplo (o servidor ipify tem o nome "ipify.example.com" e é executado na porta 80, o host do docker tem IP 10.20.30.40):

# docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
# docker run -e VIRTUAL_HOST=ipify.example.com --detach --name ipify osixia/ipify-api:0.1.0

Agora, dentro do contêiner, você pode ligar para:

# curl http://ipify.example.com
10.20.30.40
ramazotto
fonte
0

Tente isto

docker run --rm -i --net = host alpino ifconfig

Oleksandr Dudnyk
fonte
-2

No Ubuntu, o hostnamecomando pode ser usado com as seguintes opções:

  • -i, --ip-address endereços para o nome do host
  • -I, --all-ip-addressestodos os endereços para o host

Por exemplo:

$ hostname -i
172.17.0.2

Para atribuir à variável, a seguinte linha única pode ser usada:

IP=$(hostname -i)
kenorb
fonte
Isso fornecerá o endereço IP do contêiner do Docker, não do host
Mario Camou 28/02
-7

Com https://docs.docker.com/machine/install-machine/

a) $ docker-machine ip

b) Obtenha o endereço IP de um ou mais computadores.

  $ docker-machine ip host_name

  $ docker-machine ip host_name1 host_name2
Kalyani Chaudhari
fonte
10
Este recupera o IP da máquina virtual que roda os recipientes Estivador, não o IP do host que os recipientes são executados no.
Spencer Williams
2
Isso se aplica apenas à janela de encaixe que está sendo executada na máquina de encaixe. A nova janela de encaixe para mac não funciona na máquina de encaixe.
precisa saber é o seguinte