Estou tentando criar um contêiner Docker que atue como uma máquina virtual completa. Eu sei que posso usar a instrução EXPOSE dentro de um Dockerfile para expor uma porta e posso usar o -p
sinalizador with docker run
para atribuir portas, mas quando um contêiner está realmente em execução, existe um comando para abrir / mapear portas adicionais ativas?
Por exemplo, digamos que eu tenha um contêiner do Docker executando o sshd. Outra pessoa usando o ssh do contêiner e instala o httpd. Existe uma maneira de expor a porta 80 no contêiner e mapeá-la para a porta 8080 no host, para que as pessoas possam visitar o servidor Web em execução no contêiner, sem reiniciá-lo?
Respostas:
Você não pode fazer isso via Docker, mas pode acessar a porta não exposta do contêiner na máquina host.
se você tiver um contêiner que, com algo em execução na porta 8000, poderá executar
Para obter o endereço IP do contêiner, execute os 2 comandos:
Internamente, o Docker faz chamadas para iptables quando você executa uma imagem, portanto, talvez alguma variação disso funcione.
para expor a porta 8000 do contêiner na porta 8001 de localhosts:
Uma maneira de resolver isso é configurar outro contêiner com o mapeamento de porta desejado e comparar a saída do comando iptables-save (porém, tive que remover algumas das outras opções que forçam o tráfego a passar pelo docker proxy).
NOTA: isso está subvertendo a janela de encaixe, portanto, isso deve ser feito com a consciência de que pode criar fumaça azul
OU
Outra alternativa é procurar a opção (new? Post 0.6.6?) -P - que usará portas de host aleatórias e as conectará.
OU
com 0.6.5, você poderia usar o recurso LINKs para abrir um novo contêiner que se comunica com o existente, com algumas retransmissões adicionais aos sinalizadores -p desse contêiner? (Ainda não usei LINKs)
OU
com docker 0,11? você pode usar
docker run --net host ..
para conectar seu contêiner diretamente às interfaces de rede do host (ou seja, a rede não é espaçada pelo nome) e, portanto, todas as portas que você abre no contêiner são expostas.fonte
CONTAINER_IP=$(docker inspect container_name | jq .[0].NetworkSettings.IPAddress | sed -r 's/\"([^\"]+)\"/\1/''])'); iptables -t nat -A DOCKER -p tcp --dport 8001 -j DNAT --to-destination ${CONTAINER_IP}:8000
jq
esed
você pode usar-f
a opção dedocker inspect
:CONTAINER_IP=$(docker inspect -f '{{ .NetworkSettings.IPAddress }}' container_name)
jshon -e 0 -e NetworkSettings -e Networks -e bridge -e IPAddress -u
Aqui está o que eu faria:
fonte
sudo docker
e não apenasdocker
?docker commit
eu estava pronto para testar o aplicativo novamente, em vez de gastar horas para reinstalar tudo.Embora não seja possível expor uma nova porta de um contêiner existente , você pode iniciar um novo contêiner na mesma rede do Docker e fazer com que ele encaminhe o tráfego para o contêiner original.
Exemplo Trabalhado
Inicie um serviço da Web que escute na porta 80, mas não exponha sua porta 80 interna (oops!):
Encontre seu IP de rede do Docker:
Inicie
verb/socat
com a porta 8080 exposta e faça com que ele encaminhe o tráfego TCP para a porta 80 desse IP:Agora você pode acessar o pastebin em http: // localhost: 8080 / , e seus pedidos vão para o
socat:1234
qual o encaminhapastebin:80
, e a resposta segue o mesmo caminho ao contrário.fonte
verb/socat:alpine
, já que sua imagem possui 5% da área ocupada (a menos que você encontre incompatibilidades de libc ou DNS ).alpine/socat
--net myfoldername_default
ao meuverb/socat
comando de inicialização desde que iniciei o contêiner não exposto em uma composição do docker que cria uma rede.Os hacks de tabelas de IP não funcionam, pelo menos no Docker 1.4.1.
A melhor maneira seria executar outro contêiner com a porta exposta e retransmitir com o socat. Isto é o que eu fiz para (temporariamente) conectar ao banco de dados com o SQLPlus:
Dockerfile:
fonte
FROM
imagem base do seu contêiner de banco de dados, para uso eficiente dos recursos.Aqui está outra ideia. Use SSH para fazer o encaminhamento de porta; isso tem o benefício de também trabalhar no OS X (e provavelmente no Windows) quando o host do Docker for uma VM.
fonte
Eu tive que lidar com esse mesmo problema e foi capaz de resolvê-lo sem interromper nenhum dos meus contêineres em execução. Esta é uma solução atualizada em fevereiro de 2016, usando o Docker 1.9.1. De qualquer forma, esta resposta é uma versão detalhada da resposta de @ ricardo-branco, mas com mais profundidade para novos usuários.
No meu cenário, eu queria conectar-me temporariamente ao MySQL em execução em um contêiner, e como outros contêineres de aplicativos estão vinculados a ele, parar, reconfigurar e executar novamente o contêiner de banco de dados não era um iniciador.
Como eu gostaria de acessar o banco de dados MySQL externamente (do Sequel Pro via tunelamento SSH), vou usar a porta
33306
na máquina host. (Não3306
, apenas no caso de haver uma instância externa do MySQL em execução.)Cerca de uma hora de ajustar iptables se mostrou infrutífera, embora:
Passo a passo, aqui está o que eu fiz:
Edite
dockerfile
, colocando isso dentro:Então construa a imagem:
Em seguida, execute-o, vinculando ao seu contêiner em execução. (Use em
-d
vez de-rm
mantê-lo em segundo plano até explicitamente parar e remover. Só quero que ele seja executado temporariamente neste caso.)fonte
Para adicionar à solução de resposta aceita
iptables
, tive que executar mais dois comandos no host para abri-lo para o mundo externo.Nota: eu estava abrindo a porta https (443), o IP interno do meu docker era
172.17.0.2
Nota 2: Essas regras são temporárias e duram apenas até que o contêiner seja reiniciado
fonte
Você pode usar o SSH para criar um túnel e expor seu contêiner em seu host.
Você pode fazer isso de ambas as formas, de contêiner para host e de host para contêiner. Mas você precisa de uma ferramenta SSH como o OpenSSH em ambos (cliente em um e servidor em outro).
Por exemplo, no contêiner, você pode fazer
Você pode encontrar o endereço IP do contêiner nesta linha (no contêiner):
Em seguida, no host, você pode apenas fazer:
fonte
Caso nenhuma resposta esteja funcionando para alguém - verifique se o contêiner de destino já está em execução na rede docker:
Salve-o para mais tarde na variável
$NET_NAME
:Se sim, você deve executar o contêiner de proxy na mesma rede.
Em seguida, procure o alias do contêiner:
Salve-o para mais tarde na variável
$ALIAS
:Agora execute
socat
em um contêiner na rede$NET_NAME
para fazer a ponte para a$ALIAS
porta exposta (mas não publicada) do contêiner ed:fonte
Você pode usar uma rede de sobreposição como o Weave Net , que atribuirá um endereço IP exclusivo a cada contêiner e expor implicitamente todas as portas a todas as partes do contêiner da rede.
O Weave também fornece integração de rede do host . Ele está desativado por padrão, mas, se você deseja acessar também os endereços IP do contêiner (e todas as suas portas) do host, pode executar simplesmente executar
weave expose
.Divulgação completa: Trabalho na Weaveworks.
fonte
Existe um invólucro HAProxy útil.
Isso cria um HAProxy para o contêiner de destino. mole-mole.
fonte
Aqui estão algumas soluções:
https://forums.docker.com/t/how-to-expose-port-on-running-container/3252/12
fonte
Leia a resposta de Ricardo primeiro. Isso funcionou para mim.
No entanto, existe um cenário em que isso não funcionará se o contêiner em execução foi iniciado usando o docker-compose. Isso ocorre porque o docker-compose (estou executando o docker 1.17) cria uma nova rede. A maneira de abordar esse cenário seria
docker network ls
Em seguida, acrescente o seguinte
docker run -d --name sqlplus --link db:db -p 1521:1521 sqlplus --net network_name
fonte
Não é possível fazer mapeamento de porta ao vivo, mas há várias maneiras de fornecer a um contêiner do Docker o que equivale a uma interface real, como uma máquina virtual.
Interfaces Macvlan
O Docker agora inclui um driver de rede Macvlan . Isso conecta uma rede Docker a uma interface do "mundo real" e permite atribuir os endereços dessa rede diretamente ao contêiner (como um modo de ponte de máquinas virtuais).
pipework
também pode mapear uma interface real em um contêiner ou configurar uma sub interface em versões mais antigas do Docker.IP de roteamento
Se você tiver controle da rede, poderá rotear redes adicionais para o host do Docker para uso nos contêineres.
Em seguida, atribua essa rede aos contêineres e configure o host do Docker para rotear os pacotes pela rede do Docker.
Interface de host compartilhada
A
--net host
opção permite que a interface do host seja compartilhada em um contêiner, mas provavelmente essa não é uma boa configuração para executar vários contêineres em um host devido à natureza compartilhada.fonte