f
Home

Published

- 13 min de lectura

Una infraestructura, un framework

img of Una infraestructura, un framework

Personal

Este es un post que me encanta. Los desarrolladores en Vercel tienen muy claro su cometido: andar en la vanguardia, cuando se pueda. La idea de una infraestructura que no se limite a su misma programación, sino al entorno que habilita la facilidad de uso de esta última (los frameworks en la infraestructura de un software), ha estado rondado desde hace un tiempo. Sin embargo, la aprobación de esta tecnología por parte de Vercel prueba el futuro prometedor que tiene el paradigma del software con las Infraestructuras Definidas por Frameworks (en inglés , Framework-defined infrastructure).

Post

Traducido de la entrada de Malte Ubl, CTO, en el blog de Vercel.

Infrastructure as code (IaC) es la práctica estándar de la industria para el aprovisionamiento de infraestructura de manera repetible y confiable. La Infraestructura Basada en Frameworks (FdI) es una evolución de IaC, donde el entorno de implementación aprovisiona automáticamente la infraestructura derivada del framework y las aplicaciones escritas en él.

La mejor manera de entenderlo es que un programa en tiempo de construcción analiza el código fuente escrito para un framework, comprende la intención detrás del código y luego genera automáticamente la configuración de IaC necesaria para ejecutar el software. Esto significa un DevOps más predecible, de menor costo y menor riesgo a través de una arquitectura verdaderamente sin servidor, podríamos decir, sin infraestructura.

En este artículo, explicaremos cómo se ajusta la Infraestructura Definida por el Framework a las visiones modernas de definición y automatización de infraestructura. Luego mostraremos ejemplos de cómo la Infraestructura Definida por el Framework mejora la experiencia de desarrollo en frameworks de código abierto.

Contextualizando la Infrastructure as Code (IaC)

En los primeros días de los servidores e Internet, nos conectábamos por SSH (o algo peor) a máquinas individuales, ejecutábamos scripts de instalación o incluso configurábamos software de producción utilizando interfaces gráficas de usuario para aprovisionar infraestructura. A medida que la web crecía, rápidamente quedó claro que este enfoque no escalaría con ella, y junto con el movimiento DevOps, IaC se convirtió en la mejor práctica para aprovisionar infraestructura de manera repetible y confiable.

El código en IaC representa una descripción versionada del estado deseado de la infraestructura, que, al ejecutarse, creará el estado del sistema descrito. En este escenario, la infraestructura puede referirse a:

  • Equipos y configuraciones de red
  • Servidores web y de aplicaciones
  • Bases de datos y colas de mensajes

¿Qué es la Infraestructura Definida por el Framework?

La Infraestructura Definida por el Framework abstrae sobre los primitivos de la nube como servidores, colas de mensajes y funciones sin servidor, convirtiéndolos en simples detalles de implementación de los conceptos del Framework:

  • Proporcionar portabilidad entre diferentes proveedores de infraestructura objetivo
  • Eliminar la necesidad de configurar manualmente la infraestructura para ejecutar una aplicación en producción
  • Aumentar el tiempo dedicado a escribir código de producto sobre la gestión del sistema
  • Permitir el uso inalterado de las herramientas de desarrollo local nativas del framework
  • Estandarizar en servicios seguros pre-revisados.

Los frameworks utilizan patrones bien establecidos para proporcionar estructura y abstracción a las aplicaciones, lo que las hace más fáciles de escribir y entender. Aunque la palabra framework es difícil de definir, el principio de Hollywood, “No nos llames, te llamamos”, probablemente capture mejor la inversión de control, donde el framework gestiona el flujo de la aplicación a nivel alto mientras que el desarrollador escribe código dentro de los ganchos proporcionados por él.

La Infraestructura Definida por el Framework aprovecha tanto esta inversión de control como la estructura predecible de las aplicaciones basadas en frameworks para mapear automáticamente los conceptos del framework en la infraestructura apropiada sin la necesidad de una declaración explícita o configuración de la infraestructura.

Tenga en cuenta que esta publicación está dando ejemplos basados en la oferta de Platform as a Service de Vercel. Sin embargo, el concepto puede aplicarse de manera más amplia, ya que la idea básica de comprender un framework y generar configuraciones de IaC para él también puede usarse para implementaciones de infraestructura más tradicionales.

Aplicando la Infraestructura Definida por el Framework

Ahora mostraremos ejemplos de cómo los frameworks mapean automáticamente sus conceptos en la infraestructura de Vercel. Aunque estaremos utilizando aquí el popular framework Next.js para la demostración, la implementación de la Infraestructura definida por el Framework de Vercel admite una multitud de otros frameworks basados en el mismo mecanismo subyacente.

Flowchart showing the process from user code to automatically inferred infrastructure.

Next.js utiliza un enrutador basado en archivos que asigna archivos en una estructura de directorios a URL en una aplicación web. Por ejemplo, el archivo pages/blog/index.ts crea una ruta de URL que mapea la URL /blog al código definido en ese archivo.

