* pache
Meu trabalho atual envolve tornar a infraestrutura que hospeda o produto muito mais escalonável e flexível. Um bom passo para ter flexibilidade na infraestrutura é ter algo bastante flexível na frente dela para conexões proxy e possivelmente fazer algo com elas. No momento, nosso provedor de infraestrutura lida com o balanceamento de carga e não podemos ajustar as coisas de forma alguma.
Aqui está como coloquei essa camada no lugar.
O que queríamos alcançar
Primeiro, queremos ser capazes de direcionar contas específicas (leia-se: subdomínios) para hosts específicos, se necessário. Pode ser porque eles são tão grandes que precisam ou porque queremos fazer um pequeno teste com eles para um recurso específico.
Então, também temos a necessidade de implementar uma atualização da infraestrutura de uma maneira suave: adicionar um novo host, rotear apenas algumas contas para ele e ver como ele se comporta.
Tudo isso é possível com muitos dos suspeitos usuais (HA-Proxy, Nginx), mas durante uma rápida conversa Jerome Petazzoni da Docker Inc. me disse algo na essência de:
“Porque não Hipache?”
Apache, para descolados
Existem 3 primos na comunidade francesa OpenSource que são conhecidos por serem assassinos. Um deles trabalha para a Docker Inc: Jerome. Lá ele faz toneladas de coisas, incluindo ser parte das pessoas que escrevem Hipache “Apache mas para descolados”.
Não é preciso dizer que confio em Jerome quando se trata desses tópicos. Li um pouco sobre o Hipache, incluindo um bom artigo escrito pelo principal autor e contribuidor do Hipache: Sam Alba. Você pode encontrar esse artigo no blog dot cloud: http://blog.dotcloud.com/under-the-hood-dotcloud-http-routing-layer .
Resumindo: o Hipache tem como objetivo ser rápido, confiável, capaz de agrupar e usar o Redis para controlar a configuração do endpoint. Redis significa que manter várias instâncias do Hipache em sincronia é muito fácil e muito rápido. Eu gostei dessa ideia.
Preparando
O Hipache, como o Docker, está em forte desenvolvimento. Provavelmente, a versão que você instalou em uma máquina não funcionará bem com os exemplos de configuração do branch master. Portanto, verifique a versão que seu npm instala e verifique a versão adequada da documentação relacionada a essa tag no repositório. Não fiz isso inicialmente e passei algumas horas tentando descobrir o que estava acontecendo.
Hipache funciona bem com HTTP e HTTPS, você só precisa passar os certificados SSL corretos. Por enquanto, tudo bem.
A configuração dos back-ends do Hipache acontece no Redis com conjuntos. O que significa que você pode fazer isso facilmente à mão ou, muito mais interessante, através de seu idioma favorito e de qualquer ferramenta de gerenciamento de infraestrutura que estiver usando.
Nginx, Unicorn
Nossa configuração em cada host envolve Nginx e Unicorn. O Nginx desempenha um papel de micro cache e serviços de ativos. Unicorn serve ao aplicativo Rails. Nossa configuração de implantação e unicórnio nos permite implantações com tempo de inatividade zero. Nada de especial aqui.
Até agora, as conexões SSL param no Nginx. Temos um pequeno bloco para lidar com o redirecionamento de HTTP para HTTPS com ele:
server {
listen 80;
client_max_body_size 4G;
return 301 https://$host$request_uri;
}
Assim que o Hipache estiver em vigor, as conexões HTTPS parariam com o Hipache. A configuração não cobre isso. E de fato, no momento, o Hipache é muito burro: insira HTTP ou HTTPS , envie HTTP . E é isso. Você não pode dizer ao Hipache “ei, o que vier no 80, você redireciona para 443”.
Se você pensar a respeito, isso faz sentido: por que confiar nas portas? Hipache é um balanceador de carga HTTP e proxy e é isso.
Olhei em volta e então me lembrei de uma curta resposta de Jerome:
“Verificamos os cabeçalhos para isso, no lado do aplicativo”
Como eu tinha certeza de quais cabeçalhos ele estava falando, pesquisei e ajustei um pequeno aplicativo Rack para ver os cabeçalhos HTTP .
require 'rack'
class HttpHeaders
def self.call(env)
headers = env.select {|k,v| k.start_with? 'HTTP_'}
.collect {|pair| [pair[0].sub(/^HTTP_/, ''), pair[1]]}
.collect {|pair| pair.join(": ") << "<br>"}
.sort
[200, {'Content-Type' => 'text/html'}, headers]
end
end
Um pouco de config.ru com isso:
require 'rack'
require ‘./http_headers’
use Rack::SSL
app = Rack::Builder.new do
run HttpHeaders
end
Rack::Server.start :app => app, :Port => 8082
Iniciei o aplicativo, adicionei o host como back-end no Redis / Hipache e voila:
# HTTP
X_FORWARDED_PORT: 80
X_FORWARDED_PROTO: http
X_FORWARDED_PROTOCOL: http
# HTTPS
X_FORWARDED_PORT: 443
X_FORWARDED_PROTO: https
X_FORWARDED_PROTOCOL: https
O primeiro é o que é exibido se eu me conectar ao host com HTTP , o segundo se for com HTTPS .
Eu sei que o middleware Rack seria facilmente capaz de pegar isso e responder rapidamente, sem envolver o resto do aplicativo. Conforme Rack vai, pelo menos 2 gemas já fazem isso: Rack-SSL e Rack-SSL-enforcer.
Um pouco de trabalho no config.ru :
require 'rubygems'
require 'rack'
require ‘./http_headers’
require 'rack/ssl'
use Rack::SSL
app = Rack::Builder.new do
use Rack::SSL
run HttpHeaders
end
Rack::Server.start :app => app, :Port => 8082
E bem, funciona.
Então, no final, aqui está a configuração:
- Hipache com um redis slave, configuração HTTP e HTTPS apontando para um host HTTP
- Host HTTP (nginx) apenas conectando-se ao unicórnio por meio de um soquete
- instância unicórnio executando o aplicativo com um middleware de rack para solicitar HTTPS como origem
Aqui está o link para a página do github do Hipache: https://github.com/dotcloud/hipache e você pode encontrar uma entrevista com Jerome Petazzoni no tópico Docker ( http://blog.leanstack.io/how-docker-was- nascido ) que também contém trechos sobre Hipache.