Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Learn why MongoDB was selected as a leader in the 2024 Gartner® Magic Quadrant™
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
MongoDBchevron-right

Desenvolvimento local com MongoDB Atlas CLI e Docker

Nic Raboy9 min read • Published Feb 03, 2023 • Updated Feb 06, 2023
DockerNode.jsMongoDBCLIBashJavaScript
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Precisa de uma experiência consistente de desenvolvimento e implantação, pois os desenvolvedores trabalham em equipes e usam máquinas diferentes para suas tarefas diárias? É aqui que o Docker te salva com os contêineres. Uma experiência comum pode incluir executar uma versão local do MongoDB Community em um contêiner e um aplicativo em outro contêiner. Essa estratégia funciona para algumas organizações, mas e se você quiser aproveitar todos os benefícios que vêm com o MongoDB Atlas, além de uma estratégia de contêiner para o desenvolvimento de seu aplicativo?
Neste tutorial, veremos como criar um aplicativo da Web compatível com o MongoDB, agrupá-lo em um contêiner com o Docker e gerenciar a criação e a destruição do MongoDB Atlas com o Atlas CLI durante a implantação do contêiner.
Deve-se observar que este tutorial foi criado para uma configuração de desenvolvimento ou teste em seu computador local. Não é aconselhável usar todas as técnicas encontradas neste tutorial em uma configuração de produção. Avalie cuidadosamente quando se trata do código incluído.
Se quiser testar os resultados deste tutorial, confira o repositório e as instruções no GitHub.

Os pré-requisitos

Há muitas partes dinâmicas neste tutorial, portanto, você precisará de algumas coisas antes para ser bem-sucedido:
O Atlas CLI pode criar uma conta Atlas para você junto com quaisquer chaves e IDs, mas para o escopo deste tutorial, você precisará de uma criada junto com acesso rápido à "Chave de API pública", "Chave de API privada", "Organização ID" e "ID do projeto" na sua conta. Você pode ver como fazer isso na documentação.
O Docker será o grande foco deste tutorial. Você não precisa de nada além do Docker aplicativo Node.js e a Atlas CLI serão gerenciados pelo contêiner Docker, não pelo seu computador host.
Em seu computador host, crie um diretório de projeto. O nome não é importante, mas, para este tutorial, usaremos mongodbexample como diretório de projeto.

Crie um aplicativo Node.js simples com o Express Framework e o MongoDB

