Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

Para começar, um pouco de teoria. O que é The Twelve-Factor App?

Em termos simples, é um documento que visa simplificar o desenvolvimento de aplicativos SaaS, ajudando os desenvolvedores e engenheiros de DevOps a entender os problemas e as práticas que mais comumente surgem no desenvolvimento de aplicativos modernos.

O documento foi elaborado pelos desenvolvedores da plataforma Heroku.

A metodologia de doze fatores (The Twelve-Factor App) pode ser aplicada a aplicativos escritos em qualquer linguagem de programação e que utilizam quaisquer combinações de serviços externos (backing services) (bancos de dados, filas de mensagens, cache, etc.).

Resumidamente, aqui estão os fatores que sustentam essa metodologia:

  1. Base de código – Uma base de código, rastreada em um sistema de controle de versão, – múltiplas implantações
  2. Dependências – Declare e isole dependências explicitamente
  3. Configuração – Mantenha a configuração no ambiente de execução
  4. Serviços externos (Backing Services) – Considere serviços externos (backing services) como recursos conectáveis
  5. Construção, lançamento, execução – Separe rigorosamente as etapas de construção e execução
  6. Processos – Execute o aplicativo como um ou mais processos sem estado (stateless)
  7. Vinculação de portas (Port binding) – Exporte serviços por meio da vinculação de portas
  8. Paralelismo – Escalone o aplicativo usando processos
  9. Descartabilidade (Disposability) – Maximize a confiabilidade com inicialização rápida e encerramento ordenado
  10. Paridade de desenvolvimento/produção do aplicativo – Mantenha os ambientes de desenvolvimento, de staging e de produção o mais semelhantes possível
  11. Registro (Logs) – Considere o log como um fluxo de eventos
  12. Tarefas administrativas – Execute tarefas de administração/gerenciamento usando processos únicos

Mais informações sobre os 12 fatores podem ser obtidas a partir dos seguintes recursos:

O que é Blue-Green deployment?

Blue-Green deployment é uma forma de entrega de aplicativo. production dessa forma, o cliente final não percebe nenhuma alteração do seu lado. Em outras palavras, a implantação do aplicativo ocorre com zero downtime.

O esquema clássico do BG Deploy é como mostrado na imagem abaixo.

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

  • No início, há 2 servidores físicos com o mesmo código, aplicativo, projeto, e há um roteador (balanceador).
  • O roteador inicialmente direciona todas as solicitações para um dos servidores (alfa).
  • No momento em que é necessário lançar novamente, todo o projeto é atualizado em outro servidor (azul), que no momento não está processando nenhuma solicitação.
  • Depois que o código no servidor azul estiver completamente atualizado, o roteador recebe a ordem de mudar do servidor verde para azul servidor.
  • Agora todos os clientes veem o resultado do trabalho do código no servidor azul servidor físico.
  • Por um tempo, alfa o servidor serve como backup caso a implantação no azul servidor falhe e, em caso de falha e bugs, o roteador redireciona o fluxo de usuários de volta para o alfa servidor com a versão estável antiga, enquanto o novo código é enviado para melhorias e testes.
  • E no final do processo, o alfa servidor também é atualizado. E após sua atualização, o roteador redireciona o fluxo de solicitações de volta para alfa servidor.

Isso tudo parece muito bom e, à primeira vista, não deve haver problemas com isso.
Mas como vivemos em um mundo moderno, a opção de troca física, como indicado no esquema clássico, não é adequada para nós. Por enquanto, registre essas informações, retornaremos a elas mais tarde.

Conselhos bons e ruins

Aviso Legal: Nos exemplos abaixo estão utilitários / metodologias que eu uso, você pode utilizar absolutamente quaisquer alternativas com funções semelhantes.

A maior parte dos exemplos irá, de alguma forma, se sobrepor ao desenvolvimento web (surpresa, não é?), ao PHP e ao Docker.

Nos pontos abaixo, há uma descrição prática simples do uso de fatores em exemplos específicos; se você deseja obter mais teoria sobre o assunto, consulte as referências acima ao material original.

1. Código fonte

Use FTP e FileZilla para carregar arquivos nos servidores um a um, não armazene o código em nenhum lugar além do servidor de produção.

