Cómo desplegar NGINX en un Droplet de DigitalOcean usando Pulumi
Pulumi es una herramienta para la declaración de infraestructura como código pero con foco en el uso de lenguajes de programación reales. ¿Querés saber cómo funciona? Seguí leyendo...
La semana pasada mostraba cómo armar una ambiente totalmente funcional de Droplets, Configuración DNS, Implementación de Traefik con Docker usando Terraform. Hoy, te voy a mostrar como hacer algo parecido con Pulumi, una herramienta que buscar más o menos lo mismo que la mencionada anteriormente pero que hace foco en el hecho de que tanto desarrolladores como operadores (SysAdmin, DevOps Engineers, etc) puedan usarlo y entenderlo.
Además que tiene unas cosas interesantes como un backend en la nube que nos permite guardar nuestros "secretos" entre otras cosas que con más en detalle veremos en otro post.
Lo que hoy te quiero mostrar es cómo desplegar un Droplet (Maquina virtual) que corra NGINX en DigitalOcean.
Para arrancar, primero tenemos que elegir el lenguaje que vamos a usar para armar nuestros archivos. Pulumi soporta TypeScript, Python, JavaScript y versiones Preview de Go y C#.
Manos a la obra
Si no tenés instalado Pulumi, podés usar Brew para hacerlo, en mi caso, solo basto con ejecutar:
brew install pulumi
Una vez que está instalado, creemos una carpeta y entremos a ella, ahí es donde vamos a trabajar. La carpeta, para este ejemplo, se llamará "do".
mkdir do && cd do
Luego, vamos a iniciar un nuevo "trabajo" y vamos a especificar el lenguaje que vamos a usar. Para mi caso, elegí TypeScript.
pulumi new typescript
Esto va a lanzar una especie de asistente para crear nuestro stack.
This command will walk you through creating a new Pulumi project.
Enter a value or leave blank to accept the (default), and press <ENTER>.
Press ^C at any time to quit.
project name: <nombre-de-proyecto>
project description: (A minimal TypeScript Pulumi program) <este es un proyecto de prueba>
Created project '<nombre-de-proyecto'
Please enter your desired stack name.
To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`).
stack name: (dev) dev
Created stack 'dev'
Luego de esto, comenzará descargar unos paquetes, se verá algo así:
Installing dependencies...
> deasync@0.1.19 install /Users/nacho/pulumi/do_2/node_modules/deasync
> node ./build.js
`darwin-x64-node-12` exists; testing
Binary is fine; exiting
> grpc@1.24.2 install /Users/nacho/pulumi/do_2/node_modules/grpc
> node-pre-gyp install --fallback-to-build --library=static_library
[grpc] Success: "/Users/nacho/pulumi/do_2/node_modules/grpc/src/node/extension_binary/node-v72-darwin-x64-unknown/grpc_node.node" is installed via remote
> protobufjs@6.8.8 postinstall /Users/nacho/pulumi/do_2/node_modules/protobufjs
> node scripts/postinstall
added 178 packages from 208 contributors and audited 282 packages in 13.459s
found 0 vulnerabilities
Finished installing dependencies
Your new project is ready to go! ✨
To perform an initial deployment, run 'pulumi up'
Luego, descargaremos el provider de DigitalOcean para Pulumi.
npm install @pulumi/digitalocean
Esto, nos devolverá algo como esto:
> @pulumi/digitalocean@1.4.0 install /Users/nacho/pulumi/do_2/node_modules/@pulumi/digitalocean
> node scripts/install-pulumi-plugin.js resource digitalocean v1.4.0
[resource plugin digitalocean-1.4.0] installing
npm WARN typescript@ No description
npm WARN typescript@ No repository field.
npm WARN typescript@ No license field.
+ @pulumi/digitalocean@1.4.0
added 2 packages from 1 contributor and audited 642 packages in 4.076s
found 0 vulnerabilities
╭────────────────────────────────────────────────────────────────╮
│ │
│ New minor version of npm available! 6.9.0 → 6.13.6 │
│ Changelog: https://github.com/npm/cli/releases/tag/v6.13.6 │
│ Run npm install -g npm to update! │
│ │
╰────────────────────────────────────────────────────────────────╯
Terminado esto, vamos a configurar nuestro token, para eso, si aún no tenés tu token de acceso a DigitalOcean, lo podés generar desde este apartado de tu panel de control. Una vez que lo tengamos, ejecutamos lo siguiente:
pulumi config set digitalocean:token <tu-token> --secret
Esto lo que va a hacer es guardar este "secreto" en el backend de Pulumi que está en la web y que te podés registrar de manera gratuita. (En otro artículo hablaré de profundidad de este backend)
Ya con esto configurado, vamos a ver que en la carpeta "do" tenemos varios archivos, el que nos interesa a nosotros para este tutorial es es: index.ts, que lo vamos a modificar para que quede de esta manera:
import * as pulumi from "@pulumi/pulumi";
import * as digitalocean from "@pulumi/digitalocean";
const dropletCount = 1;
const region = digitalocean.Regions.NYC3;
const dropletTypeTag = new digitalocean.Tag("mi-app");
const userData =
`#!/bin/bash
sudo apt-get update
sudo apt-get install -y nginx`;
const droplets = [];
for (let i = 0; i < dropletCount; i++) {
let nameTag = new digitalocean.Tag(`web-${i}`);
droplets.push(new digitalocean.Droplet(`web-${i}`, {
image: "ubuntu-18-04-x64",
region: region,
privateNetworking: true,
size: digitalocean.DropletSlugs.Droplet512mb,
tags: [nameTag.id, dropletTypeTag.id],
userData: userData,
}));
}
Vamos a desmenuzar un poco esto:
Lo primero que tenemos es la especificación del proveedor que usaremos y luego, la cantidad de Droplets y la región donde estará alojado. En este caso es 1 y NYC 3.
const dropletCount = 1;
const region = digitalocean.Regions.NYC3;
Lo siguiente que haremos es darle una etiqueta y ya pasarle comandos para cuando el Droplet esté listo. Para este caso se llamará "mi-app" y los comandos son la actualización de los repositorios y la instalación de NGINX.
const dropletTypeTag = new digitalocean.Tag("mi-app");
const userData =
`#!/bin/bash
sudo apt-get update
sudo apt-get install -y nginx`;
Por último vemos configuración referida al nombre y lo más importante que es el tamaño del Droplet y qué imagen usará:
const droplets = [];
for (let i = 0; i < dropletCount; i++) {
let nameTag = new digitalocean.Tag(`web-${i}`);
droplets.push(new digitalocean.Droplet(`web-${i}`, {
image: "ubuntu-18-04-x64",
region: region,
privateNetworking: true,
size: digitalocean.DropletSlugs.Droplet512mb,
tags: [nameTag.id, dropletTypeTag.id],
userData: userData,
}));
}
Si todo está listo y configuramos el index.ts como queremos. Guardamos, salimos y ejecutamos:
pulumi up
Nos devolverá algo como esto, que es básicamente el resumen de lo que va a hacer, los recursos que va a crear:
Previewing update (dev):
Type Name Plan
+ pulumi:pulumi:Stack do-dev create
+ ├─ digitalocean:index:Tag mi-app create
+ ├─ digitalocean:index:Tag web-0 create
+ └─ digitalocean:index:Droplet web-0 create
Resources:
+ 4 to create
Do you want to perform this update?
> yes
no
details
Sí estamos de acuerdo, seleccionamos "yes" y lo dejamos que haga su magia.
Al finalizar, veremos algo como esto, en donde nos indica qué recursos se crearon, cuánto tiempo tomó y el enlace al backend donde Pulumi guardó todo.
Updating (dev):
Type Name Status
+ pulumi:pulumi:Stack do-dev created
+ ├─ digitalocean:index:Tag web-0 created
+ ├─ digitalocean:index:Tag mi-app created
+ └─ digitalocean:index:Droplet web-0 created
Resources:
+ 4 created
Duration: 38s
Permalink: https://app.pulumi.com/<tuusuario>/do/dev/updates/3
Para este escenario, no sucede como en Terraform que nos guarda un tfstate, dónde nos devuelve todo lo que hizo con el detalle del direccionamiento IP y demás, así que si o si debemos ir al backend de Pulumi y sacar los datos de ahí. En otro momento, les mostraré como hacerlo todo de manera local.
Por último, revisamos que ese NGINX este corriendo, así que basta con que vayamos a la IP que nos dió para este Droplet DigitalOcean para que nos aparezca la página de bienvenida del WebServer.
Así que listo, de esta manera, ejecutamos nuestra primera carga de trabajo usando Pulumi en DigitalOcean. Para destruirlo en el caso de que querramos, como también es mi caso, basta con ejecutar lo siguiente:
pulumi destroy
Nos devolverá algo como esto
Previewing destroy (dev):
Type Name Plan
- pulumi:pulumi:Stack do-dev delete
- ├─ digitalocean:index:Droplet web-0 delete
- ├─ digitalocean:index:Tag web-0 delete
- └─ digitalocean:index:Tag mi-app delete
Resources:
- 4 to delete
Do you want to perform this destroy?
> yes
no
details
Seleccionamos que "yes" y lo siguiente que veremos es esto:
Destroying (dev):
Type Name Status
- pulumi:pulumi:Stack do-dev deleted
- ├─ digitalocean:index:Droplet mi-app deleted
- ├─ digitalocean:index:Tag demo-app deleted
- └─ digitalocean:index:Tag web-0 deleted
Resources:
- 4 deleted
Duration: 29s
Permalink: https://app.pulumi.com/<tuusuario>/do/dev/updates/4
The resources in the stack have been deleted, but the history and configuration associated with the stack are still maintained.
If you want to remove the stack completely, run 'pulumi stack rm dev'.
Para cerrar
Para ir cerrando, me gustaría animarte a que lo pruebes. Pero no sin antes leer más sobre Pulumi desde esta dirección:
También invitarte a que te registres en DigitalOcean, de esta manera, cuando uses el crédito de regalo, me dará crédito a mi que me viene bien para poder seguir demostrando cosas usando DO.
Por último, te dejo el enlace al proyecto de Gitlab que te permitirá replicar este tutorial:
Si tenés dudas o consultas, no dudes en dejar un comentario acá abajo y lo vamos viendo.
Creditos imágen: Unplash