CI/CD no Github Actions para um projeto em Flask+Angular

CI/CD no Github Actions para um projeto em Flask+Angular
Neste artigo, compartilharei minha experiência na configuração de CI/CD usando o painel de controle Plesk e o Github Actions. Hoje, vamos aprender a fazer o deploy de um projeto simples chamado "Helloworld". Ele é desenvolvido no framework Flask em Python, com workers no Celery e frontend em Angular 8.

Links para os repositórios: backend, frontend.

Na primeira parte do artigo, veremos nosso projeto e suas partes. Na segunda, entenderemos como configurar o Plesk e instalar as extensões e componentes necessários (BD, RabbitMQ, Redis, Docker, etc.).

Na terceira parte, finalmente entenderemos como configurar o pipeline para o deploy do nosso projeto no servidor em ambiente dev e prod. Depois, vamos lançar o site no servidor.

E sim, esqueci de me apresentar. Me chamo Oleg Borzov, sou desenvolvedor fullstack na equipe de CRM para gerentes de crédito hipotecário no Domclick.

Visão Geral do Projeto

Para começar, vamos examinar dois repositórios do projeto — o backend e o frontend — e dar uma olhada no código.

Parte do backend: Flask+Celery

Para a parte backend, escolhi uma combinação bastante popular entre desenvolvedores Python: o framework Flask (para API) e o Celery (para gerenciamento de filas). Utiliza-se o SQLAlchemy como ORM. Para migrações, aplicamos o Alembic. Para validação de JSON nas rotas, usamos o Marshmallow.

Em repositório existe um arquivo Readme.md com uma descrição detalhada da estrutura e instruções para iniciar o projeto.

API do frontend é bastante simples, composta por 6 rotas:

  • /ping — para verificar a disponibilidade;
  • rotas para registro, autorização, desautorização e obtenção do usuário autorizado;
  • uma rota para enviar email, que coloca a tarefa na fila do Celery.

Parte do Celery é ainda mais simples, há apenas uma tarefa send_mail_task.

Na pasta /conf existem duas pastas secundárias:

  • docker com dois arquivos Docker (base.dockerfile para construir uma imagem base que muda raramente e Dockerfile para as construções principais);
  • .env_files — com arquivos contendo variáveis de ambiente para diferentes ambientes.

Na raiz do projeto, existem quatro arquivos docker-compose:

  • docker-compose.local.db.yml para levantar o BD local para desenvolvimento;
  • docker-compose.local.workers.yml para levantar localmente o worker, BD, Redis e RabbitMQ;
  • docker-compose.test.yml para executar testes durante o deploy;
  • docker-compose.yml para o deploy.

E a última pasta interessante para nós — .ci-cd. Dentro dela estão scripts shell para o deploy:

  • deploy.sh — execução de migrações e deploy. É executado no servidor após a compilação e execução de testes no Github Actions;
  • rollback.sh — reverter contêineres para a versão anterior da construção;
  • curl_tg.sh — envio de notificações sobre o deploy no Telegram.

Frontend em Angular

Repositório com o front-end significativamente mais simples que o back-end. O front-end consiste em três páginas:

  • Página inicial com um formulário para envio de email e um botão de saída.
  • Página de login.
  • Página de registro.

A página inicial tem um design minimalista:

CI/CD no Github Actions para um projeto em Flask+Angular
Na raiz há dois arquivos Dockerfile e docker-compose.yml, além da pasta familiar .ci-cd com um número um pouco menor de scripts em comparação com o repositório do back-end (os scripts para execução de testes foram removidos).

Criando o projeto no Plesk

Vamos começar configurando o Plesk e criando uma assinatura para o nosso site.

Instalação de extensões

No Plesk, precisamos de quatro extensões:

  • Docker para gerenciar e visualizar o estado dos contêineres na interface administrativa do Plesk;
  • Git para configurar o passo de implantação no servidor;
  • Let's Encrypt para geração (e renovação automática) de certificados TLS gratuitos;
  • Firewall para configurar a filtragem de tráfego de entrada.