O projeto deve sempre ter uma única base de código, ou seja, todo o código vem de uma só fonte. Git repositórios. Os servidores (produção, homologação, teste1, teste2 …) utilizam código das ramificações de um repositório compartilhado. Dessa forma, conseguimos garantir a consistência do código.

2. Dependências

Baixe todas as bibliotecas em pastas diretamente na raiz do projeto. As atualizações devem ser feitas simplesmente transferindo o novo código para a pasta com a versão atual da biblioteca. Instale todas as utilidades diretamente no servidor de hospedagem onde operam mais 20 serviços.

Um projeto deve sempre ter uma lista de dependências claramente definida (entendo por dependências também o ambiente). Todas as dependências devem ser explicitamente definidas e isoladas.
Como exemplo, vamos considerar Composer e Docker.

Composer — um gerenciador de pacotes que permite instalar bibliotecas PHP. O Composer possibilita especificar versões de forma rigorosa ou não, e defini-las claramente. No servidor, podem existir 20 projetos diferentes, cada um com sua própria lista de pacotes e bibliotecas, sem depender uns dos outros.

Docker — uma ferramenta que permite definir e isolar o ambiente em que o aplicativo irá operar. Consequentemente, assim como acontece com o Composer, mas de uma forma mais robusta, podemos definir com o que o aplicativo trabalha. Escolha uma versão específica do PHP, instale apenas os pacotes necessários para o funcionamento do projeto, sem adicionar nada desnecessário. E o mais importante, sem interferir nos pacotes e no ambiente do servidor de hospedagem e de outros projetos. Assim, todos os projetos no servidor que operam através do Docker podem utilizar qualquer conjunto de pacotes e ambientes completamente diferentes.

3. Configuração

Armazene as configurações como constantes diretamente no código. Constantes distintas para o servidor de teste e para o ambiente de produção. Conecte o funcionamento do aplicativo às dependências do ambiente diretamente na lógica de negócios do projeto, utilizando estruturas if else.

Configurações — é a única coisa que deve diferenciar as implantações do projeto. Idealmente, as configurações devem ser transmitidas através de variáveis de ambiente (env vars).

Ou seja, mesmo que você armazene vários arquivos de configuração .config.prod e .config.local e os renomeie no momento da implantação para .config (configuração principal de onde o aplicativo lê os dados) — isso não será uma abordagem correta, pois, dessa forma, as informações das configurações estarão acessíveis a todos os desenvolvedores do aplicativo e os dados do servidor de produção estarão comprometidos. Todas as configurações devem ser armazenadas diretamente no sistema de implantação (CI/CD) e geradas para diferentes ambientes com valores distintos necessários para cada ambiente exatamente no momento da implantação.

4. Serviços de terceiros (Backing Services)

Crie uma forte dependência do ambiente, utilizando diferentes conexões para os mesmos serviços em determinados ambientes.

Na verdade, este ponto está intimamente relacionado ao ponto sobre configurações, pois sem a presença deste item não será possível ter dados de configuração adequados e, de fato, a capacidade de configuração se tornará obsoleta.

Todas as conexões com serviços externos, como servidores de filas, bancos de dados e serviços de cache, devem ser consistentes tanto para o ambiente local quanto para o externo / ambiente de produção. Em outras palavras, a qualquer momento, eu posso mudar a string de conexão e substituir as chamadas ao banco #1 pelo banco #2 sem alterar o código do aplicativo. Ou, antecipando um exemplo, ao escalar o serviço, você não precisará indicar a conexão de uma maneira especial para um novo servidor de cache.

5. Construção, lançamento, execução

Tenha apenas a versão final do código no servidor, sem chances de reverter o lançamento. Não é necessário consumir espaço em disco. Quem acha que pode lançar código em produção com erro é um mau programador!

Todas as etapas de implantação devem ser separadas entre si.

Tenha a possibilidade de reverter. Faça lançamentos mantendo cópias antigas do aplicativo (já compiladas e prontas para uso) em acesso rápido, para que, em caso de erros, seja possível restaurar a versão anterior. Ou seja, existe uma pasta releases e uma pasta corrente, e após uma implantação e compilação bem-sucedidas, a pasta corrente é vinculada por um link simbólico ao novo lançamento que está dentro releases com um nome correspondente ao número do lançamento.

