Por qué usamos Terraform y no Chef, Puppet, Ansible, SaltStack o CloudFormation

Actualización, 17 de noviembre de 2016: Tomamos esta serie de publicaciones de blog, la ampliamos y la convertimos en un libro llamado Terraform: Up & ¡En ejecución!

Actualización, 8 de julio de 2019: Hemos actualizado esta serie de publicaciones de blog para Terraform 0.12 y hemos lanzado la 2a edición de Terraform: Up & ¡En ejecución!

Esta es la Parte 1 de la Guía Completa de la serie Terraform. En la introducción a la serie, discutimos por qué todas las empresas deberían usar infraestructura como código (IAC). En este post, vamos a discutir por qué elegimos Terraform como nuestra herramienta de IAC de elección.

Si usted busca el Internet para «infraestructura como código», es muy fácil venir para arriba con una lista de las herramientas más populares:

  • Cocinero
  • Títere
  • Ansible
  • SaltStack
  • CloudFormation
  • Terraformar

Lo que no es fácil es averiguar que uno de estos debe utilizar. Todas estas herramientas se pueden usar para administrar la infraestructura como código. Todos ellos son de código abierto, respaldados por grandes comunidades de colaboradores y funcionan con muchos proveedores de nube diferentes (con la notable excepción de CloudFormation, que es de código cerrado y solo para AWS). Todos ellos ofrecen soporte empresarial. Todos ellos están bien documentados, tanto en términos de documentación oficial como de recursos de la comunidad, como publicaciones de blog y preguntas de StackOverflow. Entonces, ¿cómo decides?

Lo que hace que esto sea aún más difícil es que la mayoría de las comparaciones que encuentras en línea entre estas herramientas hacen poco más que enumerar las propiedades generales de cada herramienta y hacer que suene como si pudieras tener el mismo éxito con cualquiera de ellas. Y aunque eso es técnicamente cierto, no ayuda. Es un poco como decirle a un novato en programación que podrías tener el mismo éxito construyendo un sitio web con PHP, C o Assembly, una afirmación que es técnicamente cierta, pero que omite una gran cantidad de información que sería increíblemente útil para tomar una buena decisión.

En este post, vamos a profundizar en algunas razones muy específicas por las que elegimos Terraform sobre las otras herramientas de IAC. Al igual que con todas las decisiones tecnológicas, es una cuestión de compromisos y prioridades, y si bien sus prioridades particulares pueden ser diferentes a las nuestras, esperamos que compartir nuestro proceso de pensamiento lo ayude a tomar su propia decisión. Estas son las principales compensaciones que consideramos:

  • Gestión de configuración vs Aprovisionamiento
  • Infraestructura Mutable vs Infraestructura Inmutable
  • Procedimiento vs Declarativo
  • Maestro vs Masterless
  • Agente vs Agentless
  • Comunidad grande vs Comunidad Pequeña
  • Madura vs Vanguardia
  • Usar varias herramientas juntas

Chef, Puppet, Ansible y SaltStack son herramientas de gestión de configuración, lo que significa están diseñados para instalar y administrar software en servidores existentes. CloudFormation y Terraform son herramientas de aprovisionamiento, lo que significa que están diseñadas para aprovisionar los propios servidores (así como el resto de su infraestructura, como equilibradores de carga, bases de datos, configuración de redes, etc.), dejando el trabajo de configurar esos servidores a otras herramientas. Estas dos categorías no se excluyen mutuamente, ya que la mayoría de las herramientas de gestión de configuración pueden realizar cierto grado de aprovisionamiento y la mayoría de las herramientas de aprovisionamiento pueden realizar cierto grado de gestión de la configuración. Pero el enfoque en la gestión de la configuración o el aprovisionamiento significa que algunas de las herramientas se adaptarán mejor a ciertos tipos de tareas.

