CI/CD en Github Actions para un proyecto Flask+Angular

CI/CD en Github Actions para un proyecto Flask+Angular
En este artículo, compartiré mi experiencia con la configuración de CI/CD mediante el Panel de control de Plesk y las acciones de Github. Hoy aprenderemos cómo implementar un proyecto simple con el nombre sencillo "Helloworld". Está escrito en el marco Flask Python, con trabajadores de Celery y una interfaz Angular 8.

Enlaces a repositorios: back-end, Interfaz.

En la primera parte del artículo, veremos nuestro proyecto y sus partes. En el segundo, descubriremos cómo configurar Plesk e instalar las extensiones y componentes necesarios (DB, RabbitMQ, Redis, Docker, etc.).

En la tercera parte, finalmente descubriremos cómo configurar una canalización para implementar nuestro proyecto en un servidor en un entorno de desarrollo y producción. Y luego lanzaremos el sitio en el servidor.

Y sí, me olvidé de presentarme. Mi nombre es Oleg Borzov, soy un desarrollador fullstack en el equipo de CRM para administradores de hipotecas en Domclick.

Descripción general del proyecto

Primero, veamos dos repositorios de proyectos, backend y front, y repasemos el código.

Backend: Frasco + Apio

Para la parte trasera, tomé un grupo que es bastante popular entre los desarrolladores de Python: el marco Flask (para la API) y Celery (para la cola de tareas). SQLAchemy se utiliza como ORM. El alambique se utiliza para las migraciones. Para validación JSON en identificadores - Marshmallow.

В repositorios hay un archivo Readme.md con una descripción detallada de la estructura e instrucciones para ejecutar el proyecto.

API de elementos web bastante simple, consta de 6 bolígrafos:

  • /ping - para comprobar la disponibilidad;
  • manejadores para registro, autorización, desautorización y obtención de un usuario autorizado;
  • un identificador de correo electrónico que pone una tarea en la cola de Celery.

parte de apio aún más fácil, solo hay un problema send_mail_task.

En carpeta / conf hay dos subcarpetas:

  • docker con dos Dockerfiles (base.dockerfile para construir una imagen base que rara vez cambia y Dockerfile para conjuntos principales);
  • .env_files - con archivos con variables de entorno para diferentes entornos.

Hay cuatro archivos docker-compose en la raíz del proyecto:

  • docker-compose.local.db.yml levantar una base de datos local para el desarrollo;
  • docker-compose.local.workers.yml para levantamiento local del trabajador, base de datos, Redis y RabbitMQ;
  • docker-compose.test.yml para ejecutar pruebas durante la implementación;
  • docker-compose.yml para el despliegue.

Y la última carpeta que nos interesa - .ci-cd. Contiene scripts de shell para la implementación:

  • deploy.sh — lanzamiento de la migración y el despliegue. Se ejecuta en el servidor después de compilar y ejecutar pruebas en Github Actions;
  • rollback.sh - reversión de contenedores a la versión anterior del ensamblaje;
  • curl_tg.sh - envío de notificaciones de implementación a Telegram.

Interfaz en Angular

Depósito con frente mucho más simple que el de Beck. El frente consta de tres páginas:

  • Página principal con un formulario para enviar correo electrónico y un botón de salida.
  • Página de inicio de sesión.
  • Página de registro.

La página principal parece ascética:

CI/CD en Github Actions para un proyecto Flask+Angular
Hay dos archivos en la raíz. Dockerfile и docker-compose.yml, así como la carpeta familiar .ci-cd con un poco menos de scripts que en el repositorio anterior (secuencias de comandos eliminadas para ejecutar pruebas).

Inicio de un proyecto en Plesk

Comencemos configurando Plesk y creando una suscripción para nuestro sitio.

Instalación de extensiones

En Plesk, necesitamos cuatro extensiones:

  • Docker para administrar y mostrar visualmente el estado de los contenedores en el panel de administración de Plesk;
  • Git para configurar el paso de implementación en el servidor;
  • Let's Encrypt para generar (y renovar automáticamente) certificados TLS gratuitos;
  • Firewall para configurar el filtrado del tráfico entrante.

Puede instalarlos a través del panel de administración de Plesk en la sección Extensiones:

CI/CD en Github Actions para un proyecto Flask+Angular
No consideraremos la configuración detallada para las extensiones, la configuración predeterminada servirá para nuestros propósitos de demostración.

