O que a opção --net = host no comando Docker realmente faz?

97

Sou um pouco iniciante no Docker. Não consegui encontrar uma descrição clara do que essa opção faz no comando docker run em profundidade e um pouco confuso sobre isso.

Podemos usá-lo para acessar os aplicativos em execução em contêineres docker sem especificar uma porta? Por exemplo, se eu executar um webapp implantado por meio de uma imagem docker na porta 8080 usando a opção -p 8080:8080no comando docker run, sei que terei que acessá-lo na porta 8080 em containers Docker ip / theWebAppName. Mas eu realmente não consigo pensar em como a --net=hostopção funciona.

Ravindu Fernando
fonte

Respostas:

131

Após a instalação do docker, você tem 3 redes por padrão:

docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f3be8b1ef7ce        bridge              bridge              local
fbff927877c1        host                host                local
023bb5940080        none                null                local

Estou tentando manter isso simples. Portanto, se você iniciar um contêiner por padrão, ele será criado dentro da rede bridge (docker0).

$ docker run -d jenkins
1498e581cdba        jenkins             "/bin/tini -- /usr..."   3 minutes ago       Up 3 minutes        8080/tcp, 50000/tcp   friendly_bell

No dockerfile do Jenkins, as portas 8080e 50000estão expostas. Essas portas são abertas para o contêiner em sua rede de ponte. Assim, tudo dentro dessa rede de ponte pode acessar o contêiner na porta 8080e 50000. Tudo na rede de bridge está na faixa privada de. "Subnet": "172.17.0.0/16",Se você quiser acessá-los de fora, terá que mapear as portas -p 8080:8080. Isso mapeará a porta do seu contêiner para a porta do seu servidor real (a rede host). Assim, acessar seu servidor em 8080irá direcionar para sua rede bridgen na porta 8080.

Agora você também tem sua rede de host. Que não contêineres a rede de contêineres. Portanto, se você iniciar um contêiner na rede do host, ele terá a seguinte aparência (é o primeiro):

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
1efd834949b2        jenkins             "/bin/tini -- /usr..."   6 minutes ago       Up 6 minutes                              eloquent_panini
1498e581cdba        jenkins             "/bin/tini -- /usr..."   10 minutes ago      Up 10 minutes       8080/tcp, 50000/tcp   friendly_bell

A diferença está nas portas. Seu contêiner agora está dentro de sua rede host. Portanto, se você abrir a porta 8080em seu host, acessará o contêiner imediatamente.

$ sudo iptables -I INPUT 5 -p tcp -m tcp --dport 8080 -j ACCEPT

Eu abri a porta 8080em meu firewall e quando 8080estou acessando meu servidor na porta estou acessando meus jenkins. Acho que este blog também é útil para entendê-lo melhor.

lvthillo
fonte
4
É possível adicionar a opção --net=hostdentro de um Dockerfile?
AnirbanDebnath de
6
@AnirbanDebnath Eu não acho que é possível colocá-lo em um dockerfile mas desde estivador v17 você pode usá-lo como um parâmetro para a sua construção janela de encaixe: docker build --network=host. A rede de host especificada para a construção docker serve apenas para baixar os pacotes necessários para a construção da imagem. Quando você deseja executar seu contêiner na rede host, você ainda precisará definir a opção --network = host.
lvthillo de
Sim @AnirbanDebnath, é permitido no Dockerfile. por exemplo, na v3 - network_mode: "host"(ref - docs.docker.com/compose/compose-file/#network_mode )
Mohnish
1
Esse é um arquivo Docker-Compose que descreve como executar o contêiner. Não é um Dockerfile. Mas, de fato, lá é possível e faz a mesma coisa que docker executado --network = host
lvthillo
32

A --net=hostopção é usada para fazer com que os programas dentro do contêiner do Docker pareçam estar sendo executados no próprio host, da perspectiva da rede. Ele permite ao contêiner um maior acesso à rede do que ele normalmente pode obter.

Normalmente você tem que encaminhar portas da máquina host para um contêiner, mas quando os contêineres compartilham a rede do host, qualquer atividade de rede acontece diretamente na máquina host - assim como aconteceria se o programa estivesse sendo executado localmente no host em vez de dentro de um recipiente.

Embora isso signifique que você não precisa mais expor as portas e mapeá-las para portas de contêiner, significa que você precisa editar seus Dockerfiles para ajustar as portas nas quais cada contêiner escuta, para evitar conflitos, pois não é possível ter dois contêineres operando no mesmo porta do host. No entanto, o verdadeiro motivo para essa opção é a execução de aplicativos que precisam de acesso à rede difícil de encaminhar para um contêiner no nível da porta.

Por exemplo, se você deseja executar um servidor DHCP, você precisa ser capaz de ouvir o tráfego de broadcast na rede e extrair o endereço MAC do pacote. Essas informações são perdidas durante o processo de encaminhamento de porta, portanto, a única maneira de executar um servidor DHCP dentro do Docker é executar o contêiner como --net=host.

De modo geral, --net=hosté necessário apenas quando você executa programas com necessidades de rede incomuns e muito específicas.

Por último, de uma perspectiva de segurança, os contêineres do Docker podem escutar em muitas portas, embora eles apenas anunciem (exponham) uma única porta. Normalmente, isso é bom, pois você apenas encaminha a única porta esperada; no entanto, se você usar --net=host, terá todas as portas do contêiner escutando no host, mesmo aquelas que não estão listadas no Dockerfile. Isso significa que você precisará verificar o contêiner de perto (especialmente se não for seu, por exemplo, um oficial fornecido por um projeto de software) para ter certeza de não expor inadvertidamente serviços extras na máquina.

Malvino
fonte
Qual seria o comportamento se vários contêineres fossem iniciados com as opções '--net = host'? As solicitações serão encaminhadas para um contêiner aleatório?
user482594
@ user482594: Todos eles compartilharão a mesma pilha de rede, assim como você executou todos os programas dentro do mesmo contêiner. por exemplo, se você executar dois servidores web, você precisará ter certeza de que eles estão escutando em portas diferentes, caso contrário, o segundo contêiner receberá um erro informando que a porta está em uso pelo primeiro. O tráfego de entrada será encaminhado para qualquer contêiner que estiver escutando (tecnicamente todos os --net=hostcontêineres verão o tráfego, mas é claro que apenas um programa por vez pode escutar em uma determinada porta, não importa em qual contêiner você o execute, nesta configuração )
Malvineous
1
  1. você pode criar sua própria rede como --net = "qualquer nome"
  2. isso é feito para isolar os serviços de diferentes contêineres.
  3. suponha que o mesmo serviço esteja sendo executado em contêineres diferentes, mas o mapeamento da porta permaneça o mesmo, o primeiro contêiner inicia bem, mas o mesmo serviço do segundo contêiner falhará. portanto, para evitar isso, altere os mapeamentos de porta ou crie uma rede.
Abhishek DK
fonte
1
Obrigado por mencionar "2. isso é feito para isolar os serviços (rede) de diferentes contêineres". Eu realmente vejo valor em usar outras configurações de rede do docker (exceto host) se houver a possibilidade de executar vários contêineres no mesmo host. Em outros casos (onde o isolamento da rede não é necessário), eu preferiria --net=host.
CᴴᴀZ