La Infraestructura Definida por el Framework comienza elevando esta comprensión de la tabla de rutas de una aplicación web desde un detalle de implementación del framework a algo que la infraestructura entiende. En el caso de Vercel, la tabla de rutas generada a partir de un framework eventualmente se implementaría en nuestro servicio de gateway, que luego sabe cómo invocar el primitivo de infraestructura correcto para cualquier ruta dada.

El contenido de pages/blog/index.tsx podría ser algo como esto:

   export default function BlogPosts({ posts }) {
	return posts.map((post) => <BlogPost key={post.id} post={post} />);
}

export async function getServerSideProps() {
	const posts = await getBlogPosts();
	return {
		props: { posts }
	};
}

Ejemplo de una página dinámicamente renderizada en Next.js.

En este ejemplo, el código del usuario define una función getServerSideProps que obtiene las entradas del blog en nuestro sitio. Next.js invoca esta función y pasa la salida a la exportación predeterminada de la función BlogPosts que renderiza una lista de entradas.

Las páginas de Next.js con una función getServerSideProps se renderizan dinámicamente en cada vista de página. Eso significa que una configuración de producción necesita un servicio de cómputo (como un servidor de aplicaciones o una función sin servidor) para realizar esta operación de obtención de datos y renderizado.

Con la Infraestructura Definida por el Framework, se utiliza el conocimiento de que las páginas con getServerSideProps requieren un recurso de cómputo para realizar la operación de renderizado para inferir automáticamente que se debe aprovisionar la infraestructura de cómputo para realizar la operación de renderizado. En el caso de Vercel, esto significa que se crea y despliega una función sin servidor basada en AWS Lambda con el código necesario para renderizar la página. El conocimiento para invocar esta función luego se despliega en el servicio de gateway como parte de la tabla de enrutamiento de la aplicación.

Ahora, vamos a modificar ligeramente el ejemplo de código anterior, para cambiar getServerSideProps por getStaticProps:

   export default function BlogPosts({ posts }) {
	return posts.map((post) => <BlogPost key={post.id} post={post} />);
}

export async function getStaticProps() {
	const posts = await getBlogPosts();
	return {
		props: { posts }
	};
}

El cambio de getServerSideProps a getStaticProps ahora genera el HTML en tiempo de compilación.

En Next.js, getStaticProps implica que en lugar de renderizar la página en cada vista, la función puede ser invocada en tiempo de compilación para generar una página HTML estática que luego puede ser servida al usuario. Una vez más, con la Infraestructura Definida por el Framework, se puede inferir que no se necesita más infraestructura de cómputo de producción para servir esta página web en particular. En cambio, los artefactos generados en tiempo de compilación pueden ser desplegados en una infraestructura de servidor web estática de menor costo. En el caso de Vercel, esto significa que no se despliega ninguna función sin servidor para esta página, y en su lugar, se actualiza la tabla de enrutamiento de la aplicación para apuntar al servicio de archivos estáticos respectivo.

Si bien este es solo un ejemplo de cómo los cambios en el código dentro de un archivo dado pueden desencadenar el despliegue de varias piezas de infraestructura, el concepto puede expandirse a una multitud de recursos de infraestructura. Por ejemplo:

  • Gatsby tiene un concepto llamado Generación Estática Diferida. Cuando se usa, se despliega una función sin servidor para realizar la generación diferida en la solicitud del usuario similar al renderizado en el lado del servidor. Sin embargo, la salida de la función luego se almacena en AWS S3 y se distribuye globalmente para ser servida desde el borde de Vercel sin otra invocación de función.
  • SvelteKit tiene el concepto de form actions. Cuando se usan, se crea automáticamente una función sin servidor para realizar la acción. Lo mismo sucede al usar Remix.
  • Next.js soporta el concepto de middleware, que desencadena la provisión automática de recursos de cómputo en el borde que ejecutan el código del middleware durante la fase de procesamiento de la solicitud.
  • El uso del componente para la optimización de imágenes desencadena automáticamente la configuración de un sistema de optimización de imágenes de alto rendimiento adaptando la imagen para el dispositivo del usuario que visita.

Internamente, los primitivos del framework se compilan en la API de salida de compilación de Vercel, que es una API de configuración de IaC más tradicional y declarativa que es consumida por la plataforma de Vercel para aprovisionar la infraestructura de producción.

Serverless en un mundo de IaC

IaC utiliza archivos legibles por máquina, que los desarrolladores pueden versionar de manera similar al software, para aprovisionar infraestructura como servidores físicos, máquinas virtuales y servicios de nivel superior como bases de datos o aplicaciones. La arquitectura sin servidor, que a pesar de su nombre aún utiliza servidores, elimina la necesidad de que los desarrolladores administren servidores físicos o virtuales específicos.

Los productos sin servidor todavía requieren que los desarrolladores definan y desplieguen sus primitivas sin servidor respectivas, de manera similar a la infraestructura más tradicional. Por ejemplo, en el arquetipo de productos sin servidor, AWS Lambda, los desarrolladores necesitan crear una función lambda y desplegar código en ella.

