implantações automáticas de código e EC2

1

Estou apenas começando com o balanceador de carga EC2 e tentando implementar a chamada automática e a tolerância a falhas. O banco de dados é hospedado no RDS, as sessões são compartilhadas, os arquivos são compartilhados usando o S3.

Não consigo encontrar a melhor solução para implantações de código. Não quero usar o fabric para executar novamente os comandos de implementação em todas as instâncias.

Atualizando o código em uma instância, criando uma AMI a partir dela e, em seguida, reinicie as instâncias com essa AMI parece ser um grande exagero para mim, pois implantamos várias vezes por dia e todo o processo é um pouco incômodo.

Idealmente, gostaria de armazenar o código do aplicativo em um volume compartilhado (NFS?) em todas as instâncias e atualizar o código nesse volume durante as implantações. Todas as instâncias podem assistir a um arquivo específico para alterações e reiniciar os trabalhadores do aplicativo quando o arquivo é tocado.

Existe uma maneira de usar o NFS e montar automaticamente o EBS compartilhado em todas as instâncias?

ou existe uma maneira melhor de fazer isso?

Resumo do que é desejado:

Eu atualizo 1 volume de instância / NFS do EC2 e descubro o processo sem criar todo o novo AMI, destruindo instâncias e criando novas. Eu não quero que algumas instâncias entrem no limbo quando o código do aplicativo e os esquemas do banco de dados não estão em sincronia. Sei que a melhor prática é escrever código que suporte 2 alterações consecutivas no esquema do banco de dados, mas realmente não podemos permitir isso neste momento.

    
por Owais Lone 27.09.2014 / 12:46

2 respostas

3

Eu sugeriria evitar os compartilhamentos do NFS, pois eles criam um único ponto de falha para o seu sistema, e os clientes do NFS podem, às vezes, ter problemas para recuperar-se do tempo de inatividade do servidor NFS. O NFS não é realmente o "modo de nuvem" de fazer as coisas. A maneira da AWS de fazer o compartilhamento de dados entre máquinas virtuais envolve o uso de vários serviços descentralizados da AWS.

Para esse propósito específico, sugiro usar o serviço do AWS S3. Crie um bucket do S3 para suas versões de software, faça o upload de seus lançamentos e dê acesso às máquinas virtuais para que possam fazer o download dos lançamentos consultando o bucket. Também sugeriria usar funções do IAM para fornecer aos servidores virtuais de produção acesso somente leitura ao bucket do S3 sem nenhuma credencial de API codificada. Este esquema protege seus lançamentos e baldes caso um invasor consiga acessar seus servidores. Como não há credenciais de API codificadas, elas não podem sofrer engenharia reversa nem sofrer abuso em outro lugar.

Os ambientes de desenvolvimento e criação podem ser configurados de maneira semelhante - o servidor de criação ou o servidor de IC pode ter uma função de acesso de leitura / gravação ao bloco se ele residir na infraestrutura da AWS. Se o seu servidor de criação / CI estiver em outro local, você poderá configurar um grupo IAM com direitos de acesso apropriados ao S3 e criar um usuário do IAM com credenciais de API para uso em um site externo.

Você ainda precisa preparar uma AMI para que baixe e configure o release como deseja e inicie o aplicativo, mas pelo menos não precisará repetir esse processo toda vez que fizer uma nova versão. Usar alguma ferramenta de gerenciamento de configuração, como Chef, Puppet ou Ansible, provavelmente pode fazer tudo o que você deseja, mas é preciso alocar algum tempo para se familiarizar com as ferramentas e modelar seu ambiente com elas.

A infraestrutura (balanceadores de carga, asgs, securitygroups, funções, etc.) pode ser modelada, criada e mantida com o AWS CloudFormation. Se o seu ambiente se tornar mais complexo do que um único ELB e um único ASG, recomendo dar uma olhada nisso. Ao modelar sua infraestrutura com o CloudFormation, você pode criar e manter facilmente cópias exatas de todo o seu ambiente - uma para testar / qa e uma para produção, por exemplo. A descrição da infra-estrutura é um documento json que pode ser mantido em seu repositório VCS.

