Implantando novo código ao vivo

29

Qual é a melhor prática para implantar o novo código em um site ao vivo (comércio eletrônico)?

Por agora eu parei apache para +/- 10 segundos quando renomeando diretório public_html_newpara public_htmle velho public_html_old. Isso cria um curto período de inatividade, antes de iniciar o Apache novamente.

A mesma pergunta se aplica ao Git para puxar o novo repositório para o diretório ativo. Posso retirar o repositório enquanto o site está ativo? E se eu precisar copiar um banco de dados também?

Durante a compactação tar (finalidade de backup) do site ativo, notei que ocorreram alterações no diretório de mídia. Isso me indicou que os arquivos continuam mudando periodicamente. E se essas alterações puderem interferir se o Apache não for parado durante a implantação.

nicoX
fonte

Respostas:

13

Usar um balanceador de carga é uma boa ideia. Se o site for importante o suficiente para se preocupar com alguns segundos de inatividade, é importante o suficiente para se preocupar com a tolerância a falhas.

Além disso, se isso estiver em um sistema UNIX, você poderá colocar o Apache em espera durante a renomeação (ou atualização de link simbólico etc.):

killall -STOP httpd  # Pause all httpd processes
mv public_html public_html_orig
mv public_html_new public_html
killall -CONT httpd  # Resume all httpd processes

Isso impedirá que o Apache aceite novas solicitações durante a renomeação. Se você preferir links simbólicos ou alguma outra abordagem, a mesma ideia pode ser usada:

killall -STOP httpd  # Pause all httpd processes
rm /var/www/html
ln -s /var/www/version/03 /var/www/html
killall -CONT httpd  # Resume all httpd processes

Observe que todas as conexões ou pacotes pendentes serão enfileirados no sistema operacional. Para um site extremamente ocupado, considere ajustar o ListenBacklog, se apropriado, para o seu tipo de trabalhador httpd e verifique as configurações do sistema operacional relacionadas ao backlog de escuta do TCP.

Você também pode alterar o DocumentRoot no httpd.conf e fazer uma reinicialização normal ( apachectl graceful). A desvantagem aqui é o aumento do risco de erros, pois você também precisará atualizar qualquer Directoryconfiguração.

GargantuChet
fonte
A sessão de pausa ainda terá o site em execução?
NicoX 15/08/14
4
Ele deixa de dar tempo de CPU ao Apache. Se você tentou acessar o site em um navegador enquanto o Apache está em pausa, o navegador estará aguardando a conexão até que o Apache seja reiniciado (ou o tempo limite do navegador expirará, se o Apache for pausado por mais tempo do que o tempo limite). Se alguém estiver baixando um arquivo, o Apache interromperá o envio de dados enquanto estiver em pausa, novamente porque não está recebendo tempo de CPU. Novamente, isso só causará problemas se o Apache estiver parado por tanto tempo que a transferência expire.
GargantuChet
5
Dito de outra forma, o site não responderá enquanto o Apache estiver em pausa, mas as operações pendentes serão concluídas quando for reiniciado. Os usuários não terão "conexão recusada" e os downloads não serão interrompidos, mas as operações continuarão apenas quando o Apache for reiniciado. Isso garantirá que as transações existentes possam ser concluídas, mas novas solicitações serão tratadas somente depois que seu novo conteúdo for movido para o local.
precisa
11
Observe que em qualquer site de alto tráfego, isso pode facilmente matar o seu serviço Apache. 200 rq / s vai muito facilmente lixo seu pool de conexão assim que você será o seu processo de Apache 'desbloquear' após a mudança (se o movimento demorar um pouco)
CloudWeavers
11
Em um site de alto tráfego, haverá muitas solicitações em andamento para concluir quando o Apache for reiniciado. Isso escalonará o processamento de novas solicitações. Também é um bom argumento para garantir que as configurações do Apache (número máximo de threads / servidores / clientes) sejam razoáveis ​​e ajustar o backlog do TCP adequadamente. Embora eu esteja confuso sobre o que você quer dizer com "matando" o serviço. O Apache é muito sintonizável.
precisa
32

O mais rápido e fácil é usar um diretório de versão como

/var/www/version/01
/var/www/version/02

e use um link simbólico atual como seu html_root:

/var/www/html -> /var/www/version/02