En otras palabras, el proceso para crear una función lambda, aunque algo menos complicado, es similar al proceso para crear un nuevo servicio con servidor. Aquí hay un ejemplo de cómo crear una función lambda usando Terraform de HashiCorp, una de las herramientas de configuración de IaC más populares. Como puedes ver, la función lambda es simplemente otro recurso:

   resource "aws_lambda_function" "my_lambda" {
  filename = "lambda_function_payload.zip"
  function_name = "lambda_function_name"
  role = aws_iam_role.iam_for_lambda.arn
  handler = "index.test"
  source_code_hash = filebase64sha256("lambda_function_payload.zip")
  runtime = "nodejs16.x"
  environment {
    variables = {
      foo = "bar"
    }
  }
}

Creando una función Lambda aprovechando HashiCorp Terraform

Resolviendo el problema del desarrollo local para arquitecturas sin servidor

Si bien la arquitectura sin servidor simplifica enormemente la gestión de la infraestructura de producción, los sistemas que ejecutan código sin servidor suelen ser complejos y propietarios, lo que puede causar problemas con el desarrollo local. En el peor de los casos, el desarrollo local no es posible y los desarrolladores deben probar los cambios locales realizando despliegues comparativamente lentos en la infraestructura de producción. En el mejor de los casos, los desarrolladores deben crear una simulación local de la compleja pila sin servidor, que luego debe mantenerse actualizada con el entorno de producción.

Comparación del entorno de desarrollo local con y sin Infraestructura definida por el Framework.

La Infraestructura Definida por el Framework elimina completamente este problema. Debido a que la Infraestructura Definida por el Framework permite que el propio framework dicte el comportamiento de producción, el desarrollo local puede utilizar simplemente las herramientas propias del framework, mientras que la infraestructura de producción se configura automáticamente para ser una representación escalada y optimizada del mismo comportamiento subyacente.

Infraestructura Definida por el Framework y despliegues inmutables

En estos días, el código de la aplicación se desarrolla casi exclusivamente dentro de sistemas de control de versiones como Git. La IaC mantiene la definición de la infraestructura en el mismo sistema de control de versiones o en uno similar. Sin embargo, a menudo, la infraestructura de producción misma solo puede representar puntos limitados en el tiempo de la historia de versiones de la infraestructura. Esto es fundamentalmente incompatible con la infraestructura definida por el framework, que espera que la infraestructura de producción se mapee directamente al código del framework en el mismo hash de confirmación.

Los despliegues inmutables resuelven esta discrepancia entre la historia de versiones de una aplicación y la infraestructura. En lugar de desplegar en un número limitado de infraestructuras como “producción” y “preproducción”, los despliegues inmutables crean una infraestructura completamente nueva para cada despliegue que se realice. Esta infraestructura luego nunca se cambia, es inmutable.

Cada confirmación recibe un despliegue inmutable y genera una infraestructura virtual.

Naturalmente, los despliegues inmutables son imposibles de realizar en un mundo donde la infraestructura se asigna a recursos físicos finitos, que se agotarían a medida que se realizan nuevos despliegues. Sin embargo, en un mundo sin servidor, donde la infraestructura no utilizada puede escalar a cero, los despliegues inmutables se vuelven posibles de realizar, ya que los despliegues no utilizados no ocupan recursos de cómputo físicos más allá del almacenamiento básico necesario para sus contenidos. Por ejemplo, la plataforma de Vercel crea un despliegue inmutable para cada git hash enviado a un repositorio, que luego se asigna a una infraestructura sin servidor completamente nueva y virtual.

Agradecimientos

La Infraestructura Definida por el Framework como idea se basa en el trabajo de gigantes. Depende de IaC como la interfaz de infraestructura definitiva y, por lo tanto, no podría funcionar sin el asombroso trabajo de su comunidad. Además, se basa en abstracciones de infraestructura como Kubernetes para ser factible dado el nivel relativamente bajo de detalle que se puede extraer del código fuente original, y el enfoque es particularmente adecuado para apuntar a ofertas de PaaS como el Google AppEngine original.

Frameworks, no primitivas

Aquí hemos discutido cómo la Infraestructura Definida por el Framework se basa en IaC al comprender cómo los patrones de un framework se mapean a primitivas de infraestructura necesarias para ejecutar código en un sistema de producción escalable, simplificando enormemente el desarrollo local.

Los despliegues inmutables basados en arquitectura sin servidor permiten que la infraestructura de producción se mapee perfectamente a la versión del código que se ejecuta en la infraestructura, siendo excepcionalmente escalable y rentable durante el uso bajo.

Vale la pena repetirlo: en Vercel, estamos implementando Infraestructura Definida por el Framework para un DevOps más predecible, de menor costo y menor riesgo a través de una arquitectura verdaderamente sin servidor, y para los desarrolladores, sin infraestructura.