A resposta de @T0xicCode está correta, mas pensei em expandir os detalhes, já que na verdade levei cerca de 20 horas para finalmente implementar uma solução funcional.
Se você deseja executar o Nginx em seu próprio contêiner e usá-lo como um proxy reverso para balancear a carga de vários aplicativos na mesma instância do servidor, as etapas que você precisa seguir são as seguintes:
Vincule seus contêineres
Ao usardocker run seus contêineres, normalmente inserindo um script de shell no User Data, você pode declarar links para qualquer outro contêiner em execução . Isso significa que você precisa iniciar seus contêineres em ordem e apenas os últimos contêineres podem se vincular aos anteriores. Igual a:
#!/bin/bash
sudo docker run -p 3000:3000 --name API mydockerhub/api
sudo docker run -p 3001:3001 --link API:API --name App mydockerhub/app
sudo docker run -p 80:80 -p 443:443 --link API:API --link App:App --name Nginx mydockerhub/nginx
Portanto, neste exemplo, o APIcontêiner não está vinculado a nenhum outro, mas o
Appcontêiner está vinculado a APIe Nginxestá vinculado a APIe App.
O resultado disso são as alterações nos envvars e nos /etc/hostsarquivos que residem nos containers APIe App. Os resultados são assim:
/ etc / hosts
Executar cat /etc/hostsdentro de seu Nginxcontêiner produzirá o seguinte:
172.17.0.5 0fd9a40ab5ec
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.17.0.3 App
172.17.0.2 API
ENV Vars
Executar envdentro de seu Nginxcontêiner produzirá o seguinte:
API_PORT=tcp://172.17.0.2:3000
API_PORT_3000_TCP_PROTO=tcp
API_PORT_3000_TCP_PORT=3000
API_PORT_3000_TCP_ADDR=172.17.0.2
APP_PORT=tcp://172.17.0.3:3001
APP_PORT_3001_TCP_PROTO=tcp
APP_PORT_3001_TCP_PORT=3001
APP_PORT_3001_TCP_ADDR=172.17.0.3
Trunquei muitos dos vars reais, mas os valores acima são os valores-chave de que você precisa para fazer proxy do tráfego para seus contêineres.
Para obter um shell para executar os comandos acima em um contêiner em execução, use o seguinte:
sudo docker exec -i -t Nginx bash
Você pode ver que agora você tem /etc/hostsentradas de arquivo e envvars que contêm o endereço IP local para qualquer um dos contêineres vinculados. Até onde posso dizer, isso é tudo o que acontece quando você executa contêineres com opções de link declaradas. Mas agora você pode usar essas informações para configurar nginxem seu Nginxcontêiner.
Configurando o Nginx
É aqui que fica um pouco complicado e há algumas opções. Você pode escolher configurar seus sites para apontar para uma entrada no /etc/hostsarquivo que dockercriou, ou você pode utilizar o ENVvars e executar uma substituição de string (eu usei sed) em seu nginx.confe em qualquer outro arquivo conf que possa estar em sua /etc/nginx/sites-enabledpasta para inserir o IP valores.
OPÇÃO A: Configurar Nginx usando ENV Vars
Esta é a opção que escolhi porque não consegui fazer a
/etc/hostsopção de arquivo funcionar. Em breve tentarei a Opção B e atualizarei esta postagem com todas as descobertas.
A principal diferença entre esta opção e usar a /etc/hostsopção de arquivo é como você escreve seu Dockerfilepara usar um script de shell como o CMDargumento, que por sua vez lida com a substituição da string para copiar os valores IP de ENVpara seu (s) arquivo (s) conf.
Este é o conjunto de arquivos de configuração que terminei:
Dockerfile
FROM ubuntu:14.04
MAINTAINER Your Name <you@myapp.com>
RUN apt-get update && apt-get install -y nano htop git nginx
ADD nginx.conf /etc/nginx/nginx.conf
ADD api.myapp.conf /etc/nginx/sites-enabled/api.myapp.conf
ADD app.myapp.conf /etc/nginx/sites-enabled/app.myapp.conf
ADD Nginx-Startup.sh /etc/nginx/Nginx-Startup.sh
EXPOSE 80 443
CMD ["/bin/bash","/etc/nginx/Nginx-Startup.sh"]
nginx.conf
daemon off;
user www-data;
pid /var/run/nginx.pid;
worker_processes 1;
events {
worker_connections 1024;
}
http {
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 33;
types_hash_max_size 2048;
server_tokens off;
server_names_hash_bucket_size 64;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging Settings
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Gzip Settings
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 3;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/xml text/css application/x-javascript application/json;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
# Virtual Host Configs
include /etc/nginx/sites-enabled/*;
# Error Page Config
#error_page 403 404 500 502 /srv/Splash;
}
OBSERVAÇÃO: é importante incluí-lo daemon off;em seu nginx.confarquivo para garantir que o contêiner não saia imediatamente após a inicialização.
api.myapp.conf
upstream api_upstream{
server APP_IP:3000;
}
server {
listen 80;
server_name api.myapp.com;
return 301 https://api.myapp.com/$request_uri;
}
server {
listen 443;
server_name api.myapp.com;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_pass http://api_upstream;
}
}
Nginx-Startup.sh
#!/bin/bash
sed -i 's/APP_IP/'"$API_PORT_3000_TCP_ADDR"'/g' /etc/nginx/sites-enabled/api.myapp.com
sed -i 's/APP_IP/'"$APP_PORT_3001_TCP_ADDR"'/g' /etc/nginx/sites-enabled/app.myapp.com
service nginx start
Vou deixar você fazer sua lição de casa sobre a maior parte do conteúdo de nginx.confe api.myapp.conf.
A mágica acontece Nginx-Startup.shquando usamos sedpara fazer a substituição da string no APP_IPplaceholder que escrevemos no upstreambloco de nossos arquivos api.myapp.confe app.myapp.conf.
Esta pergunta ask.ubuntu.com explica muito bem:
Encontre e substitua texto dentro de um arquivo usando comandos
GOTCHA
No OSX, sedtrata as opções de maneira diferente, o -isinalizador especificamente. No Ubuntu, a -ibandeira tratará da substituição 'no local'; ele irá abrir o arquivo, alterar o texto e então 'salvar' o mesmo arquivo. No OSX, o -isinalizador requer a extensão de arquivo que você gostaria que o arquivo resultante tivesse. Se estiver trabalhando com um arquivo sem extensão, você deve inserir '' como o valor do -isinalizador.
GOTCHA
Para usar ENV vars dentro da regex que sedusa para encontrar a string que você deseja substituir, você precisa colocar a var entre aspas duplas. Portanto, a sintaxe correta, embora de aparência instável, é a acima.
Portanto, docker lançou nosso contêiner e acionou a Nginx-Startup.shexecução do script, que costumava sedalterar o valor APP_IPpara a ENVvariável correspondente que fornecemos no sedcomando. Agora temos arquivos conf em nosso /etc/nginx/sites-enableddiretório com os endereços IP dos ENVvars que o docker definiu ao iniciar o contêiner. Em seu api.myapp.confarquivo, você verá que o upstreambloco mudou para este:
upstream api_upstream{
server 172.0.0.2:3000;
}
O endereço IP que você vê pode ser diferente, mas percebi que geralmente é 172.0.0.x.
Agora você deve ter todo o roteamento adequado.
GOTCHA
Você não pode reiniciar / executar novamente nenhum contêiner depois de executar a inicialização da instância inicial. O Docker fornece a cada contêiner um novo IP na inicialização e não parece reutilizar nenhum que foi usado antes. Portanto api.myapp.com, obterá 172.0.0.2 na primeira vez, mas obterá 172.0.0.4 na próxima vez. Mas Nginxjá terá definido o primeiro IP em seus arquivos conf, ou em seu /etc/hostsarquivo, por isso não será capaz de determinar o novo IP para api.myapp.com. A solução para isso é usar CoreOSe seu etcdserviço que, no meu entendimento limitado, atua como um compartilhamento ENVpara todas as máquinas registradas no mesmo CoreOScluster. Este é o próximo brinquedo que vou brincar com a configuração.
OPÇÃO B: usar /etc/hostsentradas de arquivo
Esta deveria ser a maneira mais rápida e fácil de fazer isso, mas não consegui fazer funcionar. Aparentemente, você acabou de inserir o valor da /etc/hostsentrada em seus arquivos api.myapp.confe app.myapp.conf, mas não consegui fazer esse método funcionar.
ATUALIZAÇÃO:
Veja a resposta de @Wes Tod para obter instruções sobre como fazer esse método funcionar.
Aqui está a tentativa que fiz em api.myapp.conf:
upstream api_upstream{
server API:3000;
}
Considerando que há uma entrada em meu /etc/hostsarquivo assim: 172.0.0.2 APIAchei que apenas puxaria o valor, mas não parece ser.
Eu também tive alguns problemas auxiliares com meu Elastic Load Balancersourcing de todos os AZ, então esse pode ter sido o problema quando tentei essa rota. Em vez disso, tive que aprender como lidar com a substituição de strings no Linux, o que foi divertido. Vou tentar isso daqui a pouco e ver no que dá.