Información general sobre el despliegue de cargas de trabajo de máquinas virtuales

En esta guía se explica el contexto conceptual necesario para desplegar una carga de trabajo basada en máquinas virtuales en un clúster aislado de Google Distributed Cloud (GDC) en Bare Metal mediante un tiempo de ejecución de máquina virtual. La carga de trabajo de esta guía es una plataforma de sistema de venta de entradas de ejemplo que está disponible en hardware local.

Arquitectura

Jerarquía de recursos

En GDC, implementas los componentes que forman el sistema de asistencia en una organización de arrendatario dedicada al equipo de Operaciones, que es idéntica a cualquier organización de cliente. Una organización es un conjunto de clústeres, recursos de infraestructura y cargas de trabajo de aplicaciones que se administran conjuntamente. Cada organización de una instancia de GDC usa un conjunto de servidores específico, lo que proporciona un aislamiento sólido entre los inquilinos. Para obtener más información sobre la infraestructura, consulta Diseñar límites de acceso.

Jerarquía de recursos de GDC con air gap

Además, puedes implementar y gestionar los recursos del sistema de asistencia en un proyecto, lo que proporciona aislamiento lógico dentro de una organización mediante políticas de software y su aplicación. Los recursos de un proyecto están diseñados para acoplar componentes que deben permanecer juntos durante su ciclo de vida.

El sistema de asistencia sigue una arquitectura de tres niveles que se basa en un balanceador de carga para dirigir el tráfico entre los servidores de aplicaciones que se conectan a un servidor de base de datos que almacena datos persistentes.

Diagrama de una arquitectura de tres niveles

Esta arquitectura permite la escalabilidad y el mantenimiento, ya que cada nivel se puede desarrollar y mantener de forma independiente. También proporciona una separación clara de las responsabilidades, lo que simplifica la depuración y la solución de problemas. Al encapsular estos niveles en un proyecto de GDC, puedes implementar y gestionar componentes de forma conjunta, como los servidores de aplicaciones y de bases de datos.

Redes

Para ejecutar el sistema de asistencia en un entorno de producción, es necesario implementar dos o más servidores de aplicaciones para conseguir una alta disponibilidad en caso de que falle un nodo. Combinada con un balanceador de carga, esta topología también permite distribuir la carga entre varias máquinas para escalar horizontalmente la aplicación. La plataforma nativa de Kubernetes de GDC utiliza Cloud Service Mesh para enrutar de forma segura el tráfico a los servidores de aplicaciones que componen el sistema de venta de entradas.

Cloud Service Mesh es una implementación de Google basada en el proyecto de código abierto que gestiona, observa y protege los servicios. Para alojar el sistema de venta de entradas en GDC, se utilizan las siguientes funciones de Cloud Service Mesh:

  • Equilibrio de carga: Cloud Service Mesh separa el flujo del tráfico del escalado de la infraestructura, lo que abre las puertas a muchas funciones de gestión del tráfico, como el enrutamiento dinámico de solicitudes. El sistema de asistencia requiere conexiones de cliente persistentes, por lo que habilitamos las sesiones fijas mediante DestinationRules para configurar el comportamiento del enrutamiento del tráfico.
  • Terminación de TLS: Cloud Service Mesh expone las pasarelas de entrada mediante certificados TLS y proporciona autenticación de transporte en el clúster a través de mTLS (Seguridad en la capa de transporte mutua) sin tener que cambiar el código de la aplicación.

  • Recuperación tras fallos: Cloud Service Mesh incluye varias funciones de recuperación tras fallos críticos, como tiempos de espera, disyuntores, comprobaciones activas del estado y reintentos vinculados.

En el clúster de Kubernetes, usamos objetos Service estándar como una forma abstracta de exponer los servidores de aplicaciones y bases de datos a la red. Los servicios proporcionan una forma cómoda de orientar las instancias mediante un selector y ofrecen resolución de nombres en el clúster mediante un servidor DNS compatible con el clúster.

apiVersion: v1
kind: Service
metadata:
  name: http-ingress
spec:
  selector:
    app.kubernetes.io/component: application-server
  ports:
  - name: http
    port: 80