Vamos começar criando um aplicativo Node.js que se comunica com o MongoDB usando o driver Node.js para MongoDB. O aplicativo será simples em termos de funcionalidade. Ele se conectará ao MongoDB, criará um banco de dados e uma coleção, inserirá um documento e exibirá um endpoint da API para mostrar o documento com uma solicitação HTTP.
No diretório do projeto, crie um novo diretório de aplicativo para o aplicativo Node.js funcionar. No diretório do aplicativo, usando uma linha de comando, execute o seguinte:
1npm init -y
2npm install express mongodb
Se você não tiver o Node.js instalado, basta criar um arquivo package.json dentro do diretório app com o seguinte conteúdo:
1{
2 "name": "mongodbexample",
3 "version": "1.0.0",
4 "description": "",
5 "main": "main.js",
6 "scripts": {
7 "test": "echo \"Error: no test specified\" && exit 1",
8 "start": "node main.js"
9 },
10 "keywords": [],
11 "author": "",
12 "license": "ISC",
13 "dependencies": {
14 "express": "^4.18.2",
15 "mongodb": "^4.12.1"
16 }
17}
Em seguida, precisaremos definir a lógica do nosso aplicativo. Dentro do diretório app, precisamos criar um arquivo main.js. Dentro do main.js, adicione o seguinte código JavaScript:
1const { MongoClient } = require("mongodb");
2const Express = require("express");
3
4const app = Express();
5
6const mongoClient = new MongoClient(process.env.MONGODB_ATLAS_URI);
7let database, collection;
8
9app.get("/data", async (request, response) => {
10 try {
11 const results = await collection.find({}).limit(5).toArray();
12 response.send(results);
13 } catch (error) {
14 response.status(500).send({ "message": error.message });
15 }
16});
17
18const server = app.listen(3000, async () => {
19 try {
20 await mongoClient.connect();
21 database = mongoClient.db(process.env.MONGODB_DATABASE);
22 collection = database.collection(`${process.env.MONGODB_COLLECTION}`);
23 collection.insertOne({ "firstname": "Nic", "lastname": "Raboy" });
24 console.log("Listening at :3000");
25 } catch (error) {
26 console.error(error);
27 }
28});
29
30process.on("SIGTERM", async () => {
31 if(process.env.CLEANUP_ONDESTROY == "true") {
32 await database.dropDatabase();
33 }
34 mongoClient.close();
35 server.close(() => {
36 console.log("NODE APPLICATION TERMINATED!");
37 });
38});
Há muita coisa acontecendo nas poucas linhas de código acima. Vamos detalhá-lo!
Antes de detalharmos as partes, anote as variáveis de ambiente usadas em todo o código JavaScript. No final, passaremos esses valores pelo Docker para que tenhamos uma experiência mais dinâmica com o nosso desenvolvimento local.
O primeiro trecho importante de código a ser enfocado é o início do nosso serviço de aplicativo:
1const server = app.listen(3000, async () => {
2 try {
3 await mongoClient.connect();
4 database = mongoClient.db(process.env.MONGODB_DATABASE);
5 collection = database.collection(`${process.env.MONGODB_COLLECTION}`);
6 collection.insertOne({ "firstname": "Nic", "lastname": "Raboy" });
7 console.log("Listening at :3000");
8 } catch (error) {
9 console.error(error);
10 }
11});
Usando o cliente que foi configurado perto da parte superior do arquivo, podemos nos conectar ao MongoDB. Uma vez conectados, podemos obter uma referência a um banco de dados e coleção. Esse banco de dados e coleção não precisa existir antes disso, pois ele será criado automaticamente quando os dados forem inseridos. Com referência a uma coleção, inserimos um documento e começamos a ouvir solicitações de API por meio de HTTP.
Isso nos leva ao nosso único endpoint:
1app.get("/data", async (request, response) => {
2 try {
3 const results = await collection.find({}).limit(5).toArray();
4 response.send(results);
5 } catch (error) {
6 response.status(500).send({ "message": error.message });
7 }
8});
Quando o endpoint /data é consumido, os cinco primeiros documento de nossa coleção são retornados ao usuário. Caso contrário, se houver algum problema, uma mensagem de erro será retornada.
Isso nos leva a algo opcional, mas potencialmente valioso quando se trata de uma implantação do Docker para desenvolvimento local:
1process.on("SIGTERM", async () => {
2 if(process.env.CLEANUP_ONDESTROY == "true") {
3 await database.dropDatabase();
4 }
5 mongoClient.close();
6 server.close(() => {
7 console.log("NODE APPLICATION TERMINATED!");
8 });
9});
O código acima diz que, quando um evento de encerramento for enviado para o aplicativo, descarte o banco de dados que criamos e feche a conexão com o MongoDB, bem como com o serviço Express Framework. Isso pode ser útil se quisermos desfazer tudo o que criamos quando o contêiner parar. Se você deseja que suas alterações persistam, talvez não seja necessário. Por exemplo, se você quiser que seus dados existam entre as implantações de contêineres, a persistência será necessária. Por outro lado, talvez você esteja usando o contêiner como parte de um pipeline de teste e queira limpá-lo quando terminar, os comandos de encerramento podem ser valiosos.
Portanto, temos um aplicativo Node.js com muitas variáveis de ambiente. O que vem a seguir?

Implantação de um MongoDB Atlas cluster com regras de rede, funções de usuário e dados de amostra