Essa técnica se integra perfeitamente a um sistema de controle de revisão (svn, git, mercurial, ...), pois você pode fazer checkout de ramos e tags, alterar o link simbólico e recarregar o Apache. O tempo de inatividade é mínimo usando essa técnica e permite reversão muito fácil .

Ele também se integra bem a sistemas de implantação mais complexos, como pacotes RPM ou infraestrutura de gerenciamento de alterações de configuração (chef, fantoche, etc.).

CloudWeavers
fonte
4
A solução mais simples é sempre a melhor ... :-) É claro que não se esqueça de mencionar que talvez sejam necessários alguns FollowSymlinks e sinalizadores apache nas configurações.
peterh diz restabelecer Monica 13/08/14
Tome especial cuidado com o que o @PeterHorvath disse. O Apache pode ficar muito mal-humorado ao trabalhar com o DocumentRoots com link simbólico. Certifique-se de testar com cuidado!
Mhutter 14/08/14
@mhutter Thanks :-) O que realmente problemático é que permitindo FollowSymlinks no Apache pode causar problemas de segurança ...
peterh diz Reintegrar Monica
Atualizar um link simbólico não é uma operação atômica. Mesmo usando algo como ln -snfdesobedecer o link simbólico original, a operação subjacente é um unlinke symlink. Há uma chance de os usuários receberem um 404 durante a atualização. Isso não é melhor do que apenas renomear o diretório original e renomear um novo diretório (assumindo que você não esteja cruzando sistemas de arquivos). Veja a resposta acima com uma marca de seleção ao lado, que aborda essa preocupação.
GargantuChet
14

Renomear os diretórios sem desligar o Apache também deve funcionar. Isso reduzirá significativamente a janela. mv public_html public_html_old && mv public_html_new public_htmldeve terminar em uma fração de segundo.

Algumas desvantagens são que essa abordagem fornecerá 404a qualquer solicitação que ainda consiga ocorrer durante a janela. E se você executar o comando acima sem ter um public_html_newdiretório, ele falhará e o deixará com um site fornecendo 404todas as solicitações.

Fazê-lo atomicamente com diretórios não é suportado. Mas você pode fazer isso com links simbólicos. Em vez de ter um diretório nomeado public_html, tenha um diretório nomeado public_html.version-numbere um link simbólico chamado public_htmlapontando para esse diretório. Agora você pode criar um diretório chamado public_html.new-version-numbere um novo link simbólico chamado public_html.new.

Em seguida, você pode renomear public_html.newpara public_htmlpara alternar atomicamente. Observe que mvé "inteligente demais" para executar essa renomeação, mas isso pode ser feito usando os.renamepython ou qualquer outra coisa que chamará a renamechamada de sistema sem tentar ser inteligente.

O que fazer com a base de dados depende de qual banco de dados você está usando e para o que está usando. Você precisa fornecer muito mais detalhes sobre o banco de dados antes de podermos dar uma boa resposta para essa parte da sua pergunta.

Kasperd
fonte
11
No meu sistema Debian, mvtem uma -Topção que impede de seguir o link simbólico. Isso permitirá que você atomicamente renomear public_html.newmais public_html, assumindo que ambos são links simbólicos.
GargantuChet
11

Symlinks e mv são seus amigos, no entanto, se você realmente precisar evitar que os usuários finais obtenham uma página de erro ao implantar uma nova versão, deverá ter um proxy reverso ou um balanceador de carga na frente de pelo menos 2 servidores de back-end (apache no seu caso).

Durante a implantação, basta interromper um back-end de cada vez, implantar o novo código, reiniciá-lo e iterar nos demais back-end.

Os usuários finais serão sempre direcionados a bons back-ends pelo proxy.

Giovanni Toraldo
fonte
4
Eu estava trabalhando nessa resposta quando vi que você já a postou. Balancer + 2 servidores torna o processo invisível e mais fácil de recuperar de uma atualização ruim ...
Bart Silverstrim
9

Se você estiver aplicando alterações regularmente em um sistema de produção, eu cuidaria de um ciclo de vida estruturado. Uma boa prática é Capistrano http://capistranorb.com/ . Esta é uma solução de código aberto para implantar software em um ou mais servidores em várias plataformas e configurações.

Para o Magento, existe até um plugin: https://github.com/augustash/capistrano-ash/wiki/Magento-Example

Para servidor único e transições quase contínuas, recomendo usar links simbólicos.