---
apiVersion: v1
kind: Service
metadata:
  name: database-ingress
spec:
  selector:
    app.kubernetes.io/component: database-server
  ports:
  - name: mysql
    port: 3306

Computación

El sistema de asistencia recomienda usar máquinas físicas o virtuales para alojar las instalaciones locales, y nosotros utilizamos la gestión de máquinas virtuales de GDC para desplegar tanto los servidores de aplicaciones como los de bases de datos como cargas de trabajo de máquinas virtuales. Definir recursos de Kubernetes nos permitió especificar tanto el VirtualMachine como el VirtualMachineDisk para adaptar los recursos a nuestras necesidades de los diferentes tipos de servidores. VirtualMachineExternalAccess nos permite configurar la transferencia de datos hacia y desde la VM.

apiVersion: virtualmachine.gdc.goog/v1
kind: VirtualMachineDisk
metadata:
  name: vm1-boot-disk
spec:
  size: 100G
  source:
    image:
      name: ts-ticketing-system-app-server-2023-08-18-203258
      namespace: vm-system
---
apiVersion: virtualmachine.gdc.goog/v1
kind: VirtualMachine
metadata:
  labels:
    app.kubernetes.io/component: application-server
  name: vm1
  namespace: support
spec:
  compute:
    vcpus: 8
    memory: 12G
  disks:
  - boot: true
    virtualMachineDiskRef:
      name: vm1-boot-disk

---
apiVersion: virtualmachine.gdc.goog/v1
kind: VirtualMachineExternalAccess
metadata:
  name: vm1
  namespace: support
spec:
  enabled: true
  ports:
   - name: ssh
     protocol: TCP
     port: 22

En cuanto a la imagen del SO invitado, hemos creado una imagen personalizada para cumplir nuestros requisitos de cumplimiento y seguridad. Es posible conectarse a instancias de VM en ejecución a través de SSH mediante VirtualMachineAccessRequest, lo que nos permite limitar la capacidad de conectarse a VMs a través del control de acceso basado en roles (RBAC) de Kubernetes y evitar la necesidad de crear cuentas de usuario locales en las imágenes personalizadas. La solicitud de acceso también define un tiempo de vida (TTL) que permite que las solicitudes de acceso basadas en el tiempo gestionen las máquinas virtuales que caducan automáticamente.

Automatización

Como resultado clave de este proyecto, hemos diseñado un método para instalar instancias del sistema de asistencia de forma repetible que pueda admitir una automatización exhaustiva y reducir las diferencias de configuración entre los despliegues.

Proceso de lanzamiento

Para personalizar las imágenes del servidor de aplicaciones y del servidor de bases de datos, se parte de una imagen del sistema operativo base y se modifica según sea necesario para instalar las dependencias necesarias para cada imagen del servidor. Hemos seleccionado una imagen del SO base por su amplia adopción en sistemas de venta de entradas en instalaciones locales. Esta imagen del SO base también proporciona las funciones de refuerzo de la seguridad necesarias para cumplir las guías técnicas de implementación de seguridad (STIGs) que se necesitan para ofrecer una imagen conforme que cumpla los controles de la NIST 800-53.

Nuestro flujo de integración continua (CI) usaba el siguiente flujo de trabajo para personalizar las imágenes de los servidores de aplicaciones y de bases de datos:

Flujo de trabajo de integración continua

Cuando los desarrolladores hacen cambios en las secuencias de comandos de personalización o en las dependencias de imágenes, activamos un flujo de trabajo automatizado en nuestras herramientas de integración continua para generar un nuevo conjunto de imágenes que se incluyen en los lanzamientos de GDC. Como parte de la creación de imágenes, también actualizamos las dependencias del SO (yum update) y esparcimos la imagen con compresión para reducir el tamaño de la imagen necesario para transferir imágenes a los entornos de los clientes.

Ciclo de vida del desarrollo de software