Podemos instalá-las através da interface administrativa do Plesk na seção de Extensões:

CI/CD no Github Actions para um projeto em Flask+Angular
Não vamos abordar a configuração detalhada das extensões; as configurações padrão são suficientes para nossos objetivos de demonstração.

Criação de assinatura e site

A seguir, precisamos criar uma assinatura para o nosso site helloworld.ru e adicionar um subdomínio dev.helloworld.ru.

  1. Criamos uma assinatura para o domínio helloworld.ru e indicamos um login e senha para o usuário do sistema:

    CI/CD no Github Actions para um projeto em Flask+Angular
    Na parte inferior da página, marcamos a caixa Secure the domain with Let’s Encrypt, se quisermos configurar HTTPS para o site:

    CI/CD no Github Actions para um projeto em Flask+Angular

  2. Em seguida, nesta assinatura, criamos o subdomínio dev.helloworld.ru (para o qual também podemos emitir um certificado TLS gratuito):

    CI/CD no Github Actions para um projeto em Flask+Angular

Instalação dos componentes do servidor

Temos um servidor com OS Debian Stretch 9.12 e com o painel de controle instalado Plesk Obsidian 18.0.27.

Precisamos instalar e configurar para o nosso projeto:

  • PostgreSQL (neste caso, teremos um servidor com dois bancos de dados para os ambientes dev e prod).
  • RabbitMQ (o mesmo, uma instância com diferentes vhosts para os ambientes).
  • Duas instâncias do Redis (para os ambientes dev e prod).
  • Docker Registry (para armazenamento local de imagens Docker construídas).
  • Interface de usuário para o registro Docker.

PostgreSQL

O Plesk já vem com o banco de dados PostgreSQL incluído, embora não na versão mais recente (no momento da escrita deste artigo, o Plesk Obsidian suportava versões do Postgres de 8.4 a 10.8). Queremos ter a versão mais recente para nosso aplicativo (12.3 no momento da escrita deste artigo), então iremos instalá-la manualmente.

Instruções detalhadas sobre como instalar o Postgres no Debian podem ser facilmente encontradas na internet (exemplo), portanto, não vou descrevê-las em detalhes, apenas vou fornecer os comandos:

wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O - | sudo apt-key add -
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main" >> /etc/apt/sources.list.d/pgdg.list'

sudo apt-get update
sudo apt-get install postgresql postgresql-contrib

Considerando que o PostgreSQL possui configurações padrão bastante medianas, é imprescindível ajustar a configuração. Para isso, podemos contar com calculador: é necessário inserir os parâmetros do seu servidor e substituir as configurações no arquivo /etc/postgresql/12/main/postgresql.confpelas sugeridas. É importante observar que tais calculadoras não são uma solução mágica, e o banco de dados deve ser ajustado de forma mais precisa, considerando seu hardware, aplicações e complexidade das consultas. Mas, para começar, isso é suficiente.

Além das configurações sugeridas pela calculadora, também alteramos no postgresql.confa porta 5432, que está configurada por padrão, para outra (no nosso exemplo — 53983).

Após alterar o arquivo de configuração, reiniciamos o postgresql-server com o comando:

service postgresql restart

Instalamos e configuramos o PostgreSQL. Agora vamos criar o banco de dados, usuários para os ambientes dev e prod, e conceder aos usuários permissões para gerenciar o banco de dados:

$ su - postgres
postgres:~$ create database hw_dev_db_name;
CREATE DATABASE
postgres:~$ create user hw_dev_db_user with password 'hw_dev_db_password';
CREATE ROLE
postgres:~$ grant ALL privileges ON database hw_dev_db_name to hw_dev_db_user;
GRANT
postgres:~$ create database hw_prod_db_name;
CREATE DATABASE
postgres:~$ create user hw_prod_db_user with password 'hw_prod_db_password';
CREATE ROLE
postgres:~$ grant ALL privileges ON database hw_prod_db_name to hw_prod_db_user;
GRANT

RabbitMQ

Vamos agora instalar o RabbitMQ — o broker de mensagens para Celery. A instalação no Debian é bastante simples:

wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
sudo dpkg -i erlang-solutions_1.0_all.deb

sudo apt-get update
sudo apt-get install erlang erlang-nox

sudo add-apt-repository 'deb http://www.rabbitmq.com/debian/ testing main'
wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -

sudo apt-get update
sudo apt-get install rabbitmq-server

Após a instalação, precisamos criar vhosts, usuários e conceder as permissões necessárias:

sudo rabbitmqctl add_user hw_dev_amqp_user hw_dev_amqp_password 
sudo rabbitmqctl set_user_tags hw_dev_amqp_user administrator
sudo rabbitmqctl add_vhost hw_dev_vhost
sudo rabbitmqctl set_permissions -p hw_dev_vhost hw_dev_amqp_user ".*" ".*" ".*"

sudo rabbitmqctl add_user hw_prod_amqp_user hw_prod_amqp_password 
sudo rabbitmqctl set_user_tags hw_prod_amqp_user administrator
sudo rabbitmqctl add_vhost hw_prod_vhost
sudo rabbitmqctl set_permissions -p hw_prod_vhost hw_prod_amqp_user ".*" ".*" ".*"

Redis

Agora vamos instalar e configurar o último componente para nossa aplicação — o Redis. Ele será utilizado como backend para armazenar os resultados das tarefas do Celery.

Iremos levantar dois contêineres Docker com Redis para os ambientes dev e prod utilizando a extensão Docker para Plesk.

  1. Acesse o Plesk, vá para a seção Extensões, busque pela extensão Docker e instale-a (precisamos da versão gratuita):

    CI/CD no Github Actions para um projeto em Flask+Angular

  2. Vá para a extensão instalada, busque pela imagem redis bitnami e instale a última versão:

    CI/CD no Github Actions para um projeto em Flask+Angular

  3. Acesse o contêiner baixado e ajuste a configuração: especifique a porta, o tamanho máximo da RAM, a senha nas variáveis de ambiente e monte o volume:

    CI/CD no Github Actions para um projeto em Flask+Angular

  4. Repita os passos 2-3 para o contêiner prod, alterando apenas os parâmetros: porta, senha, tamanho da RAM e caminho da pasta volume no servidor:

    CI/CD no Github Actions para um projeto em Flask+Angular

Docker Registry

Além dos serviços básicos, seria bom instalar um repositório Docker próprio no servidor. Felizmente, o espaço nos servidores é bastante barato atualmente (definitivamente mais barato do que uma assinatura do DockerHub), e o processo de instalação de um repositório privado é muito simples.

Queremos ter instalado:

Para isso:

  1. Criaremos no Plesk dois subdomínios em nossa assinatura: docker.helloworld.ru e docker-ui.helloworld.ru, e configuraremos certificados Let’s Encrypt para eles.
  2. Na pasta do subdomínio docker.helloworld.ru, adicionaremos o arquivo docker-compose.yml com o seguinte conteúdo:
    version: "3"
    
    services:
      docker-registry:
        image: "registry:2"
        restart: always
        ports:
          - "53985:5000"
        environment:
          REGISTRY_AUTH: htpasswd
          REGISTRY_AUTH_HTPASSWD_REALM: basic-realm
          REGISTRY_AUTH_HTPASSWD_PATH: /auth/.htpasswd
          REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
        volumes:
          - ./docker-registry.htpasswd:/auth/.htpasswd
          - ./data:/data
    
      docker-registry-ui:
        image: konradkleine/docker-registry-frontend:v2
        restart: always
        ports:
          - "53986:80"
        environment:
          VIRTUAL_HOST: '*, https://*'
          ENV_DOCKER_REGISTRY_HOST: 'docker-registry'
          ENV_DOCKER_REGISTRY_PORT: 5000
        links:
          - 'docker-registry'
    

  3. Via SSH, geraremos o arquivo .htpasswd para a autenticação básica no repositório Docker:
    htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password
  4. Vamos construir e subir os contêineres:
    docker-compose up -d
  5. E precisamos redirecionar o Nginx para os nossos contêineres. Isso pode ser feito através do Plesk.