Skiaddict
fonte
4

A maneira como faço isso é confirmar minhas alterações do meu ambiente de desenvolvimento local para um repositório on-line do Git, como o Github. Meu ambiente de produção é executado em um repositório remoto, então tudo o que preciso fazer é ssh no servidor e executar git pullpara reduzir as alterações mais recentes. Não há necessidade de parar seu servidor da web.

Se você possui arquivos em seu projeto cujas configurações e / ou conteúdo diferem da sua versão local (como arquivos de configuração e upload de mídia), é possível usar variáveis ​​de ambiente e / ou adicionar esses arquivos / diretórios a um .gitignorearquivo para impedir a sincronização com o repositório.

harryg
fonte
3

Minha primeira ideia é:

# deploy into public_html_new, and then:
rsync -vaH --delete public_html_new/ public_html/

Uma boa solução foi usar o rsync. Ele mudou apenas os arquivos realmente alterados. Cuidado, as barras no final dos caminhos são importantes aqui.

Normalmente, o apache não precisa ser reiniciado, não é o mundo java. Ele verifica a alteração de todos os arquivos php a pedido e relê (e re-tokeniza) automaticamente.

O Git pull foi semelhante eficiente, embora tenha sido um pouco mais difícil de script. É claro que permitiu um amplo espectro de diferentes possibilidades de detecção de fusão / alteração.

Essa solução funcionará perfeitamente apenas se não houver mudanças realmente importantes - se houver grandes alterações na implantação, um pouco de risco não poderá ser encerrado, porque há um intervalo de tempo não desprezível, quando o código será parcialmente alterado e particularmente não.

Se houver grandes mudanças, minha sugestão foi sua solução inicial (duas renomear).


Aqui está uma solução um pouco incondicional, mas 100% atômica:

(1) monte uma parte alternativa do seu sistema de arquivos, onde o seu magento ocorre:

mount /dev/sdXY /mnt/tmp

(2) --bindmonte seu public_html_new em public_html:

mount --bind /path/to/public_html_new /path/to/public_html

A partir deste ponto, o apache verá sua nova implantação. Qualquer alteração de um 404 é impossível.

(3) faça a sincronização com o rsync, mas no ponto de montagem alternativo):

rsync -vaH --delete /mnt/tmp/path/to/public_html_new/ /mnt/tmp/path/to/public_html/

(4) remova o suporte de ligação

umount /path/to/public_html
peterh diz restabelecer Monica
fonte
O comando excluirá public_html e implantará public_html_new nele?
NicoX 12/08
@nicoX Não, ele copiará apenas as alterações.
peterh diz restabelecer Monica 12/08/14
@nicoX Ele percorre as duas estruturas de diretório e, se encontrar alguma diferença (novo arquivo, arquivo modificado, arquivo excluído), modifica o segundo diretório para corresponder ao primeiro, conforme necessário. O resultado se você excluiu public_html e depois moveu public_html_new para seu lugar, mas sem nenhuma possibilidade de um problema 404 temporário.
peterh diz restabelecer Monica 12/08/14
11
Não, isso não é uma boa ideia. Dependendo das alterações, você pode ter um curto período de tempo em que o código public_htmlestá em um estado inconsistente e não deseja aproveitar essa oportunidade.
Sven
@ SVV Você está certo, minha ideia só é aceitável se houver apenas pequenas alterações. Estendi minha resposta de acordo.
peterh diz restabelecer Monica 12/08/14
1

Mover / substituir a http_publicpasta pode ser conseguido com simples mvou ln -scomandos ou equivalente enquanto o servidor http continua em execução. Você pode executar alguns scripts para reduzir significativamente o tempo de inatividade, mas verifique cuidadosamente os códigos de retorno dos seus comandos no script se automatizar o processo.

Dito isto, se você não deseja obter tempo de inatividade, seu aplicativo também deve suportá-lo. A maioria dos aplicativos usa um banco de dados para persistência. Fazer com que a versão N do seu aplicativo mexa com a versão N + 1 (ou o inverso) do seu modelo de dados pode quebrar as coisas, se não for previsto pela equipe de desenvolvimento.

Por experiência, manter essa consistência por meio de atualizações não é um dado para a maioria dos aplicativos. Um desligamento adequado, apesar do tempo de inatividade, é uma boa maneira de evitar problemas de consistência.

Uriel
fonte