En particular, hemos descubierto que si usa Docker o Packer, la gran mayoría de sus necesidades de administración de configuración ya están atendidas. Con Docker y Packer, puede crear imágenes (como contenedores o imágenes de máquinas virtuales) que tengan todo el software que su servidor necesita ya instalado y configurado. Una vez que tenga una imagen de este tipo, todo lo que necesita es un servidor para ejecutarla. Y si todo lo que necesita hacer es aprovisionar un montón de servidores, una herramienta de aprovisionamiento como Terraform generalmente se ajustará mejor que una herramienta de administración de configuración (aquí hay un ejemplo de cómo usar Terraform para implementar Docker en AWS).

Infraestructura mutable vs Infraestructura inmutable

Las herramientas de administración de configuración, como Chef, Puppet, Ansible y SaltStack, suelen ser un paradigma de infraestructura mutable predeterminado. Por ejemplo, si le dice a Chef que instale una nueva versión de OpenSSL, ejecutará la actualización de software en sus servidores existentes y los cambios se realizarán in situ. Con el tiempo, a medida que se aplican más y más actualizaciones, cada servidor crea un historial único de cambios. Esto a menudo conduce a un fenómeno conocido como deriva de configuración, donde cada servidor se vuelve ligeramente diferente a todos los demás, lo que conduce a errores de configuración sutiles que son difíciles de diagnosticar y casi imposibles de reproducir.

Si está utilizando una herramienta de aprovisionamiento como Terraform para implementar imágenes de máquina creadas por Docker o Packer, entonces cada «cambio» es en realidad una implementación de un nuevo servidor (al igual que cada «cambio» a una variable en la programación funcional en realidad devuelve una nueva variable). Por ejemplo, para implementar una nueva versión de OpenSSL, crearía una nueva imagen utilizando Packer o Docker con la nueva versión de OpenSSL ya instalada, implementaría esa imagen en un conjunto de servidores totalmente nuevos y, a continuación, desactivaría los servidores antiguos. Este enfoque reduce la probabilidad de errores de deriva de configuración, facilita saber exactamente qué software se está ejecutando en un servidor y le permite implementar trivialmente cualquier versión anterior del software en cualquier momento. Por supuesto, también es posible forzar a las herramientas de administración de configuración a realizar implementaciones inmutables, pero no es el enfoque idiomático para esas herramientas, mientras que es una forma natural de usar las herramientas de aprovisionamiento.

Procedural vs Declarativo

Chef y Ansible fomentan un estilo procedural en el que se escribe código que especifica, paso a paso, cómo lograr el estado final deseado. Terraform, CloudFormation, SaltStack y Puppet fomentan un estilo más declarativo en el que se escribe código que especifica el estado final deseado, y la propia herramienta IAC es responsable de averiguar cómo lograr ese estado.

Por ejemplo, supongamos que desea implementar 10 servidores («Instancias EC2» en AWS lingo) para ejecutar la versión 1 de una aplicación. Aquí es un ejemplo simplificado de un Ansible plantilla que hace esto con un enfoque del procedimiento:

- ec2:
count: 10
image: ami-v1
instance_type: t2.micro

Y aquí es un ejemplo simplificado de un Terraformar plantilla que hace lo mismo que el uso de un enfoque declarativo:

resource "aws_instance" "example" {
count = 10
ami = "ami-v1"
instance_type = "t2.micro"
}

Ahora, en la superficie, estos dos enfoques pueden parecer similares, y cuando inicialmente ejecutarlas con Ansible o Terraformar, van a producir resultados similares. Lo interesante es lo que sucede cuando quieres hacer un cambio.

Por ejemplo, imagine que el tráfico ha aumentado y desea aumentar el número de servidores a 15. Con Ansible, el código de procedimiento que escribió anteriormente ya no es útil; si solo actualizara el número de servidores a 15 y volviera a escanear ese código, desplegaría 15 servidores nuevos, ¡lo que le daría un total de 25! Por lo tanto, en su lugar, debe estar al tanto de lo que ya está implementado y escribir un script de procedimiento totalmente nuevo para agregar los 5 nuevos servidores:

- ec2:
count: 5
image: ami-v1
instance_type: t2.micro

Con código declarativo, ya que todo lo que hace es declarar el estado final que desea, y Terraform descubre cómo llegar a ese estado final, Terraform también estará al tanto de cualquier estado que haya creado en el pasado. Por lo tanto, para desplegar 5 servidores más, todo lo que tiene que hacer es volver a la misma plantilla de Terraform y actualizar el recuento de 10 a 15:

resource "aws_instance" "example" {
count = 15
ami = "ami-v1"
instance_type = "t2.micro"
}

Si ejecuta esta plantilla, Terraform se dará cuenta de que ya ha creado 10 servidores y, por lo tanto, que todo lo que necesita hacer es crear 5 servidores nuevos. De hecho, antes de ejecutar esta plantilla, puede usar el comando plan para obtener una vista previa de los cambios que realizaría:

$ terraform plan+ aws_instance.example.11
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.12
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.13
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.14
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.15
ami: "ami-v1"
instance_type: "t2.micro"Plan: 5 to add, 0 to change, 0 to destroy.

Ahora, ¿qué sucede cuando desea implementar el servicio v2? Con el enfoque de procedimiento, las dos plantillas anteriores de Ansible tampoco son útiles, por lo que debe escribir otra plantilla para rastrear los 10 servidores que implementó anteriormente (¿o eran 15 ahora?) y actualice cuidadosamente cada uno a la nueva versión. Con el enfoque declarativo de Terraform, vuelve a la misma plantilla y simplemente cambia el número de versión de ami a v2:

resource "aws_instance" "example" {
count = 15
ami = "ami-v2"
instance_type = "t2.micro"
}

Obviamente, los ejemplos anteriores se simplifican. Ansible le permite usar etiquetas para buscar instancias EC2 existentes antes de implementar otras nuevas (por ejemplo, usando los parámetros instance_tags y count_tag), pero tener que calcular manualmente este tipo de lógica para cada recurso que administre con Ansible, basado en el historial pasado de cada recurso, puede ser sorprendentemente complicado (por ejemplo, encontrar instancias existentes no solo por etiqueta, sino también por versión de imagen, zona de disponibilidad, etc.). Esto pone de relieve dos problemas principales con las herramientas de IAC de procedimiento:

  1. Cuando se trata de código de procedimiento, el estado de la infraestructura no se refleja completamente en el código. Leer las tres plantillas de Ansible que creamos anteriormente no es suficiente para saber qué se implementa. También tendrías que saber el orden en el que aplicamos esas plantillas. Si los hubiéramos aplicado en un orden diferente, podríamos terminar con una infraestructura diferente, y eso no es algo que se pueda ver en la base de código en sí. En otras palabras, para razonar sobre una base de código Ansible o Chef, debe conocer la historia completa de cada cambio que haya ocurrido.
  2. La reutilización del código de procedimiento es inherentemente limitada porque debe tener en cuenta manualmente el estado actual de la base de código. Dado que ese estado cambia constantemente, es posible que el código que usó hace una semana ya no se pueda usar porque fue diseñado para modificar un estado de su infraestructura que ya no existe. Como resultado, las bases del código de procedimiento tienden a crecer y complicarse con el tiempo.

Por otro lado, con el tipo de enfoque declarativo utilizado en Terraform, el código siempre representa el estado más reciente de su infraestructura. De un vistazo, puede saber qué se implementa actualmente y cómo se configura, sin tener que preocuparse por el historial o el calendario. Esto también facilita la creación de código reutilizable, ya que no tiene que contabilizar manualmente el estado actual del mundo. En su lugar, solo se centra en describir el estado deseado y Terraform descubre cómo pasar de un estado a otro automáticamente. Como resultado, los códigos base de Terraform tienden a ser pequeños y fáciles de entender.

Por supuesto, también hay desventajas en los lenguajes declarativos. Sin acceso a un lenguaje de programación completo, su poder expresivo es limitado. Por ejemplo, algunos tipos de cambios en la infraestructura, como una implementación continua sin tiempo de inactividad, son difíciles de expresar en términos puramente declarativos. Del mismo modo, sin la capacidad de hacer «lógica» (por ejemplo, sentencias if, bucles), crear código genérico y reutilizable puede ser complicado (especialmente en CloudFormation). Afortunadamente, Terraform proporciona una serie de potentes primitivas, como variables de entrada, variables de salida, módulos, create_before_destroy y count, que hacen posible crear código limpio, configurable y modular incluso en un lenguaje declarativo. Hablaremos más sobre estas herramientas en la Parte 4, Cómo crear infraestructura reutilizable con módulos Terraform y en la Parte 5, Consejos de Terraform & trucos: bucles, instrucciones if y trampas.

Maestro versus Maestro Sin maestro

De forma predeterminada, Chef, Puppet y SaltStack requieren que ejecute un servidor maestro para almacenar el estado de su infraestructura y distribuir actualizaciones. Cada vez que desea actualizar algo en su infraestructura, utiliza un cliente (por ejemplo, una herramienta de línea de comandos) para emitir nuevos comandos al servidor maestro, y el servidor maestro envía las actualizaciones a todos los demás servidores, o bien esos servidores descargan las últimas actualizaciones del servidor maestro de forma regular.

Un servidor maestro ofrece algunas ventajas. En primer lugar, es un lugar único y central donde puede ver y administrar el estado de su infraestructura. Muchas herramientas de administración de configuración incluso proporcionan una interfaz web (por ejemplo, la consola Chef, la consola Puppet Enterprise) para que el servidor maestro sea más fácil de ver lo que está sucediendo. En segundo lugar, algunos servidores maestros pueden ejecutarse continuamente en segundo plano y hacer cumplir su configuración. De esta manera, si alguien realiza un cambio manual en un servidor, el servidor maestro puede revertir ese cambio para evitar la desviación de la configuración.

Sin embargo, tener que ejecutar un servidor maestro tiene algunos inconvenientes graves:

  • Infraestructura adicional: Debe implementar un servidor adicional, o incluso un clúster de servidores adicionales (para alta disponibilidad y escalabilidad), solo para ejecutar el maestro.
  • Mantenimiento: Debe mantener, actualizar, realizar copias de seguridad, supervisar y escalar los servidores maestros.
  • Seguridad: Debe proporcionar una forma para que el cliente se comunique con los servidores maestros y una forma para que los servidores maestros se comuniquen con todos los demás servidores, lo que generalmente significa abrir puertos adicionales y configurar sistemas de autenticación adicionales, todo lo cual aumenta su área de superficie para los atacantes.

Chef, Puppet y SaltStack tienen diferentes niveles de soporte para modos masterless en los que solo ejecuta su software de agente en cada uno de sus servidores, normalmente en un horario periódico (por ejemplo, un trabajo cron que se ejecuta cada 5 minutos), y lo usa para descargar las últimas actualizaciones desde control de versiones (en lugar de desde un servidor maestro). Esto reduce significativamente el número de partes móviles, pero, como se explica en la siguiente sección, esto todavía deja una serie de preguntas sin respuesta, especialmente sobre cómo aprovisionar los servidores e instalar el software del agente en ellos en primer lugar.

Ansible, CloudFormation, Heat y Terraform son todos sin maestro de forma predeterminada. O, para ser más precisos, algunos de ellos pueden depender de un servidor maestro, pero ya es parte de la infraestructura que está utilizando y no una pieza adicional que debe administrar. Por ejemplo, Terraform se comunica con los proveedores de nube mediante las API del proveedor de nube, por lo que, en cierto sentido, los servidores de API son servidores maestros, excepto que no requieren ninguna infraestructura adicional ni ningún mecanismo de autenticación adicional (es decir, solo usa tus claves de API). Ansible funciona conectándose directamente a cada servidor a través de SSH, por lo que, de nuevo, no tiene que ejecutar ninguna infraestructura adicional ni administrar mecanismos de autenticación adicionales (es decir, solo use sus claves SSH).

Agente Frente a Agente sin agente

Chef, Puppet y SaltStack requieren que instale software de agente (por ejemplo, Cliente Chef, Agente Puppet, Minion Salt) en cada servidor que desee configurar. El agente normalmente se ejecuta en segundo plano en cada servidor y es responsable de instalar las últimas actualizaciones de administración de configuración.