El ciclo de vida de desarrollo de software (SDLC) es un proceso que ayuda a las organizaciones a planificar, crear, probar y desplegar software. Si siguen un SDLC bien definido, las organizaciones se aseguran de que el software se desarrolle de forma coherente y repetible, y de identificar posibles problemas en las primeras fases. Además de crear imágenes en nuestro flujo de integración continua (CI), también definimos entornos para desarrollar y poner en marcha versiones preliminares del sistema de venta de entradas para realizar pruebas y asegurar la calidad.

Implementar una instancia independiente del sistema de asistencia por proyecto de GDC nos permitió probar los cambios de forma aislada, sin afectar a las instancias existentes en la misma instancia de GDC. Hemos usado la API ResourceManager para crear y eliminar proyectos de forma declarativa mediante recursos de Kubernetes.

apiVersion: resourcemanager.gdc.goog/v1
kind: Project
metadata:
  name: ticketing-system-dev
---
apiVersion: resourcemanager.gdc.goog/v1
kind: Project
metadata:
  name: ticketing-system-qa
---
apiVersion: resourcemanager.gdc.goog/v1
kind: Project
metadata:
  name: ticketing-system-staging

Si se combina con el empaquetado de gráficos y la gestión de infraestructuras, como las máquinas virtuales como código, los desarrolladores pueden iterar rápidamente, hacer cambios y probar nuevas funciones junto con las instancias de producción. La API declarativa también permite que los frameworks de ejecución de pruebas automatizadas realicen pruebas de regresión periódicas y verifiquen las funciones existentes.

Operatividad

La operatividad es la facilidad con la que se puede utilizar y mantener un sistema. Es un aspecto importante a tener en cuenta al diseñar cualquier aplicación de software. La monitorización eficaz contribuye a la operatividad porque permite identificar y abordar los problemas antes de que tengan un impacto significativo en el sistema. La monitorización también se puede usar para identificar oportunidades de mejora y establecer una base para los objetivos de nivel de servicio.

Supervisión

Hemos integrado el sistema de incidencias con la infraestructura de observabilidad de GDC, incluidos los registros y las métricas. En el caso de las métricas, exponemos endpoints HTTP de cada VM que permiten a la aplicación extraer puntos de datos producidos por los servidores de aplicaciones y de bases de datos. Estos endpoints incluyen métricas del sistema recogidas mediante el exportador de nodos de la aplicación y métricas específicas de la aplicación.

Con los endpoints expuestos en cada VM, configuramos el comportamiento de sondeo de la aplicación mediante el recurso personalizado MonitoringTarget para definir el intervalo de raspado y anotar las métricas.

apiVersion: monitoring.gdc.goog/v1
kind: MonitoringTarget
metadata:
  name: database-monitor
spec:
  podMetricsEndpoints:
    path:
      value: /metrics
    port:
      annotation: application.io/dbMetrics
    scrapeInterval: 60s

Para el registro, instalamos y configuramos un procesador de registros y métricas en cada VM para monitorizar los registros relevantes y enviar los datos de registro a la herramienta de registro, donde los datos se indexan y se consultan a través de la instancia de monitorización. Los registros de auditoría se reenvían a un endpoint especial configurado con un periodo de conservación ampliado para cumplir los requisitos. Las aplicaciones basadas en contenedores pueden usar los recursos personalizados LoggingTarget y AuditLoggingTarget para indicar a la canalización de registro que recoja registros de servicios específicos de tu proyecto.

A partir de los datos disponibles en los procesadores de registro y monitorización, creamos alertas mediante el recurso personalizado MonitoringRule, que nos permite gestionar esta configuración como código en nuestro paquete de gráficos. Usar una API declarativa para definir alertas y paneles de control también nos permite almacenar esta configuración en nuestro repositorio de código y seguir los mismos procesos de revisión de código e integración continua que usamos para cualquier otro cambio de código.

Modos de fallo

Las primeras pruebas revelaron varios modos de fallo relacionados con los recursos, lo que nos ayudó a priorizar las métricas y las alertas que debíamos añadir primero. Empezamos monitorizando el uso elevado de memoria y disco, ya que la configuración incorrecta de la base de datos provocó que las tablas de búfer consumieran toda la memoria disponible y que el registro excesivo llenara el disco de volumen persistente adjunto. Después de ajustar el tamaño del búfer de almacenamiento e implementar una estrategia de rotación de registros, introdujimos alertas que se activan si las VMs se acercan a un uso elevado de memoria o disco.