Embora tenhamos o aplicativo, nosso cluster do MongoDB Atlas pode não estar disponível para nós. Por exemplo, talvez esta seja a primeira vez que somos expostos ao Atlas e nada foi criado ainda. Precisamos ser capazes de criar um cluster de forma rápida e fácil, configurar nossas regras de acesso IP, especificar usuários e permissões e, em seguida, conectar-se ao nosso aplicativo Node.js.
É aqui que o CLI do MongoDB Atlas faz o trabalho pesado!
Há muitas maneiras diferentes de criar um script. Alguns curtem o Bash, outros curtem o ZSH ou outra coisa. Vamos usar o ZX, que é um wrapper JavaScript para o Bash.
No diretório do projeto, e não no diretório do aplicativo, crie um arquivo docker_run_script.mjs com o seguinte código:
1#!/usr/bin/env zx
2
3$.verbose = true;
4
5const runtimeTimestamp = Date.now();
6
7process.env.MONGODB_CLUSTER_NAME = process.env.MONGODB_CLUSTER_NAME || "examples";
8process.env.MONGODB_USERNAME = process.env.MONGODB_USERNAME || "demo";
9process.env.MONGODB_PASSWORD = process.env.MONGODB_PASSWORD || "password1234";
10process.env.MONGODB_DATABASE = process.env.MONGODB_DATABASE || "business_" + runtimeTimestamp;
11process.env.MONGODB_COLLECTION = process.env.MONGODB_COLLECTION || "people_" + runtimeTimestamp;
12process.env.CLEANUP_ONDESTROY = process.env.CLEANUP_ONDESTROY || false;
13
14var app;
15
16process.on("SIGTERM", () => {
17 app.kill("SIGTERM");
18});
19
20try {
21 let createClusterResult = await $`atlas clusters create ${process.env.MONGODB_CLUSTER_NAME} --tier M0 --provider AWS --region US_EAST_1 --output json`;
22 await $`atlas clusters watch ${process.env.MONGODB_CLUSTER_NAME}`
23 let loadSampleDataResult = await $`atlas clusters loadSampleData ${process.env.MONGODB_CLUSTER_NAME} --output json`;
24} catch (error) {
25 console.log(error.stdout);
26}
27
28try {
29 let createAccessListResult = await $`atlas accessLists create --currentIp --output json`;
30 let createDatabaseUserResult = await $`atlas dbusers create --role readWriteAnyDatabase,dbAdminAnyDatabase --username ${process.env.MONGODB_USERNAME} --password ${process.env.MONGODB_PASSWORD} --output json`;
31 await $`sleep 10`
32} catch (error) {
33 console.log(error.stdout);
34}
35
36try {
37 let connectionString = await $`atlas clusters connectionStrings describe ${process.env.MONGODB_CLUSTER_NAME} --output json`;
38 let parsedConnectionString = new URL(JSON.parse(connectionString.stdout).standardSrv);
39 parsedConnectionString.username = encodeURIComponent(process.env.MONGODB_USERNAME);
40 parsedConnectionString.password = encodeURIComponent(process.env.MONGODB_PASSWORD);
41 parsedConnectionString.search = "retryWrites=true&w=majority";
42 process.env.MONGODB_ATLAS_URI = parsedConnectionString.toString();
43 app = $`node main.js`;
44} catch (error) {
45 console.log(error.stdout);
46}
Mais uma vez, vamos detalhar o que está rolando!
Como no aplicativo Node.js, o script ZX usará muitas variáveis de ambiente. No final, essas variáveis serão passadas com o Docker, mas você pode codificá-las a qualquer momento se quiser testar coisas fora do Docker.
A primeira coisa importante a observar é a padronização das variáveis de ambiente:
1process.env.MONGODB_CLUSTER_NAME = process.env.MONGODB_CLUSTER_NAME || "examples";
2process.env.MONGODB_USERNAME = process.env.MONGODB_USERNAME || "demo";
3process.env.MONGODB_PASSWORD = process.env.MONGODB_PASSWORD || "password1234";
4process.env.MONGODB_DATABASE = process.env.MONGODB_DATABASE || "business_" + runtimeTimestamp;
5process.env.MONGODB_COLLECTION = process.env.MONGODB_COLLECTION || "people_" + runtimeTimestamp;
6process.env.CLEANUP_ONDESTROY = process.env.CLEANUP_ONDESTROY || false;
O snippet acima não é um requisito, mas se você quiser evitar a configuração ou a passagem de variáveis, defini-las como padrão pode ser útil. No exemplo acima, o uso de runtimeTimestamp nos permitirá criar um banco de dados e uma coleção exclusivos, se quisermos. Isso pode ser útil se vários desenvolvedores planejarem usar as mesmas imagens do Docker para implantar contêineres, pois assim cada desenvolvedor estará em uma área de sandbox. Se o desenvolvedor optar por desfazer a implementação, apenas seu banco de dados e coleção exclusivos serão descartados.
Em seguida, temos o seguinte:
1process.on("SIGTERM", () => {
2 app.kill("SIGTERM");
3});
Também temos algo semelhante no aplicativo Node.js. Nós o temos no script porque, no fim, o script controlará o aplicativo. Então, quando nós (ou o Docker) paramos o script, o mesmo evento de parada é passado para o aplicativo. Se não fizéssemos isso, o aplicativo não teria um desligamento normal e a lógica de descarte não seria aplicada.
Agora temos três blocos try/catch, cada um focando em algo específico.
O primeiro bloco é responsável pela criação de um cluster com dados de amostra:
1try {
2 let createClusterResult = await $`atlas clusters create ${process.env.MONGODB_CLUSTER_NAME} --tier M0 --provider AWS --region US_EAST_1 --output json`;
3 await $`atlas clusters watch ${process.env.MONGODB_CLUSTER_NAME}`
4 let loadSampleDataResult = await $`atlas clusters loadSampleData ${process.env.MONGODB_CLUSTER_NAME} --output json`;
5} catch (error) {
6 console.log(error.stdout);
7}
Se o cluster já existir, um erro será detectado. Temos três blocos porque, no nosso cenário, tudo bem se certas partes já existirem.
Em seguida, nos preocupamos com usuários e acesso:
1try {
2 let createAccessListResult = await $`atlas accessLists create --currentIp --output json`;
3 let createDatabaseUserResult = await $`atlas dbusers create --role readWriteAnyDatabase,dbAdminAnyDatabase --username ${process.env.MONGODB_USERNAME} --password ${process.env.MONGODB_PASSWORD} --output json`;
4 await $`sleep 10`
5} catch (error) {
6 console.log(error.stdout);
7}
Queremos que nosso IP local seja adicionado à lista de acesso e que um usuário seja criado. Neste exemplo, estamos criando um usuário com acesso extensivo, mas talvez você queira refinar o nível de permissão que ele tem em seu próprio projeto. Por exemplo, talvez o contêiner seja para uma experiência de sandbox. Nesse cenário, faz sentido que o usuário tenha criado acesso apenas ao banco de dados e à coleção no sandbox. Buscamos sleep esses comandos porque eles não são instantâneos e queremos ter certeza de que tudo está pronto antes de tentarmos nos conectar.
Por fim, tentamos conectar:
1try {
2 let connectionString = await $`atlas clusters connectionStrings describe ${process.env.MONGODB_CLUSTER_NAME} --output json`;
3 let parsedConnectionString = new URL(JSON.parse(connectionString.stdout).standardSrv);
4 parsedConnectionString.username = encodeURIComponent(process.env.MONGODB_USERNAME);
5 parsedConnectionString.password = encodeURIComponent(process.env.MONGODB_PASSWORD);
6 parsedConnectionString.search = "retryWrites=true&w=majority";
7 process.env.MONGODB_ATLAS_URI = parsedConnectionString.toString();
8 app = $`node main.js`;
9} catch (error) {
10 console.log(error.stdout);
11}
Após a conclusão do primeiro bloco try / catch, teremos umastring de conexão. Podemos finalizar nossa string com um objeto de URL Node.js incluindo o nome de usuário e a senha e, em seguida, podemos executar nosso aplicativo Node.js. Lembre-se de que as variáveis de ambiente e todas as manipulações que fizemos nelas em nosso script serão passadas para o aplicativo Node.js.