Espero que isso ajude.

    
por 27.09.2014 / 15:12
1

Idealmente, seu sistema de autoprovisionamento deve se conectar ao seu ambiente de implementação para extrair o código inicial para novos nós. Grupos de escalonamento automático são ótimos para obter instâncias criadas, mas o problema de atualização de código é deixado como um exercício para o usuário. Assar seu código no AMI funciona bem, a menos que você esteja atualizando o código várias vezes por dia; Nesse caso, é melhor criar um mecanismo de implementação de código separado.

Realmente depende do seu código. Você tem algumas maneiras de fazer isso.

Pull Deploys

Este é o método que você descreveu: cada nó monitora algo e, uma vez que o evento de mudança aconteça, ele sabe puxar um novo código. Existem várias maneiras de conseguir isso.

  • Tarefas Cron que verificam um arquivo ou URL a cada n minutos.
  • Ansible ou algo similar publica uma coisa atualizada e agentes pesquisam e executam a ação UpdateCode.
  • O próprio código tem ganchos para pesquisar um serviço de fila e executa trabalhos de atualização quando eles chegam.

A vantagem aqui é que você pode dimensionar sua infra-estrutura de implementação de código muito bem. Os métodos de extração significam que o intervalo em que sua camada de código está executando duas versões é mais longo, o que reduz a robustez da infra-estrutura de implantação.

No entanto, você disse que não pode tolerar várias versões de código. Isso vai ser um problema. Puxar provavelmente não é o método que você quer no momento (embora acabe sendo).

Push Implanta

Este método tem código pressionado nos nós. Como puxar, há várias maneiras de fazer isso:

  • Algo como o capistrano, no qual o Grupo de dimensionamento é pesquisado em busca de uma lista de instâncias e o código é enviado paralelamente a todos os nós ao mesmo tempo.
  • Um modo diferente de Ansible ou algo similar em que um agente em cada nó é notificado pelo nó mestre para atualizar o código agora mesmo.
  • Uma chave de esquema é atualizada em seu banco de dados e seu código é inteligente o suficiente para perceber isso e dar início a um processo de autoatualização antes que ele funcione mais.

A vantagem de empurrar é que é mais fácil manter uma estreita sincronicidade em sua base de código. Se você realmente precisa de um nível restrito de apenas uma versão, é mais fácil de fazer. Dependendo de como você configurou seus intervalos de escala, é possível desativar parte de suas instâncias, atualizar o código no subconjunto e ativá-las. Uma chave de esquema em seu banco de dados informa o código para não processar nenhum trabalho e encaminhar solicitações para aqueles que possuem a chave correta. Atualize a chave no banco de dados e, em alguns milissegundos, os novos nós de código começarão a fazer todo o trabalho e os nós do código antigo começarão a encaminhar. Em seguida, atualize o código na outra camada.

Se os grupos de escalonamento não tolerarem a interrupção do código ... você provavelmente precisará ir a um sistema A / B para grupos de escalabilidade. Atualize o código no Grupo B, inverta o bit no banco de dados, mude o ELB para apontar para o Grupo B. Inverta para a próxima atualização.

Quais métodos você usa depende inteiramente de quão tolerante é o seu aplicativo geral para várias versões de código executadas ao mesmo tempo. Um sistema distribuído como este é um sistema complexo, e o estado em uma parte do sistema será ligeiramente diferente do que em outra parte do sistema, não importa o quanto você tente. Quanto menos tolerante você for, mais falta de energia terá de incorrer toda vez que atualizar o código. A interrupção pode ser inferior a um segundo, mas ainda é falta de energia.

    
por 27.09.2014 / 14:01