Automação do cluster do Atlas usando triggers agendados
Avalie esse Tutorial
Cada ação que você pode realizar na interface de usuário do Atlas é apoiada por uma API de administração correspondente, que permite levar a automação facilmente para os sistemas do Atlas. Algumas das formas mais comuns de automação do Atlas ocorrem em um agendamento, como pausar um cluster que é usado apenas para testes à noite e retomar o cluster novamente pela manhã.
Ter uma API para automatizar as ações do Atlas é ótimo, mas você ainda precisa escrever o script que chama a API, encontrar um local para hospedar o script e configurar o trabalho para chamar o script na programação desejada. É aqui que os triggers agendados do Atlas vêm ajudar.
Neste artigo Automação de clusters do Atlas usando triggers agendados, mostrarei como um trigger agendado pode ser usado para incorporar facilmente a automação em seu ambiente. Além de pausar e retomar um cluster, mostrarei como os eventos de aumento e redução do cluster também podem ser colocados em uma programação. Ambas as atividades permitem economizar nos custos quando você não precisa do cluster (pausado) ou não precisa dele para oferecer suporte a cargas de trabalho de pico (redução).
Três exemplos de triggers programados são fornecidos nesta solução. Cada trigger tem uma função de acionamento associada. A maior parte do trabalho é tratada pela função modifyCluster, que, como o nome indica, é uma função genérica para fazer modificações em um cluster. É um wrapper em torno da API de administração Modificar um cluster de um projeto do Atlas.
Para chamar as APIs administrativas do Atlas, primeiro você precisará de uma chave de API com privilégios de proprietário do projeto para os projetos que desejam agendar alterações de cluster.
As chaves de API são criadas no Gerenciador de acesso. Selecione Gerenciador de acesso no menu na barra de navegação superior e selecione Acesso ao projeto:
Em seguida, selecione a aba Chaves de API.
Crie uma nova chave, dando-lhe uma boa descrição e atribua à chave permissões de proprietário do projeto.
Clique em Avançar e anote sua chave privada:
Vamos limitar quem pode usar nossa chave de API adicionando uma lista de acesso. No nosso caso, a chave de API será usada por um trigger, que é um componente do Atlas App Services. Você encontrará a lista de endereços IP usados pelo App Services na documentação em Configuração de firewall. Observe que cada endereço IP deve ser adicionado individualmente. VocÊ pode votar nesta ideia para resolver isso: Capacidade de fornecer endereços IP como uma lista para acesso à rede
Clique em Concluído.
Como essa solução funciona em toda a sua organização do Atlas, eu gosto de hospedá-la em seu próprio projeto do Atlas dedicado.
Hospedaremos nosso trigger em um aplicativo Atlas App Services. Para começar, basta clicar na aba App Services:
Você verá que o App Services oferece vários modelos para você começar. Para esse caso de uso, basta selecionar a primeira opção para Criar seu próprio aplicativo:
Em seguida, você verá opções para vincular uma fonte de dados, nomear seu aplicativo e escolher um modelo de implantação. A iteração atual desse utilitário não usa uma fonte de dados, então você pode ignorar essa etapa (independentemente disso, um cluster gratuito para você). Você também pode deixar o modelo de implantação como padrão (Global), a menos que queira limitar o aplicativo a uma região específica.
Dei o nome de Aplicativo de automação ao aplicativo:
Clique em Create App Service. Se for apresentado a você um conjunto de guias, clique em Close Guides, pois hoje eu sou o seu guia.
A partir daqui, você tem a opção de simplesmente importar o aplicativo App Services e ajustar qualquer uma das funções para atender às suas necessidades. Se preferir criar o aplicativo do zero, pule para a próxima seção.
A extração depende da chave secreta da API, portanto, a importação falhará se ela não for configurada previamente.
Use o menu Valores à esquerda para Criar um segredo chamado AtlasPrivateKeySecret contendo sua chave privada (o segredo não está entre aspas):
O App Services CLI está disponível no npm. Para instalar o App Services CLI em seu sistema, certifique-se de ter o Node.js instalado e execute o seguinte comando em seu shell:
1 ✗ npm install -g atlas-app-services-cli
Para configurar seu aplicativo com o App Services CLI, você deve se conectar ao Atlas usando suas chaves de API:
1 ✗ appservices login --api-key="<Public API Key>" --private-api-key="<Private API Key>" 2 3 Successfully logged in
Selecione o menu Configurações do aplicativo e copie o ID do seu aplicativo:
Execute o seguinte comando appservices push no diretório em que você extraiu a exportação:
1 appservices push --remote="<Your App ID>" 2 3 ... 4 A summary of changes 5 ... 6 7 ? Please confirm the changes shown above Yes 8 9 Creating draft 10 Pushing changes 11 Deploying draft 12 Deployment complete 13 Successfully pushed app up:
Após a importação, substitua o
AtlasPublicKey
pelo valor da chave pública da API.Os 3 triggers têm 3 funções associadas. As funções pauseClustersTrigger e resumeClustersTrigger fornecem um conjunto de projetos e clusters para pausar, então elas precisam ser ajustadas para atender às suas necessidades:
1 // Supply projectIDs and clusterNames... 2 const projectIDs =[ 3 { 4 id: '5c5db514c56c983b7e4a8701', 5 names: [ 6 'Demo', 7 'Demo2' 8 ] 9 }, 10 { 11 id: '62d05595f08bd53924fa3634', 12 names: [ 13 'ShardedMultiRegion' 14 ] 15 } 16 ];
Todas as três funções de trigger chamam a função modifyCluster, onde a maior parte do trabalho é feita.
Além disso, você encontrará duas funções de utilitário, getProjectClusters e getProjects. Essas funções não são utilizadas nesta solução, mas são fornecidas para referência se você quiser automatizar ainda mais esses processos (ou seja, remover os IDs de projeto e os nomes de cluster codificados nas funções de trigger):
Agora que você revisou o rascunho, como etapa final, implante o aplicativo do App Services.
Para entender o que está incluído no aplicativo, estas são as etapas para criá-lo do zero.
As funções que precisamos criar chamarão as APIs de administração do Atlas, portanto, precisamos armazenar nossas chaves públicas e privadas de API, o que vamos fazer usando Valores e segredos. O código de amostra que forneço faz referência a esses valores como AtlasPublicKey e AtlasPrivateKey, portanto, use esses mesmos nomes, a menos que queira alterar o código em que eles são referenciados.
Você encontrará Valores no menu CRIAR:
Primeiro, crie um Valor para sua chave pública (observe que a chave está entre aspas):
Crie um Segredo contendo sua chave privada (o segredo não está entre aspas):
O Segredo não pode ser acessado diretamente, portanto, crie um segundo Valor que se vincule ao segredo:
Precisamos observar os IDs dos projetos que têm clusters que queremos automatizar. Clique nos 3 pontos no canto superior esquerdo da IU para abrir as Configurações do projeto:
Você encontrará seu ID do projeto:
Criarei duas funções, uma função genérica para modificar um cluster e uma funçãode trigger para iterar sobre os clusters a serem pausados.
Você encontrará funções no menu CRIAR :
Estou apenas demonstrando algumas coisas que você pode fazer com a automação de cluster, mas as opções são ilimitadas. A função modifyCluster a seguir é um wrapper genérico em torno da API Modificar um cluster multinuvem de um projeto para chamar a API do App Services (ou Node.js, nesse caso).
Crie uma nova função chamada modifyCluster. Defina a função como Privada, pois ela só será chamada pelo nosso trigger. As outras configurações padrão estão corretas:
Alterne para a aba Editor de funções e cole o seguinte código:
1 /* 2 * Modifies the cluster as defined by the body parameter. 3 * See https://www.mongodb.com/pt-br/docs/atlas/reference/api-resources-spec/v2/#tag/Clusters/operation/updateCluster 4 * 5 */ 6 exports = async function(username, password, projectID, clusterName, body) { 7 8 // Easy testing from the console 9 if (username == "Hello world!") { 10 username = await context.values.get("AtlasPublicKey"); 11 password = await context.values.get("AtlasPrivateKey"); 12 projectID = "5c5db514c56c983b7e4a8701"; 13 clusterName = "Demo"; 14 body = {paused: false} 15 } 16 17 const arg = { 18 scheme: 'https', 19 host: 'cloud.mongodb.com', 20 path: 'api/atlas/v2/groups/' + projectID + '/clusters/' + clusterName, 21 username: username, 22 password: password, 23 headers: {'Accept': ['application/vnd.atlas.2023-11-15+json'], 'Content-Type': ['application/json'], 'Accept-Encoding': ['bzip, deflate']}, 24 digestAuth:true, 25 body: JSON.stringify(body) 26 }; 27 28 // The response body is a BSON.Binary object. Parse it and return. 29 response = await context.http.patch(arg); 30 31 return EJSON.parse(response.body.text()); 32 };
Para testar essa função, é necessário fornecer uma chave de API, um segredo de API, um ID do projeto, um nome de cluster associado a ser modificado e uma carga útil contendo as modificações que você deseja fazer. Em nosso caso, trata-se apenas de definir a propriedade pausada.
Nota: por padrão, o Console fornece "Hello world!" ao testar a execução de uma função, então meu código de função testa essa entrada e fornece alguns valores padrão para facilitar o teste.
1 // Easy testing from the console 2 if (username == "Hello world!") { 3 username = await context.values.get("AtlasPublicKey"); 4 password = await context.values.get("AtlasPrivateKey"); 5 projectID = "5c5db514c56c983b7e4a8701"; 6 clusterName = "Demo"; 7 body = {paused: false} 8 }
Pressione o botão Executar para ver os resultados, que serão exibidos na janela Resultado:
E você deve encontrar seu cluster sendo retomado (ou pausado):
Esta função será chamada por um trigger. Como não é possível passar parâmetros para um trigger agendado, ele usa uma lista codificada de IDs do projeto e nomes de cluster associados para pausar. O ideal é que esses valores sejam armazenados em uma coleção com uma IU legal para gerenciar tudo, mas isso fica para outro dia :-).
No apêndice deste artigo, forneço funções que abrangerão todos os projetos e clusters da organização. Isso criaria uma operação verdadeiramente dinâmica que pausaria todos os clusters. Como alternativa, você poderia refatorar o código para usar uma lista de exclusão em vez de uma lista de permissão.
1 /* 2 * Iterates over the provided projects and clusters, pausing those clusters 3 */ 4 exports = async function() { 5 6 // Supply projectIDs and clusterNames... 7 const projectIDs = [{id:'5c5db514c56c983b7e4a8701', names:['Demo', 'Demo2']}, {id:'62d05595f08bd53924fa3634', names:['ShardedMultiRegion']}]; 8 9 // Get stored credentials... 10 const username = context.values.get("AtlasPublicKey"); 11 const password = context.values.get("AtlasPrivateKey"); 12 13 // Set desired state... 14 const body = {paused: true}; 15 16 var result = ""; 17 18 projectIDs.forEach(async function (project) { 19 20 project.names.forEach(async function (cluster) { 21 result = await context.functions.execute('modifyCluster', username, password, project.id, cluster, body); 22 console.log("Cluster " + cluster + ": " + EJSON.stringify(result)); 23 }); 24 }); 25 26 return "Clusters Paused"; 27 };
A capacidade de pausar e retomar um cluster é suportada pela API Modificar um cluster de um projeto. Para começar, selecione Triggers no menu à esquerda:
E adicione um gatilho.
Defina o tipo de Trigger como Agendado e o nome como pauseClusters:
Quanto à programação, você tem todo o poder das Expressões CRON ao seu alcance. Para este exercício, vamos presumir que queremos pausar o cluster todas as tardes às 6h. Selecione Avançado e defina o agendamento do CRON para
0 22 * * *
.Observe que a hora está em GMT, portanto, ajuste de acordo com seu fuso horário. Como esse cluster está sendo executado no Leste dos EUA, adicionarei 4 horas:
Verifique a janela Próximos eventos para validar a tarefa será executada quando você desejar.
A etapa final é selecionar a função a ser executada pelo trigger. Selecione a função pauseClustersTrigger.
E salve o trigger.
A etapa final é REVISAR RASCUNHO E IMPLANTAR.
Você pode optar por retomar manualmente o(s) cluster(s) conforme necessário. Mas, para completar, vamos supor que queremos que o(s) cluster(s) seja(m) retomado(s) automaticamente às 8h no Leste dos EUA todos os dias da semana.
Duplique a função pauseClustersTrigger para uma nova função chamada resumeClustersTriggger
No mínimo, edite a configuração do código de função pausada para false. Você também pode ajustar os projectIDs e clusterNames para um subconjunto de projetos a serem retomados:
1 /* 2 * Iterates over the provided projects and clusters, resuming those clusters 3 */ 4 exports = async function() { 5 6 // Supply projectIDs and clusterNames... 7 const projectIDs = [{id:'5c5db514c56c983b7e4a8701', names:['Demo', 'Demo2']}, {id:'62d05595f08bd53924fa3634', names:['ShardedMultiRegion']}]; 8 9 // Get stored credentials... 10 const username = context.values.get("AtlasPublicKey"); 11 const password = context.values.get("AtlasPrivateKey"); 12 13 // Set desired state... 14 const body = {paused: false}; 15 16 var result = ""; 17 18 projectIDs.forEach(async function (project) { 19 20 project.names.forEach(async function (cluster) { 21 result = await context.functions.execute('modifyCluster', username, password, project.id, cluster, body); 22 console.log("Cluster " + cluster + ": " + EJSON.stringify(result)); 23 }); 24 }); 25 26 return "Clusters Paused"; 27 };
Em seguida, adicione um novo trigger agendado chamado resumeClusters. Defina a programação do CRON para:
0 12 * * 1-5
. Próximos eventos valida para nós que isso é exatamente o que queremos:É comum ter cargas de trabalho que são mais exigentes durante determinadas horas do dia ou dias da semana. Em vez de executar o cluster para suportar a capacidade de pico, você pode usar essa mesma abordagem para programar o cluster para aumentar e diminuir conforme a necessidade da carga de trabalho.
OBSERVAÇÃO: os Atlas Clusters já oferecem suporte ao dimensionamento automático, o que pode muito bem atender às suas necessidades. A abordagem descrita aqui permite controlar quando seu cluster aumenta e diminui.
Digamos que queremos expandir nosso cluster todos os dias às 9h antes da nossa loja abrir.
Adicione uma nova função chamada scaleClusterUpTrigger. Aqui está o código da função. Ele é muito semelhante ao anterior, exceto pelo fato de o corpo ter sido alterado para modificar as configurações do provedor:
OBSERVAÇÃO: este exemplo representa uma topologia de região única. Se você tiver várias regiões e/ou clusters assimétricos usando nós somente leitura e/ou analíticos, basta verificar a documentação da API Modificar um cluster de um projeto para obter os detalhes da carga útil.
1 exports = async function() { 2 3 // Supply projectID and clusterNames... 4 const projectID = '<Project ID>'; 5 const clusterName = '<Cluster Name>'; 6 7 // Get stored credentials... 8 const username = context.values.get("AtlasPublicKey"); 9 const password = context.values.get("AtlasPrivateKey"); 10 11 // Set the desired instance size... 12 const body = { 13 "replicationSpecs": [ 14 { 15 "regionConfigs": [ 16 { 17 "electableSpecs": { 18 "instanceSize": "M10", 19 "nodeCount":3 20 }, 21 "priority":7, 22 "providerName": "AZURE", 23 "regionName": "US_EAST_2", 24 }, 25 ] 26 } 27 ] 28 }; 29 30 result = await context.functions.execute('modifyCluster', username, password, projectID, clusterName, body); 31 console.log(EJSON.stringify(result)); 32 33 if (result.error) { 34 return result; 35 } 36 37 return clusterName + " scaled up"; 38 };
Em seguida, adicione um trigger agendado chamado scaleClusterUp. Defina a programação do CRON para:
0 13 * * *
.A redução de um cluster seria simplesmente outro trigger, agendado para ser executado quando você quiser, usando o mesmo código acima, definindo o instanceSizeName para o que você desejar.
E é isso. Espero que seja útil. Você deve ser capaz de usar as técnicas descritas aqui para chamar facilmente qualquer endpoint da API Admin do MongoDB Atlas a partir do Atlas App Services.
Essa função autônoma pode ser testada no console do App Services para ver a lista de todos os projetos da sua organização. Você também pode chamá-la de outras funções para obter uma lista de projetos:
1 /* 2 * Returns an array of the projects in the organization 3 * See https://docs.atlas.mongodb.com/reference/api/project-get-all/ 4 * 5 * Returns an array of objects, e.g. 6 * 7 * { 8 * "clusterCount": { 9 * "$numberInt": "1" 10 * }, 11 * "created": "2021-05-11T18:24:48Z", 12 * "id": "609acbef1b76b53fcd37c8e1", 13 * "links": [ 14 * { 15 * "href": "https://cloud.mongodb.com/api/atlas/v1.0/groups/609acbef1b76b53fcd37c8e1", 16 * "rel": "self" 17 * } 18 * ], 19 * "name": "mg-training-sample", 20 * "orgId": "5b4e2d803b34b965050f1835" 21 * } 22 * 23 */ 24 exports = async function() { 25 26 // Get stored credentials... 27 const username = await context.values.get("AtlasPublicKey"); 28 const password = await context.values.get("AtlasPrivateKey"); 29 30 const arg = { 31 scheme: 'https', 32 host: 'cloud.mongodb.com', 33 path: 'api/atlas/v1.0/groups', 34 username: username, 35 password: password, 36 headers: {'Content-Type': ['application/json'], 'Accept-Encoding': ['bzip, deflate']}, 37 digestAuth:true, 38 }; 39 40 // The response body is a BSON.Binary object. Parse it and return. 41 response = await context.http.get(arg); 42 43 return EJSON.parse(response.body.text()).results; 44 };
Outro exemplo de função que retorna os detalhes do cluster para um projeto fornecido.
Observe que, para testar esta função, é necessário fornecer um projectId. Por padrão, o console fornece “Hello world!”, por isso testo essa entrada e forneço alguns valores padrão para facilitar o teste.
1 /* 2 * Returns an array of the clusters for the supplied project ID. 3 * See https://docs.atlas.mongodb.com/reference/api/clusters-get-all/ 4 * 5 * Returns an array of objects. See the API documentation for details. 6 * 7 */ 8 exports = async function(project_id) { 9 10 if (project_id == "Hello world!") { // Easy testing from the console 11 project_id = "5e8f8268d896f55ac04969a1" 12 } 13 14 // Get stored credentials... 15 const username = await context.values.get("AtlasPublicKey"); 16 const password = await context.values.get("AtlasPrivateKey"); 17 18 const arg = { 19 scheme: 'https', 20 host: 'cloud.mongodb.com', 21 path: `api/atlas/v1.0/groups/${project_id}/clusters`, 22 username: username, 23 password: password, 24 headers: {'Content-Type': ['application/json'], 'Accept-Encoding': ['bzip, deflate']}, 25 digestAuth:true, 26 }; 27 28 // The response body is a BSON.Binary object. Parse it and return. 29 response = await context.http.get(arg); 30 31 return EJSON.parse(response.body.text()).results; 32 };
Questões? Comentários? Vamos continuar a conversa. Junte-se a nós na comunidade de desenvolvedores do MongoDB para continuar.
Relacionado
Artigo
Implementação de pipelines RAG robustos: integração do Gemma 2 do Google (2B) técnicas de avaliação do MongoDB e LLM
Sep 12, 2024 | 20 min read
Tutorial
Construir um elemento de formulário de preenchimento automático com Atlas Search e JavaScript
Sep 09, 2024 | 8 min read