Crear una suscripción y un sitio

A continuación, debemos crear una suscripción para nuestro sitio web helloworld.ru y agregar allí el subdominio dev.helloworld.ru.

  1. Cree una suscripción para el dominio helloworld.ru y especifique la contraseña de inicio de sesión para el usuario del sistema:

    CI/CD en Github Actions para un proyecto Flask+Angular
    Marque la casilla en la parte inferior de la página Asegure el dominio con Let's Encryptsi queremos configurar HTTPS para el sitio:

    CI/CD en Github Actions para un proyecto Flask+Angular

  2. Luego, en esta suscripción, cree un subdominio dev.helloworld.ru (para el cual también puede emitir un certificado TLS gratuito):

    CI/CD en Github Actions para un proyecto Flask+Angular

Instalación de componentes del servidor

Tenemos un servidor con Sistema operativo Debian Stretch 9.12 y panel de control instalado Plesk Obsidiana 18.0.27.

Necesitamos instalar y configurar para nuestro proyecto:

  • PostgreSQL (en nuestro caso, habrá un servidor con dos bases de datos para entornos de desarrollo y producción).
  • RabbitMQ (misma, misma instancia con diferentes vhosts para entornos).
  • Dos instancias de Redis (para entornos de desarrollo y producción).
  • Registro de Docker (para el almacenamiento local de imágenes de Docker integradas).
  • Interfaz de usuario para el registro de Docker.

PostgreSQL

Plesk ya viene con PostgreSQL DBMS, pero no la última versión (al momento de escribir Plesk Obsidian apoyado Postgres versiones 8.4–10.8). Queremos la última versión de nuestra aplicación (12.3 en el momento de escribir este artículo), por lo que la instalaremos manualmente.

Hay muchas instrucciones detalladas para instalar Postgres en Debian en la red (ejemplo), por lo que no los describiré en detalle, solo daré los 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

Teniendo en cuenta que PostgreSQL tiene una configuración predeterminada bastante mediocre, es necesario corregir la configuración. esto nos ayudara calculadora: debe ingresar los parámetros de su servidor y reemplazar la configuración en el archivo /etc/postgresql/12/main/postgresql.confa los ofrecidos. Cabe señalar aquí que tales calculadoras no son una solución mágica, y la base debe ajustarse con mayor precisión, en función de su hardware, aplicación y complejidad de consulta. Pero esto es suficiente para empezar.

Además de los ajustes propuestos por la calculadora, también cambiamos en postgresql.confel puerto predeterminado 5432 a otro (en nuestro ejemplo, 53983).

Después de cambiar el archivo de configuración, reinicie postgresql-server con el comando:

service postgresql restart

Hemos instalado y configurado PostgreSQL. Ahora vamos a crear una base de datos, usuarios para entornos de desarrollo y producción, y dar a los usuarios derechos para administrar la base de datos:

$ 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

Pasemos a instalar RabbitMQ, un intermediario de mensajes para Celery. Instalarlo en Debian es bastante simple:

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

Después de la instalación, necesitamos crear vhosts, usuarios y conceder los derechos necesarios:

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

Ahora instalemos y configuremos el último componente de nuestra aplicación: Redis. Se utilizará como backend para almacenar los resultados de las tareas de Celery.

Levantaremos dos contenedores Docker con Redis para entornos de desarrollo y producción usando la extensión Docker para Plesk.

  1. Vamos a Plesk, vamos a la sección de Extensiones, buscamos la extensión de Docker y la instalamos (necesitamos una versión gratuita):

    CI/CD en Github Actions para un proyecto Flask+Angular

  2. Vaya a la extensión instalada, busque la imagen a través de la búsqueda redis bitnami e instalar la última versión:

    CI/CD en Github Actions para un proyecto Flask+Angular

  3. Entramos en el contenedor descargado y ajustamos la configuración: especificamos el puerto, el tamaño máximo de RAM asignado, la contraseña en las variables de entorno y montamos el volumen:

    CI/CD en Github Actions para un proyecto Flask+Angular

  4. Realizamos los pasos 2-3 para el contenedor prod, en la configuración solo cambiamos los parámetros: puerto, contraseña, tamaño de RAM y ruta a la carpeta de volumen en el servidor:

    CI/CD en Github Actions para un proyecto Flask+Angular

Registro de Docker

Además de los servicios básicos, sería bueno poner su propio repositorio de imágenes de Docker en el servidor. Afortunadamente, el espacio del servidor ahora es bastante barato (ciertamente más barato que una suscripción a DockerHub), y el proceso de configuración de un repositorio privado es muy simple.

Queremos tener:

Para hacer esto:

  1. Creemos dos subdominios en Plesk en nuestra suscripción: docker.helloworld.ru y docker-ui.helloworld.ru, y configuremos los certificados Let's Encrypt para ellos.
  2. Agregue el archivo a la carpeta del subdominio docker.helloworld.ru docker-compose.yml con contenido como este:
    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. En SSH, generaremos el archivo .htpasswd para la autorización básica en el repositorio de Docker:
    htpasswd -bBc .htpasswd hw_docker_admin hw_docker_password
  4. Recoger y levantar contenedores:
    docker-compose up -d
  5. Y necesitamos redirigir Nginx a nuestros contenedores. Esto se puede hacer a través de Plesk.

Se deben realizar los siguientes pasos para los subdominios docker.helloworld.ru y docker-ui.helloworld.ru:

En la sección Herramientas de desarrollo nuestro sitio ir a Reglas de proxy de Docker:

CI/CD en Github Actions para un proyecto Flask+Angular
Y agregue una regla para enviar tráfico entrante a nuestro contenedor:

CI/CD en Github Actions para un proyecto Flask+Angular

  1. Comprobamos que podemos iniciar sesión en nuestro contenedor desde la 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. Comprobemos también el funcionamiento del subdominio docker-ui.helloworld.ru:

    CI/CD en Github Actions para un proyecto Flask+Angular
    Cuando haga clic en Examinar repositorios, el navegador mostrará una ventana de autorización donde deberá ingresar el nombre de usuario y la contraseña para el repositorio. Después de eso, seremos transferidos a una página con una lista de repositorios (por ahora, estará vacía para usted):

    CI/CD en Github Actions para un proyecto Flask+Angular

Abrir puertos en el cortafuegos de Plesk

Después de instalar y configurar los componentes, debemos abrir puertos para que los componentes sean accesibles desde los contenedores Docker y la red externa.

Veamos cómo hacer esto usando la extensión Firewall para Plesk que instalamos anteriormente.

  1. Pasamos a Herramientas y configuración > Configuración > Cortafuegos:
    CI/CD en Github Actions para un proyecto Flask+Angular
  2. Pasamos a Modificar las reglas del cortafuegos de Plesk > Agregar regla personalizada y abra los siguientes puertos TCP para la subred de Docker (172.0.0.0 / 8):
    ConejoMQ: 1883, 4369, 5671-5672, 25672, 61613-61614
    Redis: 32785, 32786

    CI/CD en Github Actions para un proyecto Flask+Angular

  3. También agregaremos una regla que abrirá los puertos de PostgreSQL y los paneles de administración de RabbitMQ al mundo exterior:

    CI/CD en Github Actions para un proyecto Flask+Angular

  4. Aplique las reglas utilizando el botón Aplicar cambios:

    CI/CD en Github Actions para un proyecto Flask+Angular

Configuración de CI/CD en Github Actions

Pasemos a la parte más interesante: configurar una tubería de integración continua y entregar nuestro proyecto al servidor.

Este canal constará de dos partes:

  • construyendo una imagen y ejecutando pruebas (para el backend) - en el lado de Github;
  • ejecutando migraciones (para el backend) e implementando contenedores, en el servidor.

Implementar en Plesk

Tratemos primero el segundo punto (porque el primero depende de él).

Configuraremos el proceso de implementación utilizando la extensión Git para Plesk.

Considere un ejemplo con un entorno Prod para un repositorio Backend.

  1. Vamos a la suscripción de nuestro sitio web Helloworld y vamos a la subsección Git:

    CI/CD en Github Actions para un proyecto Flask+Angular

  2. Inserte un enlace a nuestro repositorio de Github en el campo "Repositorio remoto de Git" y cambie la carpeta predeterminada httpdocs a otro (ej. /httpdocs/hw_back):

    CI/CD en Github Actions para un proyecto Flask+Angular

  3. Copie la clave pública SSH del paso anterior y añadir está en la configuración de Github.
  4. Haga clic en Aceptar en la pantalla del paso 2, después de lo cual se nos redirigirá a la página del repositorio en Plesk. Ahora necesitamos configurar el repositorio para que se actualice en las confirmaciones de la rama maestra. Para hacer esto, vaya a Configuración del repositorio y guardar el valor Webhook URL (lo necesitaremos más adelante cuando configuremos Github Actions):

    CI/CD en Github Actions para un proyecto Flask+Angular

  5. En el campo Acciones en la pantalla del párrafo anterior, ingrese el script para iniciar la implementación:
    cd {REPOSITORY_ABSOLUTE_PATH}
    .ci-cd/deploy.sh {ENV} {DOCKER_REGISTRY_HOST} {DOCKER_USER} {DOCKER_PASSWORD} {TG_BOT_TOKEN} {TG_CHAT_ID} 

    donde:

    {REPOSITORY_ABSOLUTE_PATH} - ruta a la carpeta prod del repositorio backend en el servidor;
    {ENV} - entorno (dev/prod), en nuestro caso prod;
    {DOCKER_REGISTRY_HOST} - el host de nuestro repositorio docker
    {TG_BOT_TOKEN} — Token de bot de Telegram;
    {TG_CHAT_ID} — ID del chat/canal para enviar notificaciones.

    Ejemplo de guión:

    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. Agregue un usuario de nuestra suscripción al grupo Docker (para que pueda administrar contenedores):
    sudo usermod -aG docker helloworld_admin

El entorno de desarrollo para el repositorio de backend y el frontend se configuran de la misma manera.

Pipeline de implementación en Github Actions

Pasemos a configurar la primera parte de nuestra canalización de CI/CD en Github Actions.

Backend

El oleoducto se describe en archivo deployment.yml.

Pero antes de analizarlo, completemos las variables secretas que necesitamos en Github. Para hacer esto, vaya a Configuración -> Secretos:

  • DOCKER_REGISTRY - el host de nuestro repositorio Docker (docker.helloworld.ru);
  • DOCKER_LOGIN - iniciar sesión en el repositorio de Docker;
  • DOCKER_PASSWORD - contraseña para ello;
  • DEPLOY_HOST — host donde está disponible el panel de administración de Plesk (ejemplo: holamundo.ru: 8443 o 123.4.56.78:8443);
  • DEPLOY_BACK_PROD_TOKEN - un token para la implementación en el repositorio prod del servidor (lo obtuvimos en Implementación en Plesk p. 4);
  • DEPLOY_BACK_DEV_TOKEN - token para la implementación en el repositorio dev en el servidor.

El proceso de implementación es simple y consta de tres pasos principales:

  • construyendo y publicando la imagen en nuestro repositorio;
  • ejecutar pruebas en un contenedor basado en una imagen recién creada;
  • implementación en el entorno deseado dependiendo de la rama (dev/master).

Frontend

El archivo deployment.yml para el repositorio frontal poco diferente de la de Beck. Carece de un paso con la ejecución de pruebas y cambia los nombres de los tokens para la implementación. Los secretos para el repositorio frontal, por cierto, deben completarse por separado.

Configuración del sitio

Tráfico proxy a través de Nginx

Bueno, hemos llegado al final. Solo queda configurar el proxy del tráfico entrante y saliente a nuestro contenedor a través de Nginx. Ya hemos cubierto este proceso en el paso 5 de la configuración del Registro de Docker. Lo mismo debe repetirse para las partes trasera y delantera en entornos de desarrollo y producción.

Proporcionaré capturas de pantalla de la configuración.

Backend

CI/CD en Github Actions para un proyecto Flask+Angular

Frontend

CI/CD en Github Actions para un proyecto Flask+Angular
Aclaraciones importantes. Todas las URL se enviarán por proxy al contenedor frontend, excepto aquellas que comiencen con /api/ - serán enviados por proxy al contenedor trasero (por lo que en el contenedor trasero, todos los manipuladores deben comenzar con /api/).

resultados

Ahora nuestro sitio debería estar disponible en helloworld.ru y dev.helloworld.ru (prod- y dev-environments, respectivamente).

En total, aprendimos cómo preparar una aplicación simple en Flask y Angular y configurar una canalización en Github Actions para implementarla en un servidor que ejecuta Plesk.

Voy a duplicar los enlaces a los repositorios con el código: back-end, Interfaz.

Fuente: habr.com

Añadir un comentario