DEV Community

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

Posted on

2 1 1

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

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay