Infrastructure as Code con Pulumi

Infrastructure as Code con Pulumi
Photo by Tudor Baciu / Unsplash

Introducción

Según la CNCF la Infrastructure as Code (IaC) es la práctica de almacenar la definición de la infraestructura como uno o más archivos. Esta práctica reemplaza el modelo tradicional en el que la infraestructura como servicio se aprovisiona manualmente, generalmente a través de scripts de shell u otras herramientas de configuración.

En las últimas semanas me ha tocado trabajar con algunas herramientas de Infrastructures as Code y entre estas herramientas se encuentra Pulumi que es una herramienta open-source (con [servicios de paga]) escrita en Go que nos permite crear Infraestructura en diferentes proveedores utilizando la combinación de su CLI + código en cualquiera de los siguientes lenguajes:

  • Go
  • .NET Core (C#, VB, F#)
  • Node.js (JavaScript, TypeScript)
  • Python.

Al utilizar lenguajes conocidos por los desarrolladores Pulumi nos evita la curva de aprendizaje de algún otro lenguaje de marcado además de que nos permite trabajar con las herramientas, IDEs y plugins que se utilizan en el día a día durante el desarrolllo de nuestras aplicaciones.

Si bien se reduce la curva de aprendizaje de algún otro lenguaje es necesario dedicar tiempo a aprender los fundamentos y reglas necesarias para crear la infraestructura deseada en cada uno de los proveedores Cloud.

Otras carácteristicas que me parecieron interesantes de Pulumi son las siguientes:

  • Se puede importar infraestructura existente y permitir que Pulumi la administre y a diferencia de Terraform el proceso si te arroja código de los recursos que se importaron para copiar y pegar.
  • Se puede importar a partir de archivos de Terraform, aunque en mi experiencia algunas funcionalidades no son soportadas aún.
  • Según la documentación se puede referenciar información a partir del archivo state de Terraform.
  • Nos permite manejar diferentes configuraciones para cada 'stacks' además de que dichas configuraciones pueden ser accesibles desde el código.

Algunas áreas de oportunidad que noté:

  • La documentación puede no llegar a tener el mismo nivel de detalle en diferentes lenguajes, sobre todo en los ejemplos.

Nuestro primer script con Pulumi

En esta ocasión crearemos un servicio OpenSearch de AWS para entender mejor como funciona Pulumi.

Para poder trabajar con Pulumi es necesario instalar el CLI siguiendo las instrucciones descritas en su documentación, posteriormente se puede validar la instalación ejecutando el siguiente comando:

pulumi version

También para trabajar con AWS es necesario configurar Pulumi para acceder a la cuenta de AWS y tener instalado y configurado el CLI de AWS para cumplir con este punto puedes seguir la guía de Pulumi.

Para este ejemplo agregaremos las variables de entorno:

export AWS_ACCESS_KEY_ID=<YOUR_ACCESS_KEY_ID>
export AWS_SECRET_ACCESS_KEY=<YOUR_SECRET_ACCESS_KEY>

Después de haber instalado el CLI es necesario realizar el proceso de login, por default el CLI nos pedirá un token para conectarnos a sus servicios, pero para efectos de este ejemplo utilizaremos la opción --local que nos permitirá trabajar en nuestro entorno local y almacenará el estado de nuestros stacks dentro de la carpeta ~/.pulumi.

pulumi login --local

Ahora podemos crear nuestro primer proyecto utilizando el siguiente comando

 pulumi new go

Pulumi nos ofrece algunas plantillas precargadas, para ver el listado dentro del CLI elimina el parámetro go.

Durante el proceso de creación del proyecto el CLI nos solicitará algunos datos como el nombre del proyecto, stack y una passphrase (es importante que almacenes esta última ya que la necesitarás para posteriores tareas).
Para crear nuestro servicio OpenSearch agregaremos el paquete de pulumi para AWS utilizando la siguiente instrucción

go get github.com/pulumi/pulumi-aws/sdk/v5

A continuación, agregaremos el siguiente código en nuestro archivo main.go el cual nos permitirá crear nuestro servicio OpenSearch, te recomiendo cambiar las configuraciones por algunas de tu preferencia, así como cambiar la contraseña por una segura en lugar de la que tiene como demo.

package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v5/go/aws/opensearch"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := opensearch.NewDomain(ctx, "demosatur", &opensearch.DomainArgs{
			DomainName:    pulumi.String("demosatur"),
			EngineVersion: pulumi.String("OpenSearch_1.2"),
			ClusterConfig: &opensearch.DomainClusterConfigArgs{
				InstanceType:         pulumi.String("t2.micro.search"),
				InstanceCount:        pulumi.Int(3),
				ZoneAwarenessEnabled: pulumi.Bool(true),
				ZoneAwarenessConfig: opensearch.DomainClusterConfigZoneAwarenessConfigArgs{
					AvailabilityZoneCount: pulumi.Int(3),
				},
			},
			Tags: pulumi.StringMap{
				"project_name": pulumi.String("projectdemosatur"),
			},
			EbsOptions: opensearch.DomainEbsOptionsArgs{
				EbsEnabled: pulumi.Bool(true),
				VolumeSize: pulumi.Int(10),
			},
			DomainEndpointOptions: opensearch.DomainDomainEndpointOptionsArgs{
				EnforceHttps:      pulumi.Bool(true),
				TlsSecurityPolicy: pulumi.StringPtr("Policy-Min-TLS-1-2-2019-07"),
			},
			NodeToNodeEncryption: opensearch.DomainNodeToNodeEncryptionArgs{
				Enabled: pulumi.Bool(true),
			},
			EncryptAtRest: opensearch.DomainEncryptAtRestArgs{
				Enabled: pulumi.Bool(true),
			},
			AdvancedSecurityOptions: opensearch.DomainAdvancedSecurityOptionsArgs{
				Enabled:                     pulumi.Bool(true),
				InternalUserDatabaseEnabled: pulumi.Bool(true),
				MasterUserOptions: opensearch.DomainAdvancedSecurityOptionsMasterUserOptionsArgs{
					MasterUserName:     pulumi.String("test_user"),
					MasterUserPassword: pulumi.String("#AStrongPassword#"),
				},
			},
			AutoTuneOptions: opensearch.DomainAutoTuneOptionsArgs{
				DesiredState:      pulumi.String("DISABLED"),
				RollbackOnDisable: pulumi.String("NO_ROLLBACK"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}

Ahora que tenemos el código podemos crear la infraestructura en AWS utilizando el siguiente comando:

Antes de ejecutar el comando toma en cuenta que se pueden incurrir en gastos, así que toma tus precauciones :).

pulumi up

Después de unos minutos Pulumi nos indicará si el proceso ha resultado exitoso y podremos validar por medio de la consola de AWS.

En caso de necesitar agregar policies, que el acceso al servicio OpenSearch este limitado a una VPN o alguna otra configuración propia del servicio puedes revisar la documentación de Pulumi y por supuesto la del servicio.

Cómo podrás notar Pulumi es una herramienta que te resultará bastante familiar si tu perfil es orientado al desarrollo, es open-source y nos permite reducir el tiempo de aprendizaje al momento de adoptar las prácticas de IaC.

Me despido esperando te resulte de utilidad este post.
¡Happy coding! @saturpimentel