Atribuição de vhosts a portas Docker


83

Eu tenho um DNS curinga configurado para que todas as solicitações da web para um domínio personalizado (* .foo) sejam mapeadas para o endereço IP do host Docker. Se eu tiver vários contêineres executando instâncias do Apache (ou Nginx), cada contêiner mapeia a porta do Apache (80) para alguma porta de entrada externa.

O que eu gostaria de fazer é fazer uma solicitação para container-1.foo, que já está mapeado para o endereço IP correto (do host Docker) por meio do meu servidor DNS personalizado, mas proxy da solicitação da porta 80 padrão para o Docker externo correto porta de modo que a instância correta do Apache do contêiner especificado seja capaz de responder com base no domínio personalizado. Da mesma forma, container-2.foo procuraria o apache de um segundo container e assim por diante.

Existe uma solução pré-construída para isso, minha melhor aposta é executar um proxy Nginx no host Docker ou devo escrever um proxy node.js com potencial para gerenciar contêineres Docker (iniciar / parar / reconstruir via web ), ou ...? Quais opções eu tenho que tornariam o uso dos contêineres do Docker mais parecido com um evento natural e não algo com portas estranhas e malabarismo de contêiner?


Eu também tenho essa pergunta - pelo que eu posso dizer, executar cada aplicativo em um contêiner do Docker e, em seguida, fazer o roteamento no host usando um servidor nginx (talvez em seu próprio contêiner) é a maneira de fazer isso. Estou me perguntando se devo executar o servidor de aplicativos autônomo (ou seja, expor um servidor php-fpm, puma, etc.) ou incluir uma instância nginx (inútil?) Também.
Ross

Dê uma olhada em github.com/dotcloud/hipache , que é um proxy reverso configurável por meio do redis.
ZeissS de

Respostas:


81

Esta resposta pode demorar um pouco, mas o que você precisa é de um proxy reverso automático. Usei duas soluções para isso:

  • jwilder / nginx-proxy
  • Traefik

