Cómo desplegar InfluxDB v2.0 con Traefik y soporte SSL en DigitalOcean usando Terraform

Si te gusta automatizar como a mi, este artículo te va a gustar. Aprende sobre esta receta para desplegar InfluxDB v2.0 con Traefik, en DigitalOcean usando Terraform.

Hace rato no hacía nada nada como esto, así que la semana pasada me puse a jugar para crear un automatismo en Terraform que permita desplegar InfluxDB v2.0 atrás de Traefik con soporte SSL de Let's Encrypt en DigitalOcean.

El motivo es el inminente lanzamiento de InfluxDB v2.0 OSS y es parte de la contribución que hago hacia la comunidad como parte del programa InfluxAces.

Ignacio Van Droogenbroeck | InfluxAces | InfluxData
InfluxAce Ignacio Van Droogenbroeck is a Technical Marketing Engineer at Portainer, with years of experience working with cloud and container technologies.

¿Qué es lo que hace esta receta?

Esta receta de Terraform hace lo siguiente:

  • Inicializa el proveedor de DigitalOcean
  • Lleva tu llave SSH hacia DigitalOcean
  • Crea un dominio .com y un subdominio llamado influx.tudominio.com
  • Crea la máquina virtual y luego asocia el subdominio a ese droplet.
  • Crea archivos y carpetas necesarias para luego poder montar los volúmenes en los contenedores.
  • Instala Docker y Docker Compose.
  • Despliega los contenedores de InfluxDB y Traefik.
  • Se crea el certificado SSL con Let's Encrypt para que el acceso y la inyección de data hacia InfluxDB se haga por SSL.

Esta receta la pueden encontrar aquí, con bastante explicación (En inglés).

xe-nvdk/terraform-recipes
This is the repo where I save #Terraform recipes, mostly posted in cduser.com - xe-nvdk/terraform-recipes

Cómo desplegar esta receta

Antes de comenzar a configurar y a desplegar, debemos descargar la receta y hacer la modificación a los archivos dependiendo de nuestras necesidades.

Lo primero que vamos a hacer es hacer un git clone de esta receta:

$ git clone https://github.com/xe-nvdk/terraform-recipes.git

Eso va a bajar todo el repositorio, así que navegamos hasta la carpeta llamada "influxdbv2.0-traefik-do"

$ cd influxdbv2.0-traefik-do

Ahí adentro vamos a encontrar estos archivos:

drwxrwxrwx 1 nacho nacho 4096 Sep 17 12:12 ./
drwxrwxrwx 1 nacho nacho 4096 Sep 17 11:11 ../
-rwxrwxrwx 1 nacho nacho  107 Sep 17 11:11 auth.tf*
-rwxrwxrwx 1 nacho nacho  282 Sep 17 11:11 copy.tf*
-rwxrwxrwx 1 nacho nacho  295 Sep 17 11:11 dns.tf*
-rwxrwxrwx 1 nacho nacho 1540 Sep 17 11:11 docker-compose.yml*
-rwxrwxrwx 1 nacho nacho  267 Sep 17 11:11 droplet.tf*
-rwxrwxrwx 1 nacho nacho  756 Sep 17 11:11 id_rsa.pub*
-rwxrwxrwx 1 nacho nacho  532 Sep 17 11:11 readme.md*
-rwxrwxrwx 1 nacho nacho  150 Sep 17 11:11 ssh.tf*
-rwxrwxrwx 1 nacho nacho  195 Sep 17 11:11 userdata.yaml*

Veamos cuales archivos debemos modificar:

El archivo auth.tf y el copy.tf no deberíamos tocarlo. El que si debemos modificar es el dns.tf, ahí debemos especificar nuestro dominio y el subdominio que vamos a crear.

resource "digitalocean_domain" "cduser" {
  name = "cduser.com"
}

# create subdomain for influxdb
resource "digitalocean_record" "influx" {
  domain = "digitalocean_domain.cduser.name"
  type   = "A"
  name   = "influx"
  ttl    = "35"
  value  = "digitalocean_droplet.influxdb.ipv4_address"
}

En este ejemplo 👆 vemos que el dominio que estoy especificando es cduser.com y luego poquito más abajo específico que el subdominio se va a llamar influx, con lo que quedaría influx.cduser.com.

Lo siguiente a modificar el docker-compose.yml que la receta copiará al droplet para desplegar los contenedores:

version: "3.3"

services:
  traefik:
    container_name: traefik
    image: "traefik:latest"
    command:
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --providers.docker
      - --api
      - --certificatesresolvers.leresolver.acme.httpchallenge=true
      - --certificatesresolvers.leresolver.acme.email=<tu-email>
      - --certificatesresolvers.leresolver.acme.storage=/acme.json
      - --certificatesresolvers.leresolver.acme.httpchallenge.entrypoint=web
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./acme.json:/acme.json"
    labels:
      # global redirect to https
      - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
      - "traefik.http.routers.http-catchall.entrypoints=web"
      - "traefik.http.routers.http-catchall.middlewares=redirect-to-https"

      # middleware redirect
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"

  influxdbv2:
    container_name: influxdb
    image: quay.io/influxdb/influxdb:2.0.0-beta
    volumes:
      - /influxdb:/root/.influxdbv2/
    labels:
      - "traefik.http.routers.influx.rule=Host(`influx.cduser.com`)"
      - "traefik.http.routers.influx.entrypoints=websecure"
      - "traefik.http.routers.influx.tls=true"
      - "traefik.http.routers.influx.tls.certresolver=leresolver"
      - "traefik.http.services.influx.loadbalancer.server.port=9999"
      - "traefik.http.routers.influx.service=influx"

Acá 👆, lo que deberías modificar sería la siguiente línea, poniendo tu dirección de email. Esto es para el registro de Let's Encrypt.

      - --certificatesresolvers.leresolver.acme.email=<tu-email>

Lo siguiente es esta línea, que iría con tu dominio y el subdominio que hayas elegido en el dns.tf

      - "traefik.http.routers.influx.rule=Host(`influx.cduser.com`)"

El siguiente archivo para modificar, aunque es totalmente opcional, es el droplet.tf, este archivo, tiene información sobre el nombre del droplet que se va a crear y el tamaño del mismo. Esto puede cambiarse pero para este proyecto podemos dejarlo tal como está.

El siguiente archivo para modificar, también de forma opcional es el ssh.tf. Esto lo que va a hacer es llevar un archivo id_rsa.pub (tu llave publica). Lo único a tener en cuenta aquí es el path donde está esa llave para poder subirla.

El archivo userdata.yml contiene la instrucciones de que es lo que va a hacer apenas el droplet esté creado. Si haces un cambio aquí, sobre todo en la parte de generación de archivos, asegurate que estén reflejados en el docker-compose.yml de más arriba.

Una vez que tenemos todo pronto, pasamos el token de autenticación como variable. Pueden consultar este pique sobre cómo tener una y pasarla como variable de autenticación para luego usarla con Terraform.

Pique #5: Cómo usar un token de autenticación de DigitalOcean en Terraform
Para lanzar trabajos de Terraform contra DigitalOcean, hay que usar un Token deautenticación y para que no lo pida al realizar cada acción, hay que pasarle unavariable de entorno a nuestra terminal. Para obtener nuestro Token de acceso, debemos ir a este enlace y generarlo[https://cloud.digitalocean.com/account/api/tokens…

Una vez que pasamos esta variable ejecutamos...

$ terraform init

El resultado debería ser algo como esto:

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/null...
- Finding latest version of digitalocean/digitalocean...
- Installing hashicorp/null v2.1.2...
- Installed hashicorp/null v2.1.2 (signed by HashiCorp)
- Installing digitalocean/digitalocean v1.22.2...
- Installed digitalocean/digitalocean v1.22.2 (signed by a HashiCorp partner, key ID F82037E524B9C0E8)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/plugins/signing.html

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, we recommend adding version constraints in a required_providers block
in your configuration, with the constraint strings suggested below.

* digitalocean/digitalocean: version = "~> 1.22.2"
* hashicorp/null: version = "~> 2.1.2"

Terraform has been successfully initialized!

Luego, ejecutamos el plan.

$ terraform plan

En el siguiente resultado, nos aseguramos de que lo que va a hacer es lo que queramos que haga:

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # digitalocean_domain.cduser will be created
  + resource "digitalocean_domain" "cduser" {
      + id   = (known after apply)
      + name = "cduser.com"
      + urn  = (known after apply)
    }

  # digitalocean_droplet.influxdb will be created
  + resource "digitalocean_droplet" "influxdb" {
      + backups              = false
      + created_at           = (known after apply)
      + disk                 = (known after apply)
      + id                   = (known after apply)
      + image                = "ubuntu-20-04-x64"
      + ipv4_address         = (known after apply)
      + ipv4_address_private = (known after apply)
      + ipv6                 = false
      + ipv6_address         = (known after apply)
      + ipv6_address_private = (known after apply)
      + locked               = (known after apply)
      + memory               = (known after apply)
      + monitoring           = false
      + name                 = "influxdb"
      + price_hourly         = (known after apply)
      + price_monthly        = (known after apply)
      + private_networking   = (known after apply)
      + region               = "nyc1"
      + resize_disk          = true
      + size                 = "s-1vcpu-1gb"
      + ssh_keys             = (known after apply)
      + status               = (known after apply)
      + urn                  = (known after apply)
      + user_data            = "8e8667350e70e051949e95c4ca5f40e09870abf7"
      + vcpus                = (known after apply)
      + volume_ids           = (known after apply)
      + vpc_uuid             = (known after apply)
    }

  # digitalocean_record.influx will be created
  + resource "digitalocean_record" "influx" {
      + domain = "digitalocean_domain.cduser.name"
      + fqdn   = (known after apply)
      + id     = (known after apply)
      + name   = "influx"
      + ttl    = 35
      + type   = "A"
      + value  = "digitalocean_droplet.influxdb.ipv4_address"
    }

  # digitalocean_ssh_key.influx will be created
  + resource "digitalocean_ssh_key" "influx" {
      + fingerprint = (known after apply)
      + id          = (known after apply)
      + name        = "influx"
      + public_key  = "id_rsa.pub"
    }

  # null_resource.copy-docker-compose will be created
  + resource "null_resource" "copy-docker-compose" {
      + id = (known after apply)
    }

Plan: 5 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Si todo está bien, ejecutamos...

$ terraform apply

Aparecerá un output como el del terraform plan, la diferencia es que solo tipeamos "yes".

Después de confirmar, veremos algo como esto (Reduje el output para no hacerlo tan largo):

digitalocean_ssh_key.influx: Creating...
digitalocean_ssh_key.influx: Creation complete after 3s [id=28453867]
digitalocean_droplet.influxdb: Creating...
digitalocean_droplet.influxdb: Still creating... [10s elapsed]
digitalocean_droplet.influxdb: Still creating... [20s elapsed]
digitalocean_droplet.influxdb: Creation complete after 24s [id=208013743]
null_resource.copy-test-file: Creating...
null_resource.copy-test-file: Provisioning with 'file'...
null_resource.copy-test-file: Still creating... [10s elapsed]
null_resource.copy-test-file: Creation complete after 20s [id=8765686804275944894]
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Después de unos minutos (de 2 a 3 minutos) podremos apuntar nuestro navegador al subdominio y deberíamos ver el setup de InfluxDB. Ten en cuenta que tal vez aún no esté el certificado SSL pero eso es cuestión de apenas unos minutos más.

Si todo salió bien, deberíamos ver la página de bienvenida de InfluxDB.

Para ir cerrando

Automatizar es una de las cosas que más me gusta hacer y sobre todo hacerlo combinando varias tecnologías y proveedores como es este caso, si ves, combine no solo software, sino también servicios.

Algo importante, al momento de escribir este artículo, InfluxDB v2.0 no esta listo para producción, lo que se despliega con esta receta es la Beta 16. Para cuando salga 2.0, seguramente actualizaré esta receta para que soporte esa versión y ver si puedo agregarle el setup de InfluxDB para que simplemente, después de ejecutar estemos listos para loguearnos.

Espero les haya gustado, ojala lo prueben y me cuenten qué les pareció.