apiVersion: monitoring.gdc.goog/v1
kind: MonitoringRule
metadata:
  name: monitoring-rule
spec:
  interval: 60s
  limit: 0
  alertRules:
  - alert: vm1_disk_usage
    expr:
      (node_filesystem_size_bytes{container_name="compute"} -
      node_filesystem_avail_bytes{container_name="compute"}) * 100 /
      node_filesystem_size_bytes{container_name="compute"} > 90
    labels:
      severity: error
      code: <a href="/distributed-cloud/hosted/docs/latest/gdch/gdch-io/service-manual/ts/runbooks/ts-r0001">TS-R0001</a>
      resource: vm1
    annotations:
      message: "vm1 disk usage above 90% utilization"

Tras verificar la estabilidad del sistema, nos centramos en los modos de fallo de la aplicación en el sistema de asistencia. Como para depurar los problemas de la aplicación a menudo teníamos que usar Secure Shell (SSH) en cada VM del servidor de aplicaciones para consultar los registros del sistema de asistencia, configuramos una aplicación para que reenviara estos registros a la herramienta de registro. De esta forma, pudimos aprovechar la pila de observabilidad de GDC y consultar todos los registros operativos del sistema de asistencia en la instancia de monitorización.

El registro centralizado también nos permitió consultar los registros de varias VMs al mismo tiempo, lo que consolidó nuestra visión de cada componente del sistema.

Copias de seguridad

Las copias de seguridad son importantes para el funcionamiento de un sistema de software porque permiten restaurar el sistema en caso de fallo. GDC ofrece la creación de copias de seguridad y la restauración de VMs mediante recursos de Kubernetes. Si creamos un recurso personalizado VirtualMachineBackupRequest con un recurso personalizado VirtualMachineBackupPlanTemplate, podemos crear copias de seguridad del volumen persistente conectado a cada VM en el almacenamiento de objetos, donde las copias de seguridad se pueden conservar siguiendo una política de retención definida.

apiVersion: virtualmachine.gdc.goog/v1
kind: VirtualMachineBackupPlanTemplate
metadata:
  name: vm-backup-plan
spec:
  backupRepository: "backup-repository"
---
apiVersion: virtualmachine.gdc.goog/v1
kind: VirtualMachineBackupRequest
metadata:
  name: "db-vm-backup"
spec:
  virtualMachineBackupPlanTemplate: vm-backup-plan
  virtualMachine: db1
  virtualMachineBackupName: db-vm-backup

Del mismo modo, restaurar el estado de una VM a partir de una copia de seguridad implica crear un recurso personalizado VirtualMachineRestoreRequest para restaurar tanto los servidores de aplicaciones como los de bases de datos sin modificar el código ni la configuración de ninguno de los servicios.

apiVersion: virtualmachine.gdc.goog/v1
kind: VirtualMachineRestoreRequest
metadata:
  name: vm-restore-1
spec:
  virtualMachineBackup: db-vm-backup
  restoreName: restore1
  restoredResourceName: db1

Actualizaciones

Para dar soporte al ciclo de vida del software del sistema de asistencia y sus dependencias, hemos identificado tres tipos de actualizaciones de software, cada una de las cuales se gestiona de forma individual para minimizar el tiempo de inactividad y las interrupciones del servicio:

  1. Actualizaciones del SO.
  2. Actualizaciones de la plataforma, como parches y versiones principales.
  3. Actualizaciones de configuración.

En el caso de las actualizaciones del SO, creamos y lanzamos continuamente nuevas imágenes de VM para servidores de aplicaciones y de bases de datos, que se distribuyen con cada lanzamiento de GDC. Estas imágenes contienen correcciones para vulnerabilidades de seguridad y actualizaciones del sistema operativo subyacente.

