Introdução
Ainda me lembro, de uns 10 anos atrás, quando comecei a mexer com programação para Web. Me diverti bastante com o assunto, mas como minha área era realmente Redes e Infraestrutura, acabei rumando para um misto dos dois: Redes e Infraestrutura para sistemas de Internet. Ao longo de minha experiência, trabalhei com gente que fazia pequenos sites, até gente que fazia grandes blogs e portais.
Em quase todos os casos, sempre havia ambientes mistos para o desenvolvimento e testes das aplicações. Geralmente são esses três ambientes:
- Desenvolvimento – Onde realmente os desenvolvedores trabalham, onde o código está sempre cutting-edge e as coisas quebram o tempo todo, consertando-se num passe de mágica. Muitas vezes está localizado na própria máquina do desenvolvedor, dependendo do tamanho do projeto e da equipe.
- Homologação – Ambiente onde depois de um freeze do site, que a equipe acha que está estável, põe-se o produto para funcionar e fazer vários testes. Este ambiente deve ser fiel ao de produção, pois a validação (como o nome diz) tem que ser feita nele antes de qualquer tipo de lançamento.
- Produção – Depois de tudo desenvolvido e testado, o ambiente de produção é justamente aquele em que o site vai funcionar para o “mundo”. Depois de se certificar que tudo está certo, coloca-se em produção e só se altera se for validado tudo em homologação antes.
O cenário perfeito seria esse, mas falar é fácil demais, né? Os problemas já começam no Desenvolvimento, quando o ambiente já é diferente da homologação. O desenvolvedor constrói um código que funciona às maravilhas, mas na hora de colocar em homologação, nada funciona. E então na produção, nem se fala…
O desenvolvedor tem que estar ciente sobre o que faz no código: bons programadores sempre pensam macro – e assim conseguem prever diferenças entre ambientes. Essa característica do perfeccionismo é uma boa qualidade quando os prazos não estão já estourados, mas não podemos sempre contar com isso ao nosso lado, pois há diversas variáveis em jogo que podem não garantir muito bem isso.
Então é aí que entra a parte da galera de Redes e Infraestrutura: ajudar os desenvolvedores a trabalhar. No caso dos ambientes, isso significa deixar os 3 ambientes iguais. E quem trabalha com isso sabe muito bem que é bastante difícil… Mas de vez em quando vou dar algumas dicas baseadas em experiências e sugestões que vou obtendo no trabalho.
O problema com as URLs
O primeiro problema que podemos enfrentar são as benditas URLs. Cada servidor Web pode estar configurado para responder por domínios diferentes. Por exemplo, um mesmo site de uma empresa Mega Radical Enterprise tem os três ambientes que citei acima, mas configurados da seguinte forma:
- Desenvolvimento: http://devel.intranet.megaradicalenterprises.com.br (IP interno: 192.168.0.20)
- Homologação: http://homol.intranet.megaradicalenterprises.com.br (IP interno: 192.168.1.20)
- Produção: http://www.megaradicalenterprises.com.br (IP Externo: 200.xxx.xxx.xxx)
E ainda por cima, o site utiliza segregação de domínios para imagens e scripts (o que é recomendável para sites grandes), utilizando sub-domínios img e js para cada um desses sites. Imagine o terror que é para administrar tudo isso na aplicação, fica muito mais complicado. Então entra a parte em que falei que o desenvolvedor sempre que estar ciente dessas mudanças e programar ‘macro’… ou não…
Este problema poderia ser facilmente resolvido editando o arquivo hosts do Linux (ou Windows) em cada uma das máquinas. Mas em um ambiente com mais de 10 desenvolvedores e muitos sites e sistemas sendo desenvolvidos, fica meio inviável ficar administrando isso em cada máquina. Então descartando essa idéia, temos…
Uma solução com Proxies
Uma das soluções para unificar essas URLs apareceu com uma sugestão dos colegas de trabalho Denis Almeida Vieira (@davieira) e Rainer Alves (@rainer_alves), que seria usar Proxies para cada ambiente. Quando um usuário precisar acessar um ambiente, ele muda a configuração do proxy no navegador e o proxy se encarrega de direcionar os domínios pro lugar correto. Aliando essa facilidade com algum plugin que troca proxies de forma fácil no navegador, os desenvolvedores e usuários conseguem acessar os ambientes muito mais facilmente.
Para não ter que ficar criando uma máquina para cada Proxy e ambiente diferente, utilizei a seguinte topologia:
Como o DNS está usando Views, dependendo do IP do cliente, um domínio vai ter uma resposta diferente. Por exemplo:
- Cliente 192.168.0.1 consulta www.megaradicalenterprises.com.br, recebe resposta: 192.168.0.20
- Cliente 192.168.0.2 consulta www.megaradicalenterprises.com.br, recebe resposta:192.168.1.20
- Cliente 192.168.0.3 consulta www.megaradicalenterprises.com.br, recebe resposta:200.xxx.xxx.xxx
Ou seja, o mesmo domínio agora pode ter três tipos de resposta, exatamente o que a gente precisa. Do jeito que vamos fazer, como cada squid está atrelado a um IP da máquina, o cliente DNS dele terá sempre uma reposta de acordo com a view.
A única desvantagem que vejo neste modelo é que para cada domínio que você quiser usar nos três ambientes, terá que configurar as views do BIND para responder corretamente, ou seja, mais um ponto de administração de DNS, independente do DNS autoritário pro domínio. Mesmo assim, acredito que isso é pouco trabalho em compensação à vantagem.
Configuração da máquina DNS
Não vou entrar no mérito de configurar passo a passo todo o BIND, porque ao escrever esse tutorial, acho que quem o lê já tem boas noções sobre o assunto. Se não tiver, recomendo dar uma lida antes em outros materiais para aprender… :) Neste nosso método, vamos usar uma funcionalidade do BIND que vi poucas pessoas usarem por aí: views. Uma view funciona respondendo com configurações específicas, dependendo de qual cliente requisitar.
Agora lá vai uma configuração de exemplo para o BIND com três views (desenvolvimento, homologação e produção) para um mesmo domínio (megaradicalenterprises.com.br). Versão do BIND utilizada: 9.3.6. Como distribuição base para este tutorial, estou usando o RHEL/CentOS 5.x.
acl "proxy-dev" { 192.168.0.1; }; acl "proxy-homol" { 192.168.0.2; }; acl "proxy-prod" { 192.168.0.3; }; acl "ourselves" { 192.168.0.1; 192.168.0.2; 192.168.0.3; 192.168.0.10; }; options { listen-on port 53 { localhost; 192.168.0.10; }; listen-on-v6 port 53 { ::1; }; directory "/var/named"; dump-file "/var/named/data/cache_dump.db"; statistics-file "/var/named/data/named_stats.txt"; memstatistics-file "/var/named/data/named_mem_stats.txt"; allow-query { ourselves; }; allow-query-cache { ourselves; }; }; logging { channel default_debug { file "data/named.run"; severity dynamic; }; }; view localhost_resolver { match-clients { localhost; }; match-destinations { localhost; }; recursion yes; include "/etc/named.rfc1912.zones"; }; view dev { match-clients { proxy-dev; }; recursion yes; notify no; include "/etc/named.rfc1912.zones"; zone "megaradicalenterprises.com.br" { type master; file "data/dev-db.megaradicalenterprises.com.br.zone"; }; }; view homol { match-clients { proxy-homol; }; recursion yes; notify no; include "/etc/named.rfc1912.zones"; zone "megaradicalenterprises.com.br" { type master; file "data/homol-db.megaradicalenterprises.com.br.zone"; }; }; view prod { match-clients { proxy-prod; }; recursion yes; notify no; include "/etc/named.rfc1912.zones"; };
Na configuração acima, podemos ressaltar:
- Criamos três ACLs para os nossos IPs do servidor de Proxy. As ACLs são usadas no match-clients de cada view. É assim que ele vai diferenciar que configuração vai usar pro domínio.
- O arquivo /etc/named.rfc1912.zones contém configurações das zonas padrões, como o localhost, 127, além do servidores raízes. (zona “.”). É um arquivo que vem padrão na instalação do RHEL/CentOS 5.x e pode ser que não exista em outras distribuições.
- Temos três zonas: dev, homol e prod. As zonas dev e homol têm diferentes arquivos de configuração de zona.
- A zona prod não tem nenhum arquivo de configuração. Isso porque se é produção, tem que usar mesmo é o DNS real :-) Então ele ao invés de buscar a zona no BIND, faz o caminho normal pelo /etc/resolv.conf.
Agora vamos pros dois arquivos de configuração de zona:
- /var/named/data/dev-db.megaradicalenterprises.com.br.zone
$TTL 60 @ IN SOA @ master.megaradicalenterprises.com.br. ( 2010061700 ; serial 3H ; refresh 15M ; retry 1W ; expiry 1D ) ; minimum @ IN NS @ www IN A 192.168.0.20
- /var/named/data/homol-db.megaradicalenterprises.com.br.zone
$TTL 60 @ IN SOA @ master.megaradicalenterprises.com.br. ( 2010061700 ; serial 3H ; refresh 15M ; retry 1W ; expiry 1D ) ; minimum @ IN NS @ www IN A 192.168.1.20
Pronto. O BIND e suas views estão configuradas. Agora é só iniciar o serviço:
# /etc/init.d/named start
Ou no Debian/Ubuntu:
# /etc/init.d/bind9 start
E agora é hora de configurar o servidor Squid…
Configuração da máquina de Squid
Como vimos no diagrama, teremos três Squids, um para cada ambiente: desenvolvimento, homologação e produção. Aqui neste tutorial, decidi fazer os 3 squids funcionarem na mesma máquina. Mas nada impede que esta configuração fosse simplificada utilizando três máquinas diferentes. Neste caso, basta fazer alguns passos bem simples.
Configurando três proxies em três máquinas diferentes
Configure três máquinas com três IPs que estamos usando no exemplo deste tutorial:
- Máquina com nome proxy-dev, IP 192.168.0.1
- Máquina com nome proxy-homol, IP 192.168.0.2
- Máquina com nome proxy-prod, IP 192.168.0.3
Não esqueça também de configurar o cliente DNS do sistema, deixando somente a seguinte linha no arquivo /etc/resolv.conf:
nameserver 192.168.0.10
Assim ele só vai consultar o DNS que configuramos antes e mais nada.
Depois instale o squid em cada das máquinas:
# yum install squid
Ou no Debian/Ubuntu:
# apt-get install squid
Depois é só iniciar o squid. Para cada máquina que você usar como proxy no navegador, o squid vai retornar um IP diferente para os domínios que você pedir a ele, exemplo:
[usuario@proxy-dev ~$] host www.megaradicalenterprises.com.br www.megaradicalenterprises.com.br has address 192.168.0.20 [usuario@proxy-homol ~$] host www.megaradicalenterprises.com.br www.megaradicalenterprises.com.br has address 192.168.1.20 [usuario@proxy-prod ~$] host www.megaradicalenterprises.com.br www.megaradicalenterprises.com.br has address 200.xxx.xxx.xxx
Configurando três proxies em uma máquina
Pra economizar máquina, resolvi então criar os três proxies numa mesma máquina. Essa máquina, chamada proxy, é configurada com três interfaces de rede:
- Desenvolvimento: eth0 – 192.168.0.1
- Homologação: eth0:1 – 192.168.o.2 (IP alias)
- Produção: eth0:2 – 192.168.0.3 (IP alias)
E então:
- A configuração abaixo é muito específica para RHEL/CentOS 5.x.
- Na configuração de cada squid, ele estará escutando apenas em um dos 3 IPs, de acordo com sua função.
- Cada squid terá seus diretório de log e seu diretório de cache separados.
- Cada processo do squid será executado por um usuário diferente no sistema.
- O iptables se encarregará de forçar o usuário de cada squid a sair pelo IP correto para o DNS.
Então pra começar, instale o squid:
# yum install squid
Ou no Debian/Ubuntu:
# apt-get install squid
Agora crie os usuários adicionais para cada ambiente:
# adduser squid-dev # adduser squid-homol # adduser squid-prod
Pode deixar com a senha bloqueada mesmo. Agora crie os diretórios necessários de logs e cache e dê as devidas permissões:
# mkdir -p /var/log/squid-{dev,homol,prod} /var/spool/squid-{dev,homol,prod} # chown -R squid-dev:squid-dev /var/log/squid-dev /var/spool/squid-dev # chown -R squid-homol:squid-homol /var/log/squid-homol /var/spool/squid-homol # chown -R squid-prod:squid-prod /var/log/squid-prod /var/spool/squid-prod
Agora um exemplo de arquivo de configuração padrão do squid, no nosso caso para o ambiente de desenvolvimento.
- /etc/squid-dev.conf
pid_filename /var/run/squid-dev.pid acl all src 0.0.0.0/0.0.0.0 acl manager proto cache_object acl localhost src 127.0.0.1/255.255.255.255 acl nois src 192.168.0.0/255.255.255.0 acl to_localhost dst 127.0.0.0/8 acl SSL_ports port 443 acl Safe_ports port 80 # http acl Safe_ports port 21 # ftp acl Safe_ports port 443 # https acl Safe_ports port 70 # gopher acl Safe_ports port 210 # wais acl Safe_ports port 1025-65535 # unregistered ports acl Safe_ports port 280 # http-mgmt acl Safe_ports port 488 # gss-http acl Safe_ports port 591 # filemaker acl Safe_ports port 777 # multiling http acl CONNECT method CONNECT http_access allow manager localhost http_access deny manager http_access deny !Safe_ports http_access deny CONNECT !SSL_ports http_access allow localhost http_access allow nois http_access deny all icp_access allow all http_port 192.168.0.1:3128 hierarchy_stoplist cgi-bin ? access_log /var/log/squid-dev/access.log squid cache_log /var/log/squid-dev/cache.log cache_store_log /var/log/squid-dev/store.log acl QUERY urlpath_regex cgi-bin \? cache deny QUERY refresh_pattern ^ftp: 1440 20% 10080 refresh_pattern ^gopher: 1440 0% 1440 refresh_pattern . 0 20% 4320 acl apache rep_header Server ^Apache broken_vary_encoding allow apache coredump_dir /var/spool/squid-dev visible_hostname proxy-dev.localdomain cache_effective_user squid-dev cache_effective_group squid-dev cache_dir ufs /var/spool/squid-dev 100 16 256
Agora crie outros dois arquivos, substituindo apenas as linhas apresentadas abaixo:
- /etc/squid/squid-homol.conf
pid_filename /var/run/squid-homol.pid http_port 192.168.0.2:3128 access_log /var/log/squid-homol/access.log squid cache_log /var/log/squid-homol/cache.log cache_store_log /var/log/squid-homol/store.log coredump_dir /var/spool/squid-homol visible_hostname proxy-homol.localdomain cache_effective_user squid-homol cache_effective_group squid-homol cache_dir ufs /var/spool/squid-homol 100 16 256
- /etc/squid/squid-prod.conf
pid_filename /var/run/squid-prod.pid http_port 192.168.0.3:3128 access_log /var/log/squid-prod/access.log squid cache_log /var/log/squid-prod/cache.log cache_store_log /var/log/squid-prod/store.log coredump_dir /var/spool/squid-prod visible_hostname proxy-prod.localdomain cache_effective_user squid-prod cache_effective_group squid-prod cache_dir ufs /var/spool/squid-prod 100 16 256
Ou seja:
- Cada arquivo de configuração usa o http_port para escutar em um IP específico, na porta 3128.
- Cada um grava seus arquivos de log nos seus respectivos diretórios no /var/log.
- Cada um grava seus arquivos de cache nos seus respectivos diretórios no /var/spool.
- Os parâmetros cache_effective_user e cache_effective_group forçam o squid a ser executado como cada um desses usuários.
Inicialize os diretórios de cache:
# squid -f /etc/squid/squid-dev.conf -z -F -D # squid -f /etc/squid/squid-homol.conf -z -F -D # squid -f /etc/squid/squid-prod.conf -z -F -D
Então para executar o squid, basta fazer:
# squid -f /etc/squid/squid-dev.conf -D # squid -f /etc/squid/squid-homol.conf -D # squid -f /etc/squid/squid-prod.conf -D
Para facilitar a vida, modifiquei o initscript do RHEL/CentOS para fazer essas tarefas de forma padrão da distribuição. Se quiser usar dessa forma, primeiro crie os arquivos no /etc/sysconfig:
- /etc/sysconfig/squid-dev
SQUID_OPTS="-f /etc/squid/squid-dev.conf -D" SQUID_SHUTDOWN_TIMEOUT=100
- /etc/sysconfig/squid-homol
SQUID_OPTS="-f /etc/squid/squid-homol.conf -D" SQUID_SHUTDOWN_TIMEOUT=100
- /etc/sysconfig/squid-prod
SQUID_OPTS="-f /etc/squid/squid-prod.conf -D" SQUID_SHUTDOWN_TIMEOUT=100
Coloque os scripts em anexo abaixo no diretório /etc/init.d.
Depois:
# chmod 755 /etc/init.d/squid-{dev,homol,prod} # chkconfig --add squid-dev # chkconfig --add squid-homol # chkconfig --add squid-prod # chkconfig squid-dev on # chkconfig squid-homol on # chkconfig squid-prod on
E então é só iniciar (ou parar, ou reiniciar, etc…) o serviço:
# /etc/init.d/squid-dev start # /etc/init.d/squid-homol start # /etc/init.d/squid-prod start
Agora para finalizar, vamos usar o iptables para forçar a saída dos diferentes squids para os diferentes IPs:
# iptables -t nat -A POSTROUTING -m owner --uid-owner squid-dev -j SNAT --to-source 192.168.0.1 # iptables -t nat -A POSTROUTING -m owner --uid-owner squid-homol -j SNAT --to-source 192.168.0.2 # iptables -t nat -A POSTROUTING -m owner --uid-owner squid-prod -j SNAT --to-source 192.168.0.3
Os comandos do iptables podem ser colocados nos scripts de iniciação do sistema.
Agora façamos o teste do DNS!
[root@proxy ~#] su squid-dev -c "host www.megaradicalenterprises.com.br" www.megaradicalenterprises.com.br has address 192.168.0.20 [root@proxy ~#] su squid-homol -c "host www.megaradicalenterprises.com.br" www.megaradicalenterprises.com.br has address 192.168.1.20 [root@proxy ~#] su squid-prod -c "host www.megaradicalenterprises.com.br" www.megaradicalenterprises.com.br has address 200.xxx.xxx.xxx
Pronto, agora a máquina do Proxy está configurada! Agora é hora dos clientes…
Configurando os clientes
Nos navegadores dos clientes, só precisamos agora configurar o proxy de acordo com o que queremos:
- Ambiente Desenvolvimento: 192.168.0.1, porta 3128.
- Ambiente Homologação: 192.168.0.2, porta 3128.
- Ambiente Produção: 192.168.0.3, porta 3128.
Outra dica legal é utilizar um plugin de troca rápida de proxies. Por exemplo, o Firefox tem um plugin muito bom chamado FoxyProxy que com dois cliques você muda de uma configuração de proxy para outra, veja estes screenshots:
E com certeza tem outras extensões para outros navegadores que também facilitem a vida dessa troca de proxies no navegador. Só espero que você não esteja usando muito Internet Explorer pra desenvolver, porque sinceramente ele é uma droga :)
Conclusão
Este é apenas um passo em direção a um ambiente mais transparente para o desenvolvedor. Se você chegou até aqui, é porque realmente se interessou pelo assunto e trabalha nesse meio. Então se tiver alguma dúvida ou sugestão de outros problemas que enfrentamos no dia-a-dia de trabalho, não deixe de comentar sobre isso! Bom proveito.