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 API
contêiner não está vinculado a nenhum outro, mas o
App
contêiner está vinculado a API
e Nginx
está vinculado a API
e App
.
O resultado disso são as alterações nos env
vars e nos /etc/hosts
arquivos que residem nos containers API
e App
. Os resultados são assim:
/ etc / hosts
Executar cat /etc/hosts
dentro de seu Nginx
contê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 env
dentro de seu Nginx
contê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/hosts
entradas de arquivo e env
vars 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 nginx
em seu Nginx
contê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/hosts
arquivo que docker
criou, ou você pode utilizar o ENV
vars e executar uma substituição de string (eu usei sed
) em seu nginx.conf
e em qualquer outro arquivo conf que possa estar em sua /etc/nginx/sites-enabled
pasta 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/hosts
opçã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/hosts
opção de arquivo é como você escreve seu Dockerfile
para usar um script de shell como o CMD
argumento, que por sua vez lida com a substituição da string para copiar os valores IP de ENV
para 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.conf
arquivo 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.conf
e api.myapp.conf
.
A mágica acontece Nginx-Startup.sh
quando usamos sed
para fazer a substituição da string no APP_IP
placeholder que escrevemos no upstream
bloco de nossos arquivos api.myapp.conf
e app.myapp.conf
.
Esta pergunta ask.ubuntu.com explica muito bem:
Encontre e substitua texto dentro de um arquivo usando comandos
GOTCHA
No OSX, sed
trata as opções de maneira diferente, o -i
sinalizador especificamente. No Ubuntu, a -i
bandeira tratará da substituição 'no local'; ele irá abrir o arquivo, alterar o texto e então 'salvar' o mesmo arquivo. No OSX, o -i
sinalizador 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 -i
sinalizador.
GOTCHA
Para usar ENV vars dentro da regex que sed
usa 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.sh
execução do script, que costumava sed
alterar o valor APP_IP
para a ENV
variável correspondente que fornecemos no sed
comando. Agora temos arquivos conf em nosso /etc/nginx/sites-enabled
diretório com os endereços IP dos ENV
vars que o docker definiu ao iniciar o contêiner. Em seu api.myapp.conf
arquivo, você verá que o upstream
bloco 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 Nginx
já terá definido o primeiro IP em seus arquivos conf, ou em seu /etc/hosts
arquivo, por isso não será capaz de determinar o novo IP para api.myapp.com
. A solução para isso é usar CoreOS
e seu etcd
serviço que, no meu entendimento limitado, atua como um compartilhamento ENV
para todas as máquinas registradas no mesmo CoreOS
cluster. Este é o próximo brinquedo que vou brincar com a configuração.
OPÇÃO B: usar /etc/hosts
entradas 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/hosts
entrada em seus arquivos api.myapp.conf
e 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/hosts
arquivo assim: 172.0.0.2 API
Achei que apenas puxaria o valor, mas não parece ser.
Eu também tive alguns problemas auxiliares com meu Elastic Load Balancer
sourcing 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á.