Com o tempo, minha preferência é usar o Traefik. Principalmente porque é bem documentado e mantido, e vem com mais recursos (balanceamento de carga com diferentes estratégias e prioridades, verificações de saúde, disjuntores, certificados SSL automáticos com ACME / Let's Encrypt, ...).


Usando jwilder / nginx-proxy

Ao executar um contêiner do Docker , a imagem nginx-proxy do Docker de Jason Wilder , você obtém um servidor nginx configurado como um proxy reverso para seus outros contêineres sem configuração para manter.

Basta executar seus outros contêineres com a VIRTUAL_HOSTvariável de ambiente e o nginx-proxy descobrirá seu ip: port e atualizará a configuração do nginx para você.

Digamos que seu DNS esteja configurado para *.test.localmapear o endereço IP de seu host Docker e, em seguida, basta iniciar os seguintes contêineres para obter uma demonstração rápida em execução:

# start the reverse proxy
docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy

# start a first container for http://tutum.test.local
docker run -d -e "VIRTUAL_HOST=tutum.test.local" tutum/hello-world

# start a second container for http://deis.test.local
docker run -d -e "VIRTUAL_HOST=deis.test.local" deis/helloworld

Usando Traefik

Ao executar um contêiner Traefik , você obtém um servidor proxy reverso configurado que reconfigurará suas regras de encaminhamento de acordo com os rótulos do docker encontrados em seus contêineres.

Digamos que seu DNS esteja configurado para *.test.localmapear o endereço IP de seu host Docker e, em seguida, basta iniciar os seguintes contêineres para obter uma demonstração rápida em execução:

# start the reverse proxy
docker run --rm -it -p 80:80 -v /var/run/docker.sock:/var/run/docker.sock traefik:1.7 --docker

# start a first container for http://tutum.test.local
docker run -d -l "traefik.frontend.rule=Host:tutum.test.local" tutum/hello-world

# start a second container for http://deis.test.local
docker run -d -l "traefik.frontend.rule=Host:deis.test.local" deis/helloworld

-v /var/run/docker.sock:/tmp/docker.sockÉ uma solução perigosa? O contêiner deste proxy nginx tem acesso ao daemon do host do docker? Isso pode ser uma possível falha de segurança?
Mikl

possivelmente. Observe também que o não compartilhamento /var/run/docker.socktambém não é uma garantia de que o host docker não pode ser explorado a partir de um contêiner. A segurança do Docker é um assunto à parte.
Thomasleveil

Existe algum problema de segurança conhecido? Quando você pode alcançar o host docker do contêiner.
Mikl

Existia um exploit no passado e o problema agora foi corrigido, mas novos exploits podem ser encontrados no futuro. Docker não é sobre adicionar segurança, é sobre facilidade de implantação
Thomasleveil

5
Você também pode executar nginx-proxy e docker-gen separadamente para que o soquete docker não seja montado no contêiner nginx.
Jason Wilder

42

Aqui estão duas respostas possíveis: (1) configurar portas diretamente com Docker e usar Nginx / Apache para fazer proxy dos vhosts, ou (2) usar Dokku para gerenciar portas e vhosts para você (que é como aprendi a fazer o Método 1).

Método 1a (atribuir portas diretamente com docker)

Etapa 1: configure nginx.conf ou Apache no host, com as atribuições de número de porta desejadas. Este servidor web, rodando no host, fará o proxy vhost. Não há nada de especial nisso em relação ao Docker - é uma hospedagem vhost normal. A parte especial vem a seguir, na Etapa 2, para fazer o Docker usar o número de porta do host correto.

Etapa 2: force as atribuições de número de porta no Docker com "-p" para definir os mapeamentos de porta do Docker e "-e" para definir variáveis ​​de ambiente personalizadas no Docker, da seguinte maneira:

port=12345 # <-- the vhost port setting used in nginx/apache
IMAGE=myapps/container-1
id=$(docker run -d -p :$port -e PORT=$port $IMAGE)
# -p :$port will establish a mapping of 12345->12345 from outside docker to
# inside of docker.
# Then, the application must observe the PORT environment variable
# to launch itself on that port; This is set by -e PORT=$port.

# Additional goodies:
echo $id # <-- the running id of your container
echo $id > /app/files/CONTAINER # <-- remember Docker id for this instance
docker ps # <-- check that the app is running
docker logs $id # <-- look at the output of the running instance
docker kill $id # <-- to kill the app

Método 1b Porta de aplicativo codificada

... se seu aplicativo usa uma porta codificada, por exemplo a porta 5000 (ou seja, não pode ser configurada por meio da variável de ambiente PORT, como no Método 1a), então ela pode ser codificada por meio do Docker como este:

publicPort=12345
id=$(docker run -d -p $publicPort:5000 $IMAGE)
# -p $publicPort:5000 will map port 12345 outside of Docker to port 5000 inside
# of Docker. Therefore, nginx/apache must be configured to vhost proxy to 12345,
# and the application within Docker must be listening on 5000.

Método 2 (deixe Dokku descobrir as portas)

No momento, uma boa opção para gerenciar vhosts do Docker é o Dokku . Uma opção futura pode ser usar Flynn , mas no momento Flynn está apenas começando e ainda não está pronto. Portanto, vamos com o Dokku por enquanto: Após seguir as instruções de instalação do Dokku, para um único domínio, habilite o vhosts criando o arquivo "VHOST":

echo yourdomain.com > /home/git/VHOST
# in your case: echo foo > /home/git/VHOST

Agora, quando um aplicativo é enviado via SSH para Dokku (consulte os documentos do Dokku para saber como fazer isso), o Dokku vai olhar para o arquivo VHOST e para o aplicativo enviado (digamos que você tenha enviado "container-1"), ele irá gerar o seguinte arquivo:

/home/git/container-1/nginx.conf

E terá o seguinte conteúdo:

upstream container-1 { server 127.0.0.1:49162; }
server {
  listen      80;
  server_name container-1.yourdomain.com;
  location    / {
    proxy_pass  http://container-1;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $remote_addr;
  }
}

Quando o servidor for reinicializado, o Dokku garantirá que o Docker inicie o aplicativo com a porta mapeada para sua porta inicialmente implantada (49162 aqui), em vez de receber outra porta aleatoriamente. Para alcançar essa atribuição determinística, o Dokku salva a porta inicialmente atribuída /home/git/container-1/PORTe na próxima inicialização, ele define o PORTambiente com esse valor e também mapeia as atribuições de porta do Docker para ser esta porta no lado do host e no lado do aplicativo. Isso se opõe ao primeiro lançamento, quando Dokku irá definir PORT=5000e então descobrir qualquer porta aleatória que o Dokku mapeie no lado VPS para 5000 no lado do aplicativo. É redondo (e pode até mudar no futuro), mas funciona!

O modo como o VHOST funciona, por baixo do capô, é: ao fazer um push git do aplicativo via SSH, o Dokku executará ganchos que residem no /var/lib/dokku/plugins/nginx-vhosts. Esses ganchos também estão localizados no código-fonte do Dokku aqui e são responsáveis ​​por gravar os nginx.confarquivos com as configurações corretas de vhost. Se você não tiver esse diretório /var/lib/dokku, tente executar dokku plugins-install.


3

Com o docker, você deseja que os ips internos permaneçam normais (por exemplo, 80) e descubra como conectar as portas aleatórias.

Uma maneira de lidar com eles é com um proxy reverso como o hipache. Aponte seu DNS para ele e, em seguida, você pode reconfigurar o proxy conforme seus contêineres sobem e descem. Dê uma olhada em http://txt.fliglio.com/2013/09/protyping-web-stuff-with-docker/ para ver como isso pode funcionar.

Se você estiver procurando por algo mais robusto, pode dar uma olhada em "descoberta de serviço". (uma olhada na descoberta de serviço com docker: http://txt.fliglio.com/2013/12/service-discovery-with-docker-docker-links-and-beyond/ )

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.