Aqui lembramos do Blue-Green deployment, que permite não apenas alternar entre códigos, mas também entre todos os recursos e até ambientes, com a capacidade de reverter tudo.

6. Processos

Armazene os dados de estado do aplicativo diretamente no próprio aplicativo. Utilize sessões na memória do próprio aplicativo. Aproveite ao máximo o que pode ser compartilhado entre serviços externos. Baseie-se no fato de que o aplicativo pode ter apenas um processo e não permita a possibilidade de escalonamento.

Em relação às sessões, armazene os dados apenas em cache controlado por serviços externos (memcached, redis). Assim, mesmo que você tenha 20 processos do aplicativo em execução, qualquer um deles que acessar o cache poderá continuar trabalhando com o cliente no mesmo estado em que o usuário estava ao interagir com o aplicativo em outro processo. Com essa abordagem, não importa quantas instâncias de serviços externos você utilize, tudo funcionará normalmente e sem problemas de acesso aos dados.

7. Ligação de Portos (Port binding)

Somente o servidor web deve saber como trabalhar com serviços externos. Melhor ainda, suba serviços externos diretamente dentro do servidor web, como um módulo PHP no Apache.
Todos os seus serviços devem ser acessíveis entre si através de um endereço e porta (localgost:5432, localhost:3000, nginx:80, php-fpm:9000). Assim, a partir do nginx eu posso acessar tanto o php-fpm quanto o postgres, e a partir do php-fpm eu posso acessar o postgres e o nginx. Dessa maneira, a viabilidade de um serviço não depende da viabilidade de outro serviço.

8. Paralelismo

Trabalhe com um único processo, pois vários processos podem não conseguir se entender!

Deixe a possibilidade de escalabilidade. O Docker Swarm é uma ótima opção para isso.
Docker Swarm é uma ferramenta para criar e gerenciar clusters de contêineres, tanto entre diferentes máquinas quanto um monte de contêineres em uma única máquina.

Usando swarm, posso determinar quanta capacidade vou alocar para cada processo e qual a quantidade de processos do mesmo serviço que vou iniciar, e o balanceador interno, recebendo dados na porta designada, irá automaticamente proxy esses dados para os processos. Assim, ao notar que a carga no servidor aumentou, posso adicionar mais processos, reduzindo assim a carga em processos específicos.

9. Descartabilidade (Disposability)

Não use filas para trabalhar com processos e dados. A finalização de um processo deve impactar o funcionamento de toda a aplicação. Se um serviço falhar, tudo falha.

Cada processo e serviço podem ser desligados a qualquer momento, e isso não deve afetar outros serviços (não se referindo a que o serviço ficará indisponível para outro serviço, mas sim que outro serviço não irá desativar se seguir este). Todos os processos devem ser encerrados suavemente, de modo que ao finalizá-los, os dados não sejam prejudicados, e ao ligá-los novamente, o sistema funcione corretamente. Em outras palavras, mesmo em caso de encerramento abrupto, os dados não devem ser danificados (um mecanismo de transações é adequado, onde as solicitações ao banco de dados funcionam apenas em grupos, e se uma solicitação do grupo falhar ou ocorrer um erro, nenhuma outra solicitação do grupo será realmente executada).

10. Paridade entre Desenvolvimento e Operação da Aplicação

As versões de produção, estágio e local da aplicação devem ser diferentes. Em produção, utilizamos o framework Yii Lite, enquanto localmente usamos o Yii, para que funcione mais rápido em produção!

Na verdade, todos os desdobramentos e o trabalho com o código devem ocorrer em ambientes praticamente idênticos (não me refiro ao hardware físico). Além disso, a implementação do código em produção deve ser realizada por qualquer membro da equipe de desenvolvimento, e não apenas por alguma equipe de devops especificamente treinada que, devido a alguma habilidade especial, pode iniciar a aplicação em produção.

Isso também é facilitado pelo Docker. Com a adesão a todos os pontos anteriores, o uso do docker tornará o processo de desdobramento em um ambiente tanto em produção quanto em uma máquina local em apenas um ou dois comandos.

11. Registro (Logs)

Escrevemos logs em arquivos e no banco de dados! Não limpamos arquivos e bancos de dados de logs. Vamos simplesmente comprar um disco rígido de 9000 Petabytes e está bom.