As próximas ações devem ser realizadas para os subdomínios docker.helloworld.ru e docker-ui.helloworld.ru:

Na seção Dev Tools Acesse nosso site e vá para Regras de Proxy do Docker:

CI/CD no Github Actions para um projeto em Flask+Angular
E adicione uma regra para fazer proxy do tráfego de entrada para nosso contêiner:

CI/CD no Github Actions para um projeto em Flask+Angular

  1. Verifique se conseguimos nos autenticar em nosso contêiner a partir da máquina local:
    $ docker login docker.helloworld.ru -u hw_docker_admin -p hw_docker_password
    WARNING! Using --password via the CLI is insecure. Use --password-stdin.
    Login Succeeded
  2. Também verificaremos o funcionamento do subdomínio docker-ui.helloworld.ru:

    CI/CD no Github Actions para um projeto em Flask+Angular
    Ao clicar em Navegar repositórios, o navegador exibirá uma janela de autenticação onde você precisará inserir seu nome de usuário e senha para o repositório. Após isso, seremos redirecionados para a página com a lista de repositórios (que estará vazia por enquanto):

    CI/CD no Github Actions para um projeto em Flask+Angular

Abrindo portas no Plesk Firewall

Após a instalação e configuração dos componentes, precisamos abrir portas para que os componentes sejam acessíveis a partir de containers Docker e da rede externa.

Vamos ver como fazer isso usando como exemplo a extensão Firewall que instalamos anteriormente para Plesk.

  1. Vamos para Ferramentas & Configurações > Configurações > Firewall:
    CI/CD no Github Actions para um projeto em Flask+Angular
  2. Vamos para Modificar Regras do Plesk Firewall > Adicionar Regra Personalizada e abrir as seguintes portas TCP para a subnet Docker (172.0.0.0/8):
    RabbitMQ: 1883, 4369, 5671-5672, 25672, 61613-61614
    Redis: 32785, 32786

    CI/CD no Github Actions para um projeto em Flask+Angular

  3. Também adicionaremos uma regra que abrirá para o mundo externo as portas do PostgreSQL e do painel de gerenciamento do RabbitMQ:

    CI/CD no Github Actions para um projeto em Flask+Angular

  4. Aplicamos as regras pressionando o botão Aplicar Alterações:

    CI/CD no Github Actions para um projeto em Flask+Angular

Configuração de CI/CD no Github Actions

Vamos para a parte mais interessante - configurar o pipeline de integração contínua e entrega do nosso projeto para o servidor.

Este pipeline consistirá em duas partes:

  • compilação da imagem e execução de testes (para o backend) - do lado do Github;
  • execução das migrações (para o backend) e implantação dos containers - no servidor.

Implantação no Plesk

Vamos primeiro entender o segundo ponto (já que depende do primeiro).

O processo de implantação será configurado usando a extensão Git para Plesk.

