DEV Community

Cover image for Explorando um Cluster MongoDB com Terraform
Lucas Aguiar
Lucas Aguiar

Posted on

Explorando um Cluster MongoDB com Terraform

A pouco tempo após algumas conversas me interessei por aprender mais sobre terraform e como provisionar infraestrutura de maneira mais fácil, simples de replicar em outros lugares e manter a longo prazo.

A ideia aqui é demonstrar como a abordagem de Infrastructure as Code pode simplificar a criação de um cluster MongoDB, composto por um nó primário e dois nós secundários. Utilizando o Terraform e o Docker como provedor para teste local.

O passo a passo

1. Preparando o ambiente

Primeiro, vamos definir o docker como provedor e uma rede para que os containers se comuniquem usando a resolução de DNS interno, podendo usar "mongo_primary", "mongo_secondary_1" e "mongo_secondary_2" apontando para os ips internos corretos.

terraform {
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "~> 3.0.2"
    }
  }
}

provider "docker" {}

resource "docker_network" "mongo_network" {
  name = "mongo_network"
}
Enter fullscreen mode Exit fullscreen mode

2. Gerando os arquivos internos de autenticação

Antes de subir os containers, é necessário gerar um arquivo keyfile que será utilizado para a autenticação interna entre os nós do replica set do MongoDB. Esse arquivo garante que somente os nós autorizados possam se comunicar.

openssl rand -base64 756 > mongo-keyfile
Enter fullscreen mode Exit fullscreen mode

Alterando as permissões para que somente o proprietário possa ler o arquivo

chmod 400 mongo-keyfile
Enter fullscreen mode Exit fullscreen mode

Certifique-se de que o arquivo mongo-keyfile esteja na mesma pasta onde se encontra o arquivo main.tf ( ou em uma pasta no mesmo nível ), pois ele será referenciado nos volumes dos containers.

3. Configurando o replicaset

Separamos aqui os containers em duas partes 1 nó primário e 2 secundários, em um cluster replica set de mongodb o nó primário é responsável por aceitar operações de escrita e propagar as alterações para os secundários, que mantêm uma cópia dos dados e podem ser utilizados para balanceamento de carga em leituras.

// init-replica.js

conn = new Mongo("mongodb://admin:adminpass@localhost:27017");
db = conn.getDB("admin");

try {
    let status = rs.status();
    print("ℹ️ Replica Set já configurado.");
} catch (err) {
    if (err.codeName === "NotYetInitialized") {
        print("🚀 Iniciando Replica Set...");
        rs.initiate({
            _id: "rs0",
            members: [
                { _id: 0, host: "mongo_primary:27017" },
                { _id: 1, host: "mongo_secondary_1:27017" },
                { _id: 2, host: "mongo_secondary_2:27017" }
            ]
        });
        print("✅ Replica Set inicializado com sucesso!");
    } else {
        print("❌ Erro ao verificar status do Replica Set:", err);
        throw err;
    }
}
Enter fullscreen mode Exit fullscreen mode

4. Subindo os containers mongodb

No terraform a configuração dos containers mongodb é similar, entretanto, só o nó primário recebe instruções de exposição das portas e o script de configuração do cluster.

Montamos os dois volumes referente ao keyfile de autenticação e o script de configuração de replica em js.

resource "docker_container" "mongo_primary" {
  name    = "mongo_primary"
  image   = "mongo:7.0"
  restart = "always"

  networks_advanced {
    name = docker_network.mongo_network.name
  }

  ports {
    internal = 27017
    external = 27017
  }

  volumes {
    host_path      = "${abspath(path.module)}/mongo-keyfile"
    container_path = "/data/keyfile"
  }

  volumes {
    host_path      = "${abspath(path.module)}/init-replica.js"
    container_path = "/docker-entrypoint-initdb.d/init-replica.js"
  }

  env = [
    "MONGO_INITDB_ROOT_USERNAME=admin",
    "MONGO_INITDB_ROOT_PASSWORD=adminpass",
    "MONGO_REPLICA_SET_NAME=rs0"
  ]

  command = [
    "mongod",
    "--replSet", "rs0",
    "--keyFile", "/data/keyfile",
    "--bind_ip_all"
  ]

  provisioner "local-exec" {
    command = "sleep 10 && docker exec mongo_primary mongosh /docker-entrypoint-initdb.d/init-replica.js"
  }
}

resource "docker_container" "mongo_secondary_1" {
  name  = "mongo_secondary_1"
  image = "mongo:7.0"
  restart = "always"

  networks_advanced {
    name = docker_network.mongo_network.name
  }

  volumes {
    host_path      = "${abspath(path.module)}/mongo-keyfile"
    container_path = "/data/keyfile"
  }

  env = [
    "MONGO_INITDB_ROOT_USERNAME=admin",
    "MONGO_INITDB_ROOT_PASSWORD=adminpass",
    "MONGO_REPLICA_SET_NAME=rs0"
  ]

  command = [
    "mongod",
    "--replSet", "rs0",
    "--keyFile", "/data/keyfile",
    "--bind_ip_all"
  ]
}

resource "docker_container" "mongo_secondary_2" {
  name  = "mongo_secondary_2"
  image = "mongo:7.0"
  restart = "always"

  networks_advanced {
    name = docker_network.mongo_network.name
  }

  volumes {
    host_path      = "${abspath(path.module)}/mongo-keyfile"
    container_path = "/data/keyfile"
  }

  env = [
    "MONGO_INITDB_ROOT_USERNAME=admin",
    "MONGO_INITDB_ROOT_PASSWORD=adminpass",
    "MONGO_REPLICA_SET_NAME=rs0"
  ]

  command = [
    "mongod",
    "--replSet", "rs0",
    "--keyFile", "/data/keyfile",
    "--bind_ip_all"
  ]
}
Enter fullscreen mode Exit fullscreen mode

5. Integração com aplicações

Uma vez com o cluster configurado, é possível se conectar a ele através do comando:

docker exec -it mongo_primary mongosh "mongodb://admin:adminpass@localhost:27017/?replicaSet=rs0"
Enter fullscreen mode Exit fullscreen mode

Para que uma aplicação tenha acesso ao cluster, é necessário que ela esteja junto a "mongo_network" para que não haja problemas na resolução de DNS.

Conclusão

Este exemplo demonstra como o terraform pode ser uma ferramenta poderosa para criar ambientes consistentes e fáceis de serem replicados, lembrando que o exemplo anterior não é recomendado para uso em produção pois cada nó deve estar em uma máquina separada para garantir alta disponibilidade.

Caso tenha ficado algo confuso, você pode acompanhar meu código no Github:

https://github.com/lusqua/terraform-mongodb-cluster

Top comments (0)