Todos os logs devem ser considerados como um fluxo de eventos. O próprio aplicativo não deve processar logs. Os logs devem ser enviados para stdout ou transmitidos por um protocolo como o UDP, para que o trabalho com logs não cause problemas para o aplicativo. Para isso, o graylog é uma boa opção. Ao aceitar todos os logs via UDP (neste protocolo, não é necessário esperar por uma confirmação de recebimento do pacote), o graylog não interfere de forma alguma no aplicativo e se ocupa apenas de estruturar e processar logs. A lógica do aplicativo não muda para trabalhar com essas abordagens.

12. Tarefas de administração

Para atualizar dados, banco de dados, etc., utilize um endpoint separado na API. A execução deste dois vezes seguidas pode resultar em duplicação de dados. Mas vocês não são tolos, não clicariam duas vezes, e migrações não são necessárias.

Todas as tarefas de administração devem ser realizadas no mesmo ambiente que todo o código, ao nível de releases. Ou seja, se precisamos alterar a estrutura do banco de dados, não o faremos manualmente mudando nomes de colunas e adicionando novas por meio de ferramentas visuais de gerenciamento de banco de dados. Para essas tarefas, criamos scripts separados — migrações, que são executadas em todos os ambientes de forma consistente e com resultados claros. Para todas as outras tarefas, como preencher o projeto com dados, devem ser aplicadas metodologias semelhantes.

Exemplo de implementação em PHP, Laravel, Laradock, Docker-Compose

P.S. Todos os exemplos foram feitos no MacOS. A maior parte servirá também para Linux. Usuários Windows, peço desculpas, mas não trabalho com Windows há muito tempo.

Vamos imaginar uma situação em que nenhuma versão do PHP está instalada no PC e na verdade nada está instalado.
Instalamos as versões mais recentes do Docker e do Docker Compose. (isso pode ser encontrado na internet)

docker -v && 
docker-compose -v

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

1. Instalamos Laradock

git clone https://github.com/Laradock/laradock.git && 
ls

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

Sobre o Laradock, posso dizer que é uma ferramenta muito útil, que reúne muitos contêineres e utilitários. Mas usar o Laradock como está em produção — eu não recomendaria devido à sua complexidade. É melhor criar seus próprios contêineres com base nos exemplos do Laradock, assim haverá espaço para otimização, pois ninguém precisa de tudo o que existe lá ao mesmo tempo.

2. Configuramos o Laradock para o funcionamento do nosso aplicativo.

cd laradock && 
cp env-example .env

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

2.1. Abra o diretório habr (a pasta pai onde o laradock foi clonado) em qualquer editor. (No meu caso, PHPStorm)

Nesta etapa, vamos apenas dar um nome ao projeto.

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

2.2. Iniciamos a imagem workspace. (No seu caso, as imagens levarão algum tempo para serem construídas)
Workspace é uma imagem especialmente preparada para trabalhar com o framework em nome do desenvolvedor.

Vamos dentro do contêiner usando

docker-compose up -d workspace && 
docker-compose exec workspace bash

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

2.3. Instalamos o Laravel

composer create-project --prefer-dist laravel/laravel application

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

2.4. Depois da instalação, verificamos se a diretório do projeto foi criada e encerramos o compose.

ls
exit
docker-compose down

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

2.5. Voltamos para o PHPStorm e definimos o caminho correto para nossa aplicação Laravel no arquivo .env.

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

3. Adicionamos todo o código ao Git.

Para isso, vamos criar um repositório no Github (ou em qualquer outro lugar). Vamos para a pasta habr no terminal e executamos o seguinte código.

echo "# habr-12factor" >> README.md
git init
git add README.md
git commit -m "primeiro commit"
git remote add origin git@github.com:nzulfigarov/habr-12factor.git # aqui estará o link para seu repositório
git push -u origin master
git status

Verificamos se tudo está em ordem.

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

Para conveniência, recomendo usar alguma interface visual para Git, no meu caso é GitKraken. (aqui está o link de referência)

4. Vamos começar!

Antes de iniciar, assegure-se de que nada está rodando nas portas 80 e 443.

docker-compose up -d nginx php-fpm

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

Assim, nosso projeto consiste em 3 serviços separados:

  • nginx — servidor web
  • php-fpm — PHP para receber solicitações do servidor web
  • workspace — PHP para desenvolvedor

Até o momento, conseguimos criar uma aplicação que atende a 4 dos 12 pontos, a saber:

1. Base de código — todo o código está em um único repositório (uma pequena observação: pode ser mais correto incorporar o docker dentro do projeto Laravel, mas isso não é fundamental).

2. Dependências — Todas as nossas dependências estão claramente especificadas em application/composer.json e em cada Dockerfile de cada contêiner.

3. Serviços externos (Backing Services) — Cada um dos serviços (php-fpm, nginx, workspace) vive sua própria vida e é conectado externamente, então ao trabalhar com um serviço, o outro não será afetado.

4. Processos — cada serviço é um único processo. Cada um dos serviços não mantém estado interno.

5. Vinculação de portas (Port binding)

docker ps

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

Como podemos ver, cada serviço está rodando na sua própria porta e acessível a todos os outros serviços.

6. Paralelismo

O Docker nos permite iniciar vários processos dos mesmos serviços com balanceamento automático de carga entre eles.

Vamos parar os contêineres e iniciá-los com a flag —scale

docker-compose down && 
docker-compose up -d --scale php-fpm=3 nginx php-fpm

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

Como podemos ver, o contêiner php-fpm criou cópias. Não precisamos mudar nada neste contêiner. Continuamos acessando-o pela porta 9000, enquanto o Docker gerencia a carga entre os contêineres.

7. Descartabilidade (Disposability) — cada contêiner pode ser parado sem prejudicar outro. Parar ou reiniciar um contêiner não afetará a operação do aplicativo em execuções futuras. Cada contêiner também pode ser levantado a qualquer momento.

8. Paridade de desenvolvimento/produção do aplicativo — todos os nossos ambientes são idênticos. Ao iniciar o sistema em um servidor de produção, você não precisará mudar nada em seus comandos. Tudo funcionará exatamente com base no Docker.

9. Registro (Logs) — todos os logs desses contêineres são direcionados para o fluxo e visíveis no console do Docker. (neste caso, na verdade, com outros contêineres personalizados, pode não ser assim se você não cuidar disso)

 docker-compose logs -f

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

Mas, aqui está a pegadinha: os valores padrão em PHP e Nginx também gravam logs em arquivo. Para atender aos 12 fatores, é necessário desativar a gravação de logs em arquivo nas configurações de cada contêiner separadamente.

O Docker também oferece a possibilidade de direcionar logs não apenas para stdout, mas também para coisas como graylog, como eu mencionei acima. E dentro do graylog, podemos operar os logs como quisermos e nosso aplicativo não perceberá isso.

10. Tarefas administrativas — todas as tarefas administrativas são resolvidas pelo Laravel graças à ferramenta artisan, exatamente como os criadores do 12 fatores desejariam.

Como exemplo, vou mostrar como alguns comandos são executados.
Entramos no contêiner.

 
docker-compose exec workspace bash
php artisan list

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

Agora podemos usar qualquer comando. (note que não configuramos o banco de dados e o cache, portanto metade dos comandos não será executada corretamente, pois estão destinados ao trabalho com cache e bds).

Desenvolvimento de aplicativos e Blue-Green deployment, baseado na metodologia The Twelve-Factor App com exemplos em php e docker

11. Configurações e 12. Construção, lançamento, execução

Esta parte eu queria dedicar ao Blue-Green Deployment, mas isso se mostrou muito extenso para este artigo. Vou escrever um artigo separado sobre isso.

Em poucas palavras, o conceito é baseado em sistemas CI/CD como Jenkins e Gitlab CI. Em ambos, você pode definir variáveis de ambiente relacionadas a um ambiente específico. Assim, nessa configuração, o ponto sobre Configurações.

E o ponto sobre Construção, lançamento, execução é resolvido por funções integradas em ambas as ferramentas chamadas Pipeline.

Pipeline permite dividir o processo de implantação em várias etapas, destacando as fases de construção, lançamento e execução. No Pipeline, você também poderá criar backups e fazer praticamente qualquer coisa. Esta ferramenta possui um potencial ilimitado.

O código do aplicativo está localizado em Github.
Não se esqueça de inicializar o submódulo ao clonar este repositório.

P.S.: Todas essas abordagens podem ser usadas com quaisquer outras ferramentas e linguagens de programação. O importante é que a essência não mude.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster