
Me gustaría hablar sobre la nueva herramienta CLI que escribí para resolver un viejo problema.
El problema
Terraform ha sido durante mucho tiempo el estándar en la comunidad Devops / Cloud / IT. La cosa es muy conveniente y útil para hacer infraestructura como código. Hay muchos encantos en Terraform, así como muchos tenedores, cuchillos afilados y rastrillos.
Con Terraform, es muy conveniente hacer cosas nuevas y luego administrarlas, cambiarlas o eliminarlas. ¿Y qué hay de aquellos que tienen una gran infraestructura en la nube y no se crean a través de Terraform? Reescribir y recrear toda la nube es de alguna manera costoso e inseguro.
Encontré un problema de este tipo en 2 trabajos, el ejemplo más simple es cuando quieres que todo esté en forma de archivos de terraform, y tienes más de 250 cubos y escribes muchos de ellos para terraformar con tus manos.
Existe un
problema desde 2014 en terrafom que se cerró en 2016 con la esperanza de que haya importación.
En general, todo es como en la imagen solo de derecha a izquierda
Advertencias: El autor no vive en Rusia durante la mitad de su vida y escribe poco en ruso. Precaución errores ortográficos.
Soluciones
1. Existen soluciones llave en mano y antiguas para
terraformación de AWS. Cuando traté de atravesar mi cubo de más de 250, me di cuenta de que todo estaba mal allí. AWS ya ha presentado muchas opciones nuevas durante mucho tiempo y terraformación no las conoce y, en general, tiene una
plantilla de rubí
que se ve pobre . Después de las 2 de la tarde envié una
solicitud de extracción para agregar más funciones allí y me di cuenta de que tal solución no encaja en absoluto.
Cómo funciona la terraformación, toma datos del AWS SDK y genera tf y tfstate a través de la plantilla.
Hay 3 problemas:
1. Siempre habrá retrasos en las actualizaciones
2. los archivos tf a veces salen rotos
3. tfstate se recopila por separado de tf y no siempre converge
En general, es difícil obtener un resultado en el que el "plan de terraformación" indique que no hay cambios
2. `terraform import` - un comando incorporado en terraform. Como funciona
Escribe un archivo TF vacío con el nombre y el tipo del recurso, luego ejecuta `terraform import` y pasa la ID del recurso. Terraform llama al proveedor recibe los datos y crea un archivo tfstate.
Hay 3 problemas:
1. Obtenemos solo el archivo tfstate y el tf vacío debe escribirse o convertirse con tfstate
2. Capaz de trabajar con un solo recurso cada vez y no admite todos los recursos. ¿Y qué debo hacer de nuevo con más de 250 cubos?
3. Necesita conocer la ID del recurso, es decir, debe incluirlo en un código que extraiga una lista de recursos
En general, el resultado es parcial y no escala bien
Mis decisiones
Requisitos:
1. Capacidad para crear archivos tf y tfstate por recursos. Por ejemplo, descargue todos los cubos / grupo de seguridad / equilibrador de carga y que el 'plan de terraformación' haya devuelto que no hay cambios
2. Es necesario 2 nubes de GCP + AWS
3. Una solución global que es fácil de actualizar en todo momento y que no pierde tiempo en cada recurso durante 3 días de trabajo.
4. Hacer código abierto: todos tienen ese problema
Go language: por eso me encanta, y tiene una biblioteca para crear archivos HCL que se usa en terraform + mucho código en terraform que puede ser útil
El camino
Primer intento
Comenzó una opción simple. Acceda a la nube a través del SDK para el recurso deseado y conviértalo en campos para terraformar. El intento murió de inmediato en el grupo de seguridad porque no me gustó 1,5 días para convertir solo el grupo de seguridad (y hay muchos recursos). Los campos largos y luego se pueden cambiar / agregar
Segundo intento
Basado en la idea descrita
aquí . Solo toma y convierte tfstate a tf. Todos los datos están ahí y los campos son los mismos. ¿Cómo obtener el estado completo de muchos recursos? Entonces el comando `terraform refresh` vino al rescate. terraform toma todos los recursos en tfstate y extrae los datos por ID y escribe todo en tfstate. Es decir, cree un tfstate vacío con solo nombres e ID, ejecute `terraform refresh`, obtenemos el tfstate completo. ¡Hurra!
Ahora hagamos la
pornografía recursiva de escribir un convertidor de tfstate a tf. Para aquellos que nunca han leído tfstate, este es JSON, pero especial.
Aquí están sus atributos de parte importantes
"attributes": { "id": "default/backend-logging-load-deployment", "metadata.#": "1", "metadata.0.annotations.%": "0", "metadata.0.generate_name": "", "metadata.0.generation": "24", "metadata.0.labels.%": "1", "metadata.0.labels.app": "backend-logging", "metadata.0.name": "backend-logging-load-deployment", "metadata.0.namespace": "default", "metadata.0.resource_version": "109317427", "metadata.0.self_link": "/apis/apps/v1/namespaces/default/deployments/backend-logging-load-deployment", "metadata.0.uid": "300ecda1-4138-11e9-9d5d-42010a8400b5", "spec.#": "1", "spec.0.min_ready_seconds": "0", "spec.0.paused": "false", "spec.0.progress_deadline_seconds": "600", "spec.0.replicas": "1", "spec.0.revision_history_limit": "10", "spec.0.selector.#": "1",
Hay:
1. id - cadena
2. metadatos: una matriz de tamaño 1 y en ella un objeto con campos que se describe a continuación
3. spec - hash de tamaño 1 y en su clave, valor
En resumen, un formato divertido, todo puede ser profundo también en varios niveles
"spec.#": "1", "spec.0.min_ready_seconds": "0", "spec.0.paused": "false", "spec.0.progress_deadline_seconds": "600", "spec.0.replicas": "1", "spec.0.revision_history_limit": "10", "spec.0.selector.#": "1", "spec.0.selector.0.match_expressions.#": "0", "spec.0.selector.0.match_labels.%": "1", "spec.0.selector.0.match_labels.app": "backend-logging-load", "spec.0.strategy.#": "0", "spec.0.template.#": "1", "spec.0.template.0.metadata.#": "1", "spec.0.template.0.metadata.0.annotations.%": "0", "spec.0.template.0.metadata.0.generate_name": "", "spec.0.template.0.metadata.0.generation": "0", "spec.0.template.0.metadata.0.labels.%": "1", "spec.0.template.0.metadata.0.labels.app": "backend-logging-load", "spec.0.template.0.metadata.0.name": "", "spec.0.template.0.metadata.0.namespace": "", "spec.0.template.0.metadata.0.resource_version": "", "spec.0.template.0.metadata.0.self_link": "", "spec.0.template.0.metadata.0.uid": "", "spec.0.template.0.spec.#": "1", "spec.0.template.0.spec.0.active_deadline_seconds": "0", "spec.0.template.0.spec.0.container.#": "1", "spec.0.template.0.spec.0.container.0.args.#": "3",
En general, quién quiere una tarea de programación para una entrevista, solo pida escribir un analizador para este asunto :)
Después de largos intentos de escribir un analizador sin errores, encontré parte de él en el código de terraformación, y la parte más importante. Y todo parecía funcionar bien
Intento tres
El proveedor de terraform es un binario en el que hay un código con todos los recursos y la lógica para trabajar con la API de la nube. Cada nube tiene su propio proveedor y la propia terraforma solo los llama a través de su protocolo RPC entre dos procesos.
Ahora decidí acceder a los proveedores de terraform directamente a través de llamadas RPC. Resultó maravillosamente e hizo posible cambiar los proveedores de terraform por otros más nuevos y obtener nuevas oportunidades sin cambiar el código. Resultó que no todos los campos en tfstate deberían estar en tf, pero ¿cómo puedo averiguarlo? Solo pregúntele al proveedor sobre esto. Luego, otra
pornografía recursiva sobre el conjunto de expresiones regulares comenzó con la búsqueda con la búsqueda de campos dentro del estado en todos los niveles en profundidad.
Al final, obtuvimos una herramienta CLI útil que tiene una infraestructura común para todos los proveedores de terraformas y puede agregar fácilmente una nueva. También agregar recursos requiere poco código. Además de todo tipo de golosinas, como la conexión entre recursos. Por supuesto, hubo muchos problemas diferentes que no se pueden describir.
Llamó al animalito Terrafomer.
Final
Usando Terrafomer, generamos 500-700 mil líneas de tf + tfstate code a partir de dos nubes. Podrían tomar cosas heredadas y comenzar a tocarlas solo a través de terraform como en las mejores ideas de infraestructura como código. Es simplemente mágico cuando tomas una gran nube y la obtienes a través del comando en forma de archivos de trabajo de terraformación. Y luego grep / replace / git y así sucesivamente.
Peinó y ordenó, recibió permiso. Lanzado en github para todos el jueves (02/05/19).
github.com/GoogleCloudPlatform/terraformerYa recibió 600 estrellas, 2 solicitudes de extracción que agregaron soporte para openstack y kubernetes. Buenas críticas En general, el proyecto es útil para las personas.
Aconsejo a todos los que quieran comenzar a trabajar con Terraform y no reescribir todo para esto.
Me encantaría recibir solicitudes, problemas, estrellas.
Demo

Actualizaciones: se estropeó el soporte mínimo de Openstack y el soporte de kubernetes está casi listo, gracias a las personas de relaciones públicas