Transição do fluxo de trabalho do MongoDB Atlas para contêineres com Docker e Docker Compose

Neste momento, temos um aplicativo e um script para preparar o MongoDB Atlas e iniciar o aplicativo. É hora de colocar tudo em uma imagem do Docker para ser implantado como um contêiner.
Na raiz do seu diretório de projeto, adicione um arquivo Dockerfile com o seguinte:
1FROM node:18
2
3WORKDIR /usr/src/app
4
5COPY ./app/* ./
6COPY ./docker_run_script.mjs ./
7
8RUN curl https://fastdl.mongodb.org/mongocli/mongodb-atlas-cli_1.3.0_linux_x86_64.tar.gz --output mongodb-atlas-cli_1.3.0_linux_x86_64.tar.gz
9RUN tar -xvf mongodb-atlas-cli_1.3.0_linux_x86_64.tar.gz && mv mongodb-atlas-cli_1.3.0_linux_x86_64 atlas_cli
10RUN chmod +x atlas_cli/bin/atlas
11RUN mv atlas_cli/bin/atlas /usr/bin/
12
13RUN npm install -g zx
14RUN npm install
15
16EXPOSE 3000
17
18CMD ["./docker_run_script.mjs"]
A imagem personalizada do Docker será baseada em uma imagem Node.js que nos permitirá executar nosso aplicativo Node.js, bem como nosso script ZX.
Depois que nossos arquivos são copiados para a imagem, executamos alguns comandos para baixar e extrair o MongoDB Atlas CLI.
Por fim, instalamos o ZX e as dependências do nosso aplicativo e executamos o script do ZX. O comando CMD para executar o script é feito quando o contêiner é executado. Todo o resto é feito quando a imagem é criada.
Poderíamos construir nossa imagem a partir deste arquivo Dockerfile, mas é muito mais fácil de gerenciar quando há uma configuração Compose. No diretório do projeto, crie um arquivo docker-compose.yml com o seguinte YAML:
1version: "3.9"
2services:
3 web:
4 build:
5 context: .
6 dockerfile: Dockerfile
7 ports:
8 - "3000:3000"
9 environment:
10 MONGODB_ATLAS_PUBLIC_API_KEY: YOUR_PUBLIC_KEY_HERE
11 MONGODB_ATLAS_PRIVATE_API_KEY: YOUR_PRIVATE_KEY_HERE
12 MONGODB_ATLAS_ORG_ID: YOUR_ORG_ID_HERE
13 MONGODB_ATLAS_PROJECT_ID: YOUR_PROJECT_ID_HERE
14 MONGODB_CLUSTER_NAME: examples
15 MONGODB_USERNAME: demo
16 MONGODB_PASSWORD: password1234
17 # MONGODB_DATABASE: sample_mflix
18 # MONGODB_COLLECTION: movies
19 CLEANUP_ONDESTROY: true
Você deverá trocar os valores das variáveis de ambiente pelos seus próprios valores. No exemplo acima, as variáveis de banco de dados e de coleção estão comentadas para que os padrões sejam usados no script ZX.
Para ver tudo em ação, execute o seguinte a partir da linha de comando no computador host:
1docker-compose up
O comando acima usará o arquivo docker-compose.yml para criar a imagem Docker se ela ainda não existir. O processo de criação agrupará nossos arquivos, instalará nossas dependências e obterá o MongoDB Atlas CLI. Quando o Compose implantar um contêiner a partir da imagem, as variáveis de ambiente serão passadas para o script ZX responsável por configurar o MongoDB Atlas. Quando estiver pronto, o script ZX executará a aplicação Node.js, passando ainda mais as variáveis de ambiente. Se a variável CLEANUP_ONDESTROY foi definida como true, quando o contêiner for interrompido, o banco de dados e a coleção serão removidos.

Conclusão

A CLI do MongoDB Atlas pode ser uma ferramenta poderosa para trazer o MongoDB Atlas para sua experiência de desenvolvimento local no Docker. Essencialmente, você estaria trocando uma versão local do MongoDB pela lógica Atlas CLI para gerenciar uma versão em nuvem mais rica em recursos do MongoDB.
O MongoDB Atlas aprimora a experiência do MongoDB dando acesso a mais recursos, como Atlas Search, Charts e App Services, que permitem criar ótimos aplicativos com o mínimo de esforço.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Exemplo de código

Exemplo de aplicativo para cuidadores de cães


Jul 12, 2024 | 3 min read
Artigo

Queries que não diferenciam maiúsculas de minúsculas sem índices que não diferenciam maiúsculas de minúsculas


Oct 01, 2024 | 8 min read
Tutorial

Introdução ao MongoDB e ao Amazon Q Assistente de codificação IA generativa


Sep 25, 2024 | 3 min read
Início rápido

Tutorial do MongoDB e Node.js - Operações CRUD


Aug 22, 2023 | 17 min read
Sumário