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"
}
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
Alterando as permissões para que somente o proprietário possa ler o arquivo
chmod 400 mongo-keyfile
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;
}
}
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"
]
}
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"
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:
Top comments (0)