tutorial tool providers deploy devops terraform

devops - tool - terraform tutorial



Mejores prácticas al usar Terraform (8)

Antes de que las respuestas hayan sido muy sólidas e informativas, intentaré agregar mis 2 centavos aquí

Recomendaciones comunes para estructurar código

  1. Es más fácil y rápido trabajar con un menor número de recursos:

    • El terraform plan Cmds y la aplicación de terraform aplican llamadas API de nube para verificar el estado de los recursos.
    • Si tiene toda su infraestructura en una sola composición, esto puede llevar muchos minutos (incluso si tiene varios archivos en la misma carpeta).
  2. El radio de explosión es más pequeño con menos recursos:

    • Aislar los recursos no relacionados entre sí colocándolos en composiciones separadas (carpetas) reduce el riesgo si algo sale mal.
  3. Comience su proyecto usando el estado remoto:

  4. Intente practicar una estructura consistente y una convención de nomenclatura:

    • Al igual que el código de procedimiento, el código de Terraform debe escribirse para que las personas lo lean primero, la coherencia ayudará cuando ocurran cambios dentro de seis meses.
    • Es posible mover recursos en el archivo de estado de Terraform, pero puede ser más difícil si tiene una estructura y un nombre inconsistentes.
  5. Mantenga los módulos de recursos tan simples como sea posible.

  6. No codifique valores que puedan pasarse como variables o descubrirse utilizando fuentes de datos.

  7. Utilice data fuentes de data y terraform_remote_state específicamente como un pegamento entre los módulos de infraestructura dentro de la composición.

( Artículo de referencia: https://www.terraform-best-practices.com/code-structure )

Ejemplo:

Es más fácil y rápido trabajar con un número menor de recursos, por lo que a continuación presentamos un diseño de código recomendado.

NOTA: solo como referencia no debe seguirse estrictamente ya que cada proyecto tiene sus propias características específicas

. ├── 1_tf-backend #remote AWS S3 + Dynamo Lock tfstate │ ├── main.tf │ ├── ... ├── 2_secrets │ ├── main.tf │ ├── ... ├── 3_identities │ ├── account.tf │ ├── roles.tf │ ├── group.tf │ ├── users.tf │ ├── ... ├── 4_security │ ├── awscloudtrail.tf │ ├── awsconfig.tf │ ├── awsinspector.tf │ ├── awsguarduty.tf │ ├── awswaf.tf │ └── ... ├── 5_network │ ├── account.tf │ ├── dns_remote_zone_auth.tf │ ├── dns.tf │ ├── network.tf │ ├── network_vpc_peering_dev.tf │ ├── ... ├── 6_notifications │ ├── ... ├── 7_containers │ ├── account.tf │ ├── container_registry.tf │ ├── ... ├── config │ ├── backend.config │ └── main.config └── readme.md

Estoy en el proceso de cambiar nuestra infraestructura en terraform. ¿Cuál es la mejor práctica para administrar realmente los archivos de terraform y el estado? Me doy cuenta de que es una infraestructura como código, y comprometeré mis archivos .tf en git, pero ¿también confirmo tfstate? ¿Debería residir en algún lugar como S3? Eventualmente me gustaría que CI maneje todo esto, pero eso está muy extendido y requiere que descubra las piezas en movimiento para los archivos.

Realmente solo estoy buscando ver cómo la gente utiliza este tipo de cosas en la producción


Anteriormente, remote config permitía esto, pero ahora ha sido reemplazado por " backends ", por lo que el control remoto de terraform ya no está disponible.

terraform remote config -backend-config="bucket=<s3_bucket_to_store_tfstate>" -backend-config="key=terraform.tfstate" -backend=s3 terraform remote pull terraform apply terraform remote push

Ver los docs para más detalles.


Creo que hay pocas prácticas recomendadas que se deben seguir al usar terraform para orquestar la infraestructura

  1. No vuelva a escribir el mismo código (Reusabilidad)
  2. Mantenga la configuración del entorno separada para mantenerla fácilmente.
  3. Use el backend remoto s3 (encriptado) y dynamo DB para manejar el bloqueo de concurrencia
  4. Cree un módulo y use ese módulo en la infraestructura principal varias veces, es como una función reutilizable a la que se puede llamar varias veces al pasar parámetros diferentes.

Manejar múltiples ambientes

La mayoría de las veces la forma recomendada es usar el ''espacio de trabajo'' de terraform para manejar los múltiples entornos, pero creo que el uso del espacio de trabajo podría variar según la forma de trabajo en una organización. Otro es almacenar el código Terraform para cada uno de sus entornos (por ejemplo, etapa, producción, control de calidad) para separar los estados del entorno. Sin embargo, en este caso solo estamos copiando el mismo código en muchos lugares.

├── main.tf ├── dev │ ├── main.tf │ ├── output.tf │ └── variables.tf └── prod ├── main.tf ├── output.tf └── variables.tf

Seguí un enfoque diferente para manejar y evitar la duplicación del mismo código de terraformación al guardar en cada carpeta de entorno, ya que creo que la mayoría de las veces todo el entorno sería 90% igual.

├── deployment │ ├── 01-network.tf │ ├── 02-ecs_cluster.tf │ ├── 03-ecs_service.tf │ ├── 04-eks_infra.tf │ ├── 05-db_infra.tf │ ├── 06-codebuild-k8s.tf │ ├── 07-aws-secret.tf │ ├── backend.tf │ ├── provider.tf │ └── variables.tf ├── env │ ├── dev │ │ ├── dev.backend.tfvar │ │ └── dev.variables.tfvar │ └── prod │ ├── prod.backend.tfvar │ └── prod.variables.tfvar ├── modules │ └── aws │ ├── compute │ │ ├── alb_loadbalancer │ │ ├── alb_target_grp │ │ ├── ecs_cluster │ │ ├── ecs_service │ │ └── launch_configuration │ ├── database │ │ ├── db_main │ │ ├── db_option_group │ │ ├── db_parameter_group │ │ └── db_subnet_group │ ├── developertools │ ├── network │ │ ├── internet_gateway │ │ ├── nat_gateway │ │ ├── route_table │ │ ├── security_group │ │ ├── subnet │ │ ├── vpc │ └── security │ ├── iam_role │ └── secret-manager └── templates

Configuración relacionada con entornos

Mantenga la configuración y los parámetros relacionados con el entorno por separado en un archivo variable y pase ese valor para configurar la infraestructura. por ejemplo, como a continuación

  • dev.backend.tfvar

    region = "ap-southeast-2" bucket = "dev-samplebackendterraform" key = "dev/state.tfstate" dynamo_db_lock = "dev-terraform-state-lock"

  • dev.variable.tfvar

    environment = "dev" vpc_name = "demo" vpc_cidr_block = "10.20.0.0/19" private_subnet_1a_cidr_block = "10.20.0.0/21" private_subnet_1b_cidr_block = "10.20.8.0/21" public_subnet_1a_cidr_block = "10.20.16.0/21" public_subnet_1b_cidr_block = "10.20.24.0/21"

Salto condicional de parte de infraestructura

Cree una configuración en un archivo de variable específica de env y, en función de esa variable, decida crear u omitir esa parte. De esta manera, según la necesidad, se puede omitir la parte específica de la infraestructura.

variable vpc_create { default = "true" } module "vpc" { source = "../modules/aws/network/vpc" enable = "${var.vpc_create}" vpc_cidr_block = "${var.vpc_cidr_block}" name = "${var.vpc_name}" } resource "aws_vpc" "vpc" { count = "${var.enable == "true" ? 1 : 0}" cidr_block = "${var.vpc_cidr_block}" enable_dns_support = "true" enable_dns_hostnames = "true" }

Se requiere el siguiente comando para inicializar y ejecutar los cambios infra para cada entorno, cd a la carpeta de entorno requerida.

terraform init -var-file=dev.variables.tfvar -backend-config=dev.backend.tfvar ../../deployment/ terraform apply -var-file=dev.variables.tfvar ../../deployment

Para referencia: https://github.com/mattyait/devops_terraform


Cubierto con más profundidad por @Yevgeny Brikman pero respondiendo específicamente a las preguntas del OP:

¿Cuál es la mejor práctica para administrar realmente los archivos de terraform y el estado?

Use git para archivos TF. Pero no verifique los archivos de estado en (es decir, tfstate). En su lugar, use Terragrunt para sincronizar / bloquear archivos de estado a S3.

pero ¿me comprometo tfstate también?

No.

¿Debería residir en algún lugar como S3?

si


Sé que hay muchas respuestas aquí, pero mi enfoque es bastante diferente.

⁃ Modules ⁃ Environment management ⁃ Separation of duties

Módulos

  1. Crear módulos para colecciones lógicas de recursos. Ejemplo: si su objetivo es implementar una API, que requiere una base de datos, máquinas virtuales de alta disponibilidad, escalado automático, DNS, PubSub y almacenamiento de objetos, entonces todos estos recursos deben tener una plantilla en un solo módulo.
  2. Evite crear módulos que utilicen un solo recurso. Esto se puede hacer y se ha hecho, y muchos de los módulos en el registro lo hacen, pero es una práctica que ayuda con la accesibilidad de los recursos en lugar de la orquestación de la infraestructura. Ejemplo: Un módulo para AWS EC2 ayuda al usuario a acceder al EC2 al hacer que las configuraciones complejas sean más simples de invocar, pero un módulo como el ejemplo en 1. ayuda al usuario a organizar la aplicación, la infraestructura de componentes o servicios.
    1. Evite las declaraciones de recursos en su espacio de trabajo. Esto se trata más de mantener su código ordenado y organizado. Como los módulos se versionan fácilmente, tiene más control sobre sus versiones.

Gestión del medio ambiente

IaC ha hecho que el proceso SDLC sea relevante para la gestión de la infraestructura y no es normal esperar tener infraestructura de desarrollo y entornos de aplicaciones de desarrollo.

  1. No use carpetas para administrar sus entornos IaC. Esto lleva a la deriva ya que no hay una plantilla común para su infraestructura.
  2. Utilice un solo espacio de trabajo y variables para controlar las especificaciones del entorno. Ejemplo: escriba sus módulos para que cuando cambie la variable de entorno (var.stage sea popular) el plan se modifique para adaptarse a sus requisitos. Normalmente, los entornos deben variar lo menos posible, siendo la cantidad, la exposición y la capacidad las configuraciones variables. Dev puede implementar 1 VM con 1 núcleo y 1 GB de RAM en topología privada, pero la producción puede ser de 3 VM con 2 núcleos y 4 GB de RAM con topología pública adicional. Por supuesto, puede tener más variación: el desarrollador puede ejecutar el proceso de la base de datos en el mismo servidor que la aplicación para ahorrar costos, pero la producción puede tener una instancia de base de datos dedicada. Todo esto se puede gestionar cambiando una sola variable, declaraciones ternarias e interpolación.

Separación de tareas

Si está en una organización pequeña o ejecuta una infraestructura personal, esto realmente no se aplica, pero lo ayudará a administrar sus operaciones.

  1. Descomponga su infraestructura por deberes, responsabilidades o equipos. Ejemplo: Control central de TI subyacente a los servicios compartidos (redes virtuales, subredes, direcciones IP públicas, grupos de registro, recursos de gobernanza, bases de datos multipropiedad, claves compartidas, etc.) mientras que el equipo de API solo controla los recursos necesarios para su servicio (VM, LB) , PubSub, etc.) y consumen servicios de TI centrales a través de fuentes de datos y búsquedas de estado remotas.
    1. Gobierna el acceso del equipo. Ejemplo: TI central puede tener derechos de administrador, pero el equipo de API solo tiene acceso a un conjunto restringido de API de nube pública.

Esto también ayuda con las preocupaciones de liberación, ya que encontrará que algunos recursos rara vez cambian, mientras que otros cambian todo el tiempo. La separación elimina el riesgo y la complejidad.

Esta estrategia traza paralelos con la estrategia de múltiples cuentas de AWS. Lee para más información.

CI / CD

Este es un tema en sí mismo, pero Terraform funciona muy bien dentro de una buena tubería. El error más común aquí es tratar a CI como una bala de plata. Técnicamente, Terraform solo debe aprovisionar infraestructura durante las etapas de una tubería de ensamblaje. Esto estaría separado de lo que sucede en las etapas de CI en las que normalmente se validan y prueban las plantillas.

Nota: escrito en el móvil, así que disculpe cualquier error.


Si todavía está buscando la mejor solución, eche un vistazo a los espacios de trabajo que pueden reemplazar el mantenimiento de una estructura de carpeta de entorno diferente que puede tener variables específicas del espacio de trabajo.

Como mentioned , es mejor tener una estructura de módulos.


También estoy en un estado de migración de la infraestructura de AWS existente a Terraform, por lo que mi objetivo será actualizar la respuesta a medida que me desarrolle.

He estado confiando mucho en los examples oficiales de Terraform y en múltiples pruebas y errores para desarrollar áreas en las que no estaba seguro.

archivos .tfstate

La configuración de Terraform se puede usar para aprovisionar muchas cajas en diferentes infraestructuras, cada una de las cuales podría tener un estado diferente. Como también puede ser administrado por varias personas, este estado debe estar en una ubicación centralizada (como S3) pero no en git.

Esto se puede confirmar mirando el Terraform .gitignore .

Control de desarrollador

Nuestro objetivo es proporcionar un mayor control de la infraestructura a los desarrolladores al tiempo que mantenemos una auditoría completa (registro de git) y la capacidad de realizar cambios de comprobación de cordura (solicitudes de extracción). Con eso en mente, el nuevo flujo de trabajo de infraestructura al que apunto es:

  1. Base básica de AMI comunes que incluyen módulos reutilizables, por ejemplo, títeres.
  2. Infraestructura central aprovisionada por DevOps usando Terraform.
  3. Los desarrolladores cambian la configuración de Terraform en Git según sea necesario (número de instancias; nueva VPC; adición de región / zona de disponibilidad, etc.).
  4. Se aplicó la configuración de Git y un miembro del escuadrón de DevOps verificó una solicitud de extracción para que fuera comprobada.
  5. Si se aprueba, llama al webhook a CI para compilar e implementar (no está seguro de cómo particionar múltiples entornos en este momento)

Edición 1 - Actualización sobre el estado actual

Desde que comencé esta respuesta, he escrito mucho código TF y me siento más cómodo en nuestro estado de cosas. Hemos encontrado errores y restricciones en el camino, pero acepto que esta es una característica del uso de un nuevo software que cambia rápidamente.

Diseño

Tenemos una infraestructura de AWS complicada con múltiples VPC, cada una con múltiples subredes. La clave para gestionar esto fácilmente fue definir una taxonomía flexible que abarque la región, el entorno, el servicio y el propietario, que podemos utilizar para organizar nuestro código de infraestructura (tanto terraform como puppet).

Módulos

El siguiente paso fue crear un único repositorio git para almacenar nuestros módulos de terraformación. Nuestra estructura de directorios de nivel superior para los módulos se ve así:

tree -L 1 .

Resultado:

├── README.md ├── aws-asg ├── aws-ec2 ├── aws-elb ├── aws-rds ├── aws-sg ├── aws-vpc └── templates

Cada uno establece algunos valores predeterminados razonables, pero los expone como variables que nuestro "pegamento" puede sobrescribir.

pegamento

Tenemos un segundo repositorio con nuestro glue que hace uso de los módulos mencionados anteriormente. Se presenta de acuerdo con nuestro documento de taxonomía:

. ├── README.md ├── clientA │   ├── eu-west-1 │   │   └── dev │   └── us-east-1 │   └── dev ├── clientB │   ├── eu-west-1 │   │   ├── dev │   │   ├── ec2-keys.tf │   │   ├── prod │   │   └── terraform.tfstate │   ├── iam.tf │   ├── terraform.tfstate │   └── terraform.tfstate.backup └── clientC ├── eu-west-1 │   ├── aws.tf │   ├── dev │   ├── iam-roles.tf │   ├── ec2-keys.tf │   ├── prod │   ├── stg │   └── terraform.tfstate └── iam.tf

Dentro del nivel del cliente tenemos archivos .tf específicos de la cuenta de AWS que aprovisionan recursos globales (como los roles de IAM); el siguiente es el nivel de región con claves públicas SSH EC2; Finalmente en nuestro entorno ( dev , stg , prod , etc.) se almacenan nuestras configuraciones de VPC, creación de instancias y conexiones entre pares, etc.

Nota al margen: Como puede ver, voy en contra de mi propio consejo sobre mantener terraform.tfstate en git. Esta es una medida temporal hasta que me mude a S3, pero me conviene, ya que actualmente soy el único desarrollador.

Próximos pasos

Esto todavía es un proceso manual y aún no está en Jenkins, pero estamos portando una infraestructura bastante grande y complicada y hasta ahora tan buena. Como dije, ¡algunos errores pero van bien!

Edición 2 - Cambios

Ha pasado casi un año desde que escribí esta respuesta inicial y tanto el estado de Terraform como el mío han cambiado significativamente. Ahora estoy en una nueva posición usando Terraform para administrar un clúster de Azure y Terraform ahora es v0.10.7 .

Estado

La gente me ha dicho repetidamente que el estado no debe ir en Git, y están en lo correcto. Usamos esto como una medida provisional con un equipo de dos personas que confiaba en la comunicación y disciplina del desarrollador. Con un equipo más grande y distribuido, ahora estamos aprovechando completamente el estado remoto en S3 con locking proporcionado por DynamoDB. Idealmente, esto se migrará a cónsul, ahora es v1.0 cortar proveedores de nube cruzada.

Módulos

Anteriormente creamos y utilizamos módulos internos. Este sigue siendo el caso, pero con el advenimiento y el crecimiento del registro de Terraform tratamos de usarlos como al menos una base.

Estructura de archivo

La nueva posición tiene una taxonomía mucho más simple con solo dos entornos infx: dev y prod . Cada uno tiene sus propias variables y salidas, reutilizando nuestros módulos creados anteriormente. El proveedor remote_state también ayuda a compartir las salidas de los recursos creados entre entornos. Nuestro escenario es subdominios en diferentes grupos de recursos de Azure para un TLD administrado globalmente.

├── main.tf ├── dev │   ├── main.tf │   ├── output.tf │   └── variables.tf └── prod ├── main.tf ├── output.tf └── variables.tf

Planificación

Una vez más, con los desafíos adicionales de un equipo distribuido, ahora siempre guardamos nuestra salida del comando de terraform plan . Podemos inspeccionar y saber qué se ejecutará sin el riesgo de algunos cambios entre el plan y la etapa de apply (aunque el bloqueo ayuda con esto). Recuerde eliminar este archivo de plan ya que podría contener variables "secretas" de texto sin formato.

En general, estamos muy contentos con Terraform y seguimos aprendiendo y mejorando con las nuevas funciones agregadas.


Utilizamos Terraform en gran medida y nuestra configuración recomendada es la siguiente:

Diseño de archivo

Recomendamos encarecidamente almacenar el código Terraform para cada uno de sus entornos (p. Ej., Stage, prod, qa) en conjuntos separados de plantillas (y, por lo tanto, archivos .tfstate separados). Esto es importante para que sus entornos separados estén realmente aislados unos de otros al realizar cambios. De lo contrario, mientras juegas con algo de código en la puesta en escena, también es demasiado fácil hacer explotar algo en productos. Vea Terraform, VPC y por qué desea un archivo tfstate por env para una discusión colorida de por qué.

Por lo tanto, nuestro diseño de archivo típico se ve así:

stage └ main.tf └ vars.tf └ outputs.tf prod └ main.tf └ vars.tf └ outputs.tf global └ main.tf └ vars.tf └ outputs.tf

Todo el código de Terraform para el VPC del escenario va a la carpeta del stage , todo el código para el VPC prod va a la carpeta prod , y todo el código que vive fuera de un VPC (por ejemplo, usuarios de IAM, temas de SNS, cubos S3) entra La carpeta global .

Tenga en cuenta que, por convención, generalmente dividimos nuestro código de Terraform en 3 archivos:

  • vars.tf : variables de entrada.
  • outputs.tf : variables de salida.
  • main.tf : los recursos reales.

Módulos

Por lo general, definimos nuestra infraestructura en dos carpetas:

  1. infrastructure-modules : esta carpeta contiene infrastructure-modules pequeños, reutilizables y versionados. Piense en cada módulo como un modelo de cómo crear una sola pieza de infraestructura, como una VPC o una base de datos.
  2. infrastructure-live : esta carpeta contiene la infraestructura real en ejecución que se crea al combinar los módulos en los módulos de infrastructure-modules . Piense en el código de esta carpeta como las casas reales que construyó a partir de sus planos.

Un módulo de Terraform es cualquier conjunto de plantillas de Terraform en una carpeta. Por ejemplo, podríamos tener una carpeta llamada vpc en infrastructure-modules que define todas las tablas de rutas, subredes, puertas de enlace, ACL, etc. para una sola VPC:

infrastructure-modules └ vpc └ main.tf └ vars.tf └ outputs.tf

Entonces podemos usar ese módulo en infrastructure-live/stage e infrastructure-live/prod para crear el VPC de escenario y prod. Por ejemplo, así es como se vería infrastructure-live/stage/main.tf :

module "stage_vpc" { source = "git::[email protected]:gruntwork-io/module-vpc.git//modules/vpc-app?ref=v0.0.4" vpc_name = "stage" aws_region = "us-east-1" num_nat_gateways = 3 cidr_block = "10.2.0.0/18" }

Para usar un módulo, use el recurso del module y apunte su campo de source a una ruta local en su disco duro (por ejemplo, source = "../infrastructure-modules/vpc" ) o, como en el ejemplo anterior, a una URL de Git (ver fuentes del módulo ). La ventaja de la URL de Git es que podemos especificar un git sha1 o etiqueta específico ( ref=v0.0.4 ). Ahora, no solo definimos nuestra infraestructura como un conjunto de pequeños módulos, sino que también podemos versionar esos módulos y actualizarlos o revertirlos cuidadosamente según sea necesario.

Hemos creado una serie de paquetes de infraestructura reutilizables, probados y documentados para crear VPC, clústeres Docker, bases de datos, etc., y bajo el capó, la mayoría de ellos son solo módulos Terraform versionados.

Estado

Cuando utiliza Terraform para crear recursos (por ejemplo, instancias EC2, bases de datos, VPC), registra información sobre lo que creó en un archivo .tfstate . Para realizar cambios en esos recursos, todos los .tfstate su equipo necesitan acceder a este mismo archivo .tfstate , pero NO debe ingresarlo en Git (consulte aquí para obtener una explicación ).

En su lugar, recomendamos almacenar archivos .tfstate en S3 habilitando Terraform Remote State , que automáticamente empujará / extraerá los últimos archivos cada vez que ejecute Terraform. Asegúrese de habilitar el control de versiones en su bucket S3 para que pueda volver a los archivos .tfstate más .tfstate en caso de que de alguna manera dañe la última versión. Sin embargo, una nota importante: Terraform no proporciona bloqueo . Entonces, si dos miembros del equipo ejecutan .tfstate al mismo tiempo en el mismo archivo .tfstate , pueden terminar sobrescribiendo los cambios de los demás.

Para resolver este problema, creamos una herramienta de código abierto llamada Terragrunt , que es un envoltorio delgado para Terraform que usa Amazon DynamoDB para proporcionar el bloqueo (que debería ser completamente gratuito para la mayoría de los equipos). Consulte Agregar bloqueo y configuración de estado remoto automático a Terraform con Terragrunt para obtener más información.

Otras lecturas

Acabamos de comenzar una serie de publicaciones de blog llamada Una guía completa de Terraform que describe en detalle todas las mejores prácticas que hemos aprendido para usar Terraform en el mundo real.

Actualización: la serie completa de publicaciones de blog de la Guía Terraform se hizo tan popular que la expandimos a un libro llamado Terraform: Up & Running !