Vamos considerar um exemplo com o ambiente de Produção para o repositório Backend.

  1. Acesse a assinatura do nosso site Helloworld e vá para a seção Git:

    CI/CD no Github Actions para um projeto em Flask+Angular

  2. Cole no campo "Repositório Git remoto" o link para nosso repositório no Github e altere a pasta padrão httpdocs para outra (por exemplo, /httpdocs/hw_back):

    CI/CD no Github Actions para um projeto em Flask+Angular

  3. Copie a chave pública SSH da etapa anterior e adicionamos ela nas configurações do Github.
  4. Clique em OK na tela na etapa 2, após a qual seremos redirecionados para a página do repositório no Plesk. Agora precisamos configurar a atualização do repositório ao realizar commits na branch master. Para isso, vamos para Configurações do Repositório e salvamos o valor Webhook URL (ele será necessário mais tarde na configuração do Github Actions):

    CI/CD no Github Actions para um projeto em Flask+Angular

  5. No campo Ações na tela da etapa anterior, inserimos o script para acionar a implantação:
    cd {REPOSITORY_ABSOLUTE_PATH}
    .ci-cd/deploy.sh {ENV} {DOCKER_REGISTRY_HOST} {DOCKER_USER} {DOCKER_PASSWORD} {TG_BOT_TOKEN} {TG_CHAT_ID} 

    onde:

    {REPOSITORY_ABSOLUTE_PATH} — caminho para a pasta do repositório backend em prod no servidor;
    {ENV} — ambiente (dev/prod), no nosso caso prod;
    {DOCKER_REGISTRY_HOST} — host do nosso repositório Docker
    {TG_BOT_TOKEN} — token do bot do Telegram;
    {TG_CHAT_ID} — ID do chat/canal para enviar notificações.

    Exemplo de script:

    cd /var/www/vhosts/helloworld.ru/httpdocs/hw_back/
    .ci-cd/deploy.sh dev docker.helloworld.ru docker_user docker_password 12345678:AAbcdEfghCH1vGbCasdfSAs0K5PALDsaw -1001234567890
  6. Adicionamos o usuário da nossa assinatura ao grupo Docker (para que ele possa gerenciar os contêineres):
    sudo usermod -aG docker helloworld_admin

O ambiente de desenvolvimento para o repositório backend e frontend é configurado da mesma forma.

Pipeline de deployment no Github Actions

Vamos configurar a primeira parte do nosso pipeline CI/CD no Github Actions.

Backend

O pipeline é descrito no arquivo deploy.yml.

Mas antes de analisá-lo, vamos preencher as variáveis secretas necessárias no Github. Para isso, acesse Configurações -> Segredos:

  • DOCKER_REGISTRY — o host do nosso repositório Docker (docker.helloworld.ru);
  • DOCKER_LOGIN — login para o repositório Docker;
  • DOCKER_PASSWORD — senha correspondente;
  • DEPLOY_HOST — o host onde a interface do Plesk está disponível (exemplo: helloworld.ru:8443 ou 123.4.56.78:8443);
  • DEPLOY_BACK_PROD_TOKEN — token para deployment no repositório de produção no servidor (obtivemos isso em Deployment no Plesk item 4);
  • DEPLOY_BACK_DEV_TOKEN — token para deployment no repositório de desenvolvimento no servidor.

O processo de deployment é simples e consiste em três etapas principais:

  • criação e publicação da imagem em nosso repositório;
  • execução de testes no contêiner com base na imagem recém-criada;
  • deployment no ambiente correto dependendo do ramo (dev/master).

Frontend

O arquivo deploy.yml para o repositório frontend não difere muito do do backend. Ele não contém a etapa de execução de testes e os nomes dos tokens para deployment mudam. Os segredos para o repositório frontend, aliás, precisam ser preenchidos separadamente.

Configuração do site

Proxy de tráfego através do Nginx

Bem, chegamos ao final. Agora só falta configurar o proxy do tráfego de entrada e saída em nosso contêiner através do Nginx. Esse processo já foi abordado na seção 5 da configuração do Docker Registry. O mesmo deve ser repetido para as partes backend e frontend nos ambientes dev e prod.

Vou apresentar capturas de tela das configurações.

Backend

CI/CD no Github Actions para um projeto em Flask+Angular

Frontend

CI/CD no Github Actions para um projeto em Flask+Angular
Uma observação importante. No contêiner frontend, todos os URLs serão proxyados, exceto aqueles que começam com /api/ — eles serão proxyados para o contêiner backend (por isso no contêiner backend, todos os manipuladores devem começar com /api/).

Resultados

Agora nosso site deve estar acessível pelos endereços helloworld.ru e dev.helloworld.ru (os ambientes prod e dev, respectivamente).

Em resumo, aprendemos como preparar um aplicativo simples em Flask e Angular e configurar um pipeline no Github Actions para implantá-lo em um servidor gerenciado pelo Plesk.

Reitero os links para os repositórios com o código: backend, frontend.

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