Las actualizaciones de la plataforma del sistema de asistencia requieren que se apliquen actualizaciones a las imágenes de las máquinas virtuales, por lo que no podemos depender de una infraestructura inmutable para realizar las actualizaciones de parches y de versiones principales. En el caso de las actualizaciones de la plataforma, probamos y verificamos la versión del parche o de la versión principal en nuestros entornos de desarrollo y de preproducción antes de lanzar un paquete de actualización independiente junto con la versión de GDC.

Por último, las actualizaciones de configuración se aplican sin tiempo de inactividad a través de las APIs del sistema de asistencia para conjuntos de actualizaciones y otros datos de usuario. Desarrollamos y probamos las actualizaciones de configuración en nuestros entornos de desarrollo y de prueba antes de empaquetar varios conjuntos de actualizaciones durante el proceso de lanzamiento de GDC.

Integraciones

Proveedores de identidades

Para ofrecer a los clientes una experiencia fluida y permitir que las organizaciones incorporen a sus usuarios, integramos el sistema de asistencia con varios proveedores de identidades disponibles en GDC. Por lo general, los clientes de empresas y del sector público tienen sus propios proveedores de identidades bien gestionados para conceder y revocar derechos a sus empleados. Debido a los requisitos de cumplimiento y a la facilidad de la gestión de identidades y accesos, estos clientes quieren usar sus proveedores de identidades como fuente de información veraz para gestionar el acceso de sus empleados al sistema de asistencia.

El sistema de asistencia admite proveedores de SAML 2.0 y OIDC a través de su módulo de varios proveedores de identidades, que hemos habilitado previamente en nuestra imagen de VM del servidor de aplicaciones. Los clientes se autentican a través de su proveedor de identidad de la organización, que crea automáticamente usuarios y asigna roles en el sistema de asistencia.

El acceso saliente a los servidores del proveedor de identidades se permite a través del recurso personalizado ProjectNetworkPolicy, que limita si se puede acceder a los servicios externos desde una organización de GDC. Estas políticas nos permiten controlar de forma declarativa a qué endpoints puede acceder el sistema de asistencia en la red.

Ingestión de alertas

Además de permitir que los usuarios inicien sesión para crear manualmente casos de asistencia, también creamos incidencias en el sistema de asistencia en respuesta a las alertas del sistema.

Para lograr esta integración, personalizamos un webhook de Kubernetes de código abierto para recibir alertas de la aplicación y gestionar el ciclo de vida de los incidentes mediante el endpoint de la API del sistema de asistencia técnica expuesto a través de Cloud Service Mesh.

Las claves de API se almacenan en el almacén de secretos de GDC, que se basa en secretos de Kubernetes controlados mediante el control de acceso basado en roles (RBAC). Otras configuraciones, como los endpoints de la API y los campos de personalización de incidentes, se gestionan mediante el almacenamiento de valores clave de ConfigMap de Kubernetes.

Correo electrónico

El sistema de gestión de incidencias ofrece integraciones con servidores de correo para que los clientes puedan recibir asistencia por correo electrónico. Los flujos de trabajo automatizados convierten los correos de los clientes en casos de asistencia y envían respuestas automáticas a los clientes con enlaces a los casos, lo que permite que nuestro equipo de Asistencia gestione mejor su bandeja de entrada, haga un seguimiento sistemático de las solicitudes por correo y las resuelva, y proporcione un mejor servicio de atención al cliente.

apiVersion: networking.gdc.goog/v1
kind: ProjectNetworkPolicy
metadata:
  name: allow-ingress-traffic-from-ticketing-system
spec:
  subject:
    subjectType: UserWorkload
  ingress:
  - from:
    - projects:
        matchNames:
        - ticketing-system

Al exponer el correo electrónico como un servicio de Kubernetes, también se proporciona el descubrimiento de servicios y la resolución de nombres de dominio, y se desacopla aún más el backend del servidor de correo de los clientes, como el sistema de asistencia.

Cumplimiento

Registros de auditoría

Los registros de auditoría contribuyen a la postura de cumplimiento, ya que proporcionan una forma de monitorizar el uso del software y de hacer un seguimiento del mismo, así como de registrar la actividad del sistema. Los registros de auditoría registran los intentos de acceso de usuarios no autorizados, monitorizan el uso de las APIs e identifican posibles riesgos de seguridad. Los registros de auditoría cumplen los requisitos de cumplimiento normativo, como los que imponen la ley de transferencia y responsabilidad de los seguros médicos de EE. UU. (HIPAA), el estándar de seguridad de datos del sector de las tarjetas de pago (PCI DSS) y la ley Sarbanes-Oxley (SOX).

GDC proporciona un sistema para registrar las actividades y los accesos administrativos en la plataforma, así como para conservar estos registros durante un periodo configurable. Al desplegar el recurso personalizado AuditLoggingTarget, se configura la canalización de registro para recoger los registros de auditoría de nuestra aplicación.

En el sistema de asistencia, hemos configurado destinos de registro de auditoría tanto para los eventos de auditoría del sistema recogidos como para los eventos específicos de la aplicación generados por el registro de auditoría de seguridad del sistema de asistencia. Ambos tipos de registros se envían a una instancia de Loki centralizada en la que podemos escribir consultas y ver paneles de control en la instancia de monitorización.

Control de acceso

El control de acceso es el proceso de conceder o denegar el acceso a los recursos en función de la identidad del usuario o del proceso que solicita el acceso. De esta forma, se protegen los datos frente a accesos no autorizados y se asegura que solo los usuarios autorizados puedan hacer cambios en el sistema. En GDC, usamos el control de acceso basado en roles (RBAC) de Kubernetes para declarar políticas y aplicar la autorización a los recursos del sistema, que consisten en la aplicación del sistema de asistencia.

Definir un ProjectRole en GDC nos permite conceder acceso detallado a los recursos de Kubernetes mediante un rol de autorización predefinido.

apiVersion: resourcemanager.gdc.goog/v1
kind: ProjectRole
metadata:
  name: ticketing-system-admin
  labels:
    resourcemanager.gdc.goog/rbac-selector: system
spec:
  rules:
  - apiGroups:
    - ""
    resources:
    - configmaps
    - events
    - pods/log
    - services
    verbs:
    - get
    - list

Recuperación tras fallos

Replicación de bases de datos

Para cumplir los requisitos de recuperación ante desastres, implementamos el sistema de incidencias en una configuración principal-secundaria en varias instancias de GDC. En este modo, las solicitudes al sistema de incidencias se dirigen normalmente al sitio principal, mientras que el sitio secundario replica continuamente el registro binario de la base de datos. En caso de que se produzca una conmutación por error, el sitio secundario se convierte en el nuevo sitio principal y las solicitudes se dirigen a este.

Aprovechamos las funciones de replicación de bases de datos para configurar los servidores de bases de datos principal y de réplica por instancia de GDC en función de los parámetros definidos.

Para habilitar la replicación en una instancia que lleva más tiempo en ejecución que el periodo de conservación del registro binario, podemos restaurar la base de datos de réplica mediante una copia de seguridad de la base de datos para iniciar la replicación desde la base de datos principal.

En el modo principal, los servidores de aplicaciones y la base de datos funcionan igual que ahora, pero la base de datos principal está configurada para habilitar la replicación. Por ejemplo:

  1. Habilita el registro binario.

  2. Defina el ID de servidor.

  3. Crea una cuenta de usuario de replicación.

  4. Crear copia de seguridad

En el modo de réplica, los servidores de aplicaciones inhabilitarán el servicio web de emisión de tickets para evitar que se conecten directamente a la base de datos de réplica. La base de datos de réplica debe configurarse para iniciar la replicación desde la base de datos principal. Por ejemplo:

  1. Defina el ID de servidor.

  2. Configura las credenciales del usuario de replicación y los detalles de la conexión principal, como el host y el puerto.

  3. Restaurar desde la posición del registro binario de reanudación de la copia de seguridad.

La replicación de bases de datos requiere conectividad de red para que la réplica se conecte a la base de datos principal y empiece la replicación. Para exponer el endpoint de la base de datos principal para la replicación, usamos Cloud Service Mesh para crear una malla de servicios de entrada que admita la finalización de TLS en la malla de servicios, de forma similar a como gestionamos la transferencia de datos HTTPS en la aplicación web del sistema de venta de entradas.