Esto tiene algunos inconvenientes:

  • Bootstrapping: ¿Cómo aprovisiona sus servidores e instala el software del agente en ellos en primer lugar? Algunas herramientas de administración de configuración ponen en marcha la lata, suponiendo que algún proceso externo se encargue de esto (por ejemplo, primero usa Terraform para implementar un grupo de servidores con una imagen de máquina virtual que tiene el agente ya instalado); otras herramientas de administración de configuración tienen un proceso de arranque especial en el que ejecuta comandos únicos para aprovisionar los servidores utilizando las API de proveedores de nube e instalar el software del agente en esos servidores a través de SSH.
  • Mantenimiento: Debe actualizar cuidadosamente el software del agente de forma periódica, teniendo cuidado de mantenerlo sincronizado con el servidor maestro si lo hay. También debe supervisar el software del agente y reiniciarlo si se bloquea.
  • Seguridad: Si el software del agente descarga la configuración de un servidor maestro (o de otro servidor si no está utilizando un servidor maestro), debe abrir los puertos de salida en cada servidor. Si el servidor maestro envía la configuración al agente, debe abrir los puertos de entrada en cada servidor. En cualquier caso, debe averiguar cómo autenticar al agente en el servidor con el que está hablando. Todo esto aumenta la superficie de los atacantes.

Una vez más, Chef, Puppet y SaltStack tienen diferentes niveles de soporte para modos sin agentes (por ejemplo, salt-ssh), pero a menudo se sienten como si se hubieran agregado como una idea de último momento y no siempre admiten el conjunto completo de funciones de la herramienta de administración de configuración. Es por eso que en la naturaleza, la configuración predeterminada o idiomática para Chef, Puppet y SaltStack casi siempre incluye un agente, y generalmente también un maestro.

Todas estas piezas móviles adicionales introducen un gran número de nuevos modos de fallo en su infraestructura. Cada vez que reciba un informe de error a las 3 a.m., tendrá que averiguar si se trata de un error en el código de su aplicación, o en su código IAC, o en el cliente de administración de configuración, o en los servidores maestros, o la forma en que el cliente habla con los servidores maestros, o la forma en que otros servidores hablan con los servidores maestros, o An

Ansible, CloudFormation, Heat y Terraform no requieren que instale agentes adicionales. O, para ser más precisos, algunos de ellos requieren agentes, pero por lo general ya están instalados como parte de la infraestructura que está utilizando. Por ejemplo, AWS, Azure, Google Cloud y todos los demás proveedores de nube se encargan de instalar, administrar y autenticar el software de agente en cada uno de sus servidores físicos. Como usuario de Terraform, no tiene que preocuparse por nada de eso: solo emite comandos y los agentes del proveedor de la nube los ejecutan en todos sus servidores. Con Ansible, sus servidores necesitan ejecutar
el Demonio SSH, que es común ejecutar en la mayoría de los servidores de todos modos.

Comunidad grande vs Comunidad pequeña

Cada vez que eliges una tecnología, también eliges una comunidad. En muchos casos, el ecosistema alrededor del proyecto puede tener un impacto mayor en su experiencia que la calidad inherente de la tecnología en sí. La comunidad determina cuántas personas contribuyen al proyecto, cuántos complementos, integraciones
y extensiones están disponibles, qué tan fácil es encontrar ayuda en línea (por ejemplo, publicaciones de blog, preguntas sobre StackOverflow) y qué tan fácil es contratar a alguien para que te ayude (por ejemplo, un empleado, consultor o empresa de soporte).

Es difícil hacer una comparación precisa entre comunidades, pero puedes detectar algunas tendencias buscando en línea. La siguiente tabla muestra una comparación de herramientas de IAC populares, con datos que recopilé durante mayo de 2019, que incluyen si la herramienta de IAC es de código abierto o de código cerrado, qué proveedores de nube admite, el número total de colaboradores y estrellas en GitHub, cuántas confirmaciones y problemas activos hubo durante un período de un mes desde mediados de abril hasta mediados de mayo, cuántas bibliotecas de código abierto están disponibles para la herramienta, el número de preguntas que se enumeran para esa herramienta en StackOverflow y el número de trabajos que mencionan la herramienta en Indeed.com.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *