Como programar instâncias de computação com o Cloud Scheduler

Este tutorial mostra como usar o Cloud Scheduler e o Cloud Functions para iniciar e parar automaticamente as instâncias do Compute Engine em uma programação regular usando rótulos de recursos.

Objetivos

  • Escrever e implantar um conjunto de funções com o Cloud Functions que iniciem e interrompam instâncias do Compute Engine.
  • Crie um conjunto de tarefas com o Cloud Scheduler que agende instâncias com um rótulo de recurso dev para execução das 09:00-17:00, de segunda a sexta-feira, para corresponder ao horário comercial normal.

Custos

Neste tutorial, usamos os seguintes componentes faturáveis do Google Cloud:

  • Cloud Scheduler
  • Cloud Functions
  • Pub/Sub
  • Compute Engine

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem ser qualificados para uma avaliação gratuita.

Antes de começar

  1. Configure seu ambiente para o Cloud Scheduler.

    Como configurar seu ambiente

  2. Ative as APIs Cloud Functions, Pub/Sub, and Compute Engine.

    Ative as APIs

Arquitetura do aplicativo

Esta solução inclui os seguintes componentes do Google Cloud:

  1. Instância do Compute Engine: uma instância do Compute Engine a ser executada em uma programação.
  2. Funções do Cloud Functions: funções para iniciar e interromper a instância a ser programada.
  3. Mensagens do Pub/Sub: mensagens enviadas e recebidas para cada evento de inicialização e parada.
  4. Jobs do Cloud Scheduler: jobs para fazer chamadas de inicialização e parada da instância em uma programação definida.

Diagrama da arquitetura do sistema mostrando o Cloud Scheduler agendando uma instância do Compute Engine via Pub/Sub

Requisitos para locais

Alguns componentes são compatíveis apenas com determinadas regiões:

  1. Instância do Compute Engine: compatível com as regiões listadas nas Regiões e zonas do Compute Engine.
  2. Funções do Cloud Functions: compatíveis com as regiões listadas como Locais do Cloud Functions.
  3. Mensagens do Pub/Sub: compatíveis globalmente, uma vez que o Pub/Sub é um serviço global.
  4. Jobs do Cloud Scheduler: compatíveis com qualquer um dos locais atuais do App Engine.

Prática recomendada: por que não HTTP em vez do Pub/Sub?

Você pode simplificar essa arquitetura usando Gatilhos HTTP do Cloud Functions em vez de Gatilhos do Pub/Sub.

Diagrama de arquitetura do sistema que mostra o Cloud Scheduler agendando uma instância do Compute Engine por meio de HTTP

Diagrama de arquitetura do sistema mostrando que o agendamento por HTTP permite que qualquer pessoa agende sua instância do Compute Engine

Para criar uma configuração mais segura, recomendamos que você use as funções Pub/Sub.

Configurar a instância do Compute Engine

Console

  1. Acesse a página Instâncias de VM no Console do Cloud.
    Faça isso neste link
  2. Clique em Criar instância.
  3. Defina o Nome como dev-instance.
  4. Em Região, selecione us-west1.
  5. Em Zona, selecione us-west1-b.
  6. Expanda a seção Gerenciamento, segurança, discos, rede, locatário único.
  7. Em Gerenciamento, clique em Adicionar rótulo. Digite env para Chave e dev para Valor.
  8. Clique em Criar na parte inferior da página.

gcloud

gcloud compute instances create dev-instance \
    --network default \
    --zone us-west1-b \
    --labels=env=dev

Configure as funções do Cloud Functions com o Pub/Sub

Criar e implantar as funções

Console

Criar a função de inicialização

  1. Acesse a página Cloud Functions no Console do Cloud.
    Acessar a página do Cloud Functions.
  2. Clique em Criar função.
  3. Defina o Nome da função como startInstancePubSub.
  4. Deixe o valor padrão em Região.
  5. Em Tipo de gatilho, selecione Cloud Pub/Sub.
  6. Em Selecionar um tópico do Cloud Pub/Sub, selecione Create a topic....
  7. Uma caixa de diálogo Novo tópico pub/sub será exibida.
    1. Em ID do tópico, insira start-instance-event.
    2. Clique em Criar tópico para fechar a caixa de diálogo.
  8. Clique em Salvar na parte inferior da caixa Acionador.
  9. Clique em Avançar na parte inferior da página.
  10. Para Ambiente de execução, selecione Node.js 10.
  11. Em Ponto de entrada, digite startInstancePubSub.
  12. No lado esquerdo do editor de código, selecione index.js.
  13. Substitua o código inicial pelo seguinte:

    const Compute = require('@google-cloud/compute');
    const compute = new Compute();
    
    /**
     * Starts Compute Engine instances.
     *
     * Expects a PubSub message with JSON-formatted event data containing the
     * following attributes:
     *  zone - the GCP zone the instances are located in.
     *  label - the label of instances to start.
     *
     * @param {!object} event Cloud Function PubSub message event.
     * @param {!object} callback Cloud Function PubSub callback indicating
     *  completion.
     */
    exports.startInstancePubSub = async (event, context, callback) => {
      try {
        const payload = _validatePayload(
          JSON.parse(Buffer.from(event.data, 'base64').toString())
        );
        const options = {filter: `labels.${payload.label}`};
        const [vms] = await compute.getVMs(options);
        await Promise.all(
          vms.map(async (instance) => {
            if (payload.zone === instance.zone.id) {
              const [operation] = await compute
                .zone(payload.zone)
                .vm(instance.name)
                .start();
    
              // Operation pending
              return operation.promise();
            }
          })
        );
    
        // Operation complete. Instance successfully started.
        const message = `Successfully started instance(s)`;
        console.log(message);
        callback(null, message);
      } catch (err) {
        console.log(err);
        callback(err);
      }
    };
    
    /**
     * Validates that a request payload contains the expected fields.
     *
     * @param {!object} payload the request payload to validate.
     * @return {!object} the payload object.
     */
    const _validatePayload = (payload) => {
      if (!payload.zone) {
        throw new Error(`Attribute 'zone' missing from payload`);
      } else if (!payload.label) {
        throw new Error(`Attribute 'label' missing from payload`);
      }
      return payload;
    };
  14. No lado esquerdo do editor de código, selecione package.json.

  15. Substitua o código inicial pelo seguinte:

    {
      "name": "cloud-functions-schedule-instance",
      "version": "0.1.0",
      "private": true,
      "license": "Apache-2.0",
      "author": "Google Inc.",
      "repository": {
        "type": "git",
        "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
      },
      "engines": {
        "node": ">=10.0.0"
      },
      "scripts": {
        "test": "mocha test/*.test.js --timeout=20000"
      },
      "devDependencies": {
        "mocha": "^8.0.0",
        "proxyquire": "^2.0.0",
        "sinon": "^9.0.0"
      },
      "dependencies": {
        "@google-cloud/compute": "^2.0.0"
      }
    }
    
  16. Clique em Deploy na parte inferior da página.

Criar a função de parada

  1. Você deve estar na página Cloud Functions no Cloud Console.
  2. Clique em Criar função.
  3. Defina o Nome da função como stopInstancePubSub.
  4. Deixe o valor padrão em Região.
  5. Mantenha o valor padrão em Memória alocada.
  6. Em Tipo de gatilho, selecione Cloud Pub/Sub.
  7. Em Selecionar um tópico do Cloud Pub/Sub, selecione Create a topic....
  8. Uma caixa de diálogo Novo tópico pub/sub será exibida.
    1. Em ID do tópico, insira stop-instance-event.
    2. Clique em Criar tópico para fechar a caixa de diálogo.
  9. Clique em Salvar na parte inferior da caixa Acionador.
  10. Clique em Avançar na parte inferior da página.
  11. Para Ambiente de execução, selecione Node.js 10.
  12. Em Ponto de entrada, digite stopInstancePubSub.
  13. No lado esquerdo do editor de código, selecione index.js.
  14. Substitua o código inicial pelo seguinte:

    const Compute = require('@google-cloud/compute');
    const compute = new Compute();
    
    /**
     * Stops Compute Engine instances.
     *
     * Expects a PubSub message with JSON-formatted event data containing the
     * following attributes:
     *  zone - the GCP zone the instances are located in.
     *  label - the label of instances to stop.
     *
     * @param {!object} event Cloud Function PubSub message event.
     * @param {!object} callback Cloud Function PubSub callback indicating completion.
     */
    exports.stopInstancePubSub = async (event, context, callback) => {
      try {
        const payload = _validatePayload(
          JSON.parse(Buffer.from(event.data, 'base64').toString())
        );
        const options = {filter: `labels.${payload.label}`};
        const [vms] = await compute.getVMs(options);
        await Promise.all(
          vms.map(async (instance) => {
            if (payload.zone === instance.zone.id) {
              const [operation] = await compute
                .zone(payload.zone)
                .vm(instance.name)
                .stop();
    
              // Operation pending
              return operation.promise();
            } else {
              return Promise.resolve();
            }
          })
        );
    
        // Operation complete. Instance successfully stopped.
        const message = `Successfully stopped instance(s)`;
        console.log(message);
        callback(null, message);
      } catch (err) {
        console.log(err);
        callback(err);
      }
    };
    
    /**
     * Validates that a request payload contains the expected fields.
     *
     * @param {!object} payload the request payload to validate.
     * @return {!object} the payload object.
     */
    const _validatePayload = (payload) => {
      if (!payload.zone) {
        throw new Error(`Attribute 'zone' missing from payload`);
      } else if (!payload.label) {
        throw new Error(`Attribute 'label' missing from payload`);
      }
      return payload;
    };
  15. No lado esquerdo do editor de código, selecione package.json.

  16. Substitua o código inicial pelo seguinte:

    {
      "name": "cloud-functions-schedule-instance",
      "version": "0.1.0",
      "private": true,
      "license": "Apache-2.0",
      "author": "Google Inc.",
      "repository": {
        "type": "git",
        "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
      },
      "engines": {
        "node": ">=10.0.0"
      },
      "scripts": {
        "test": "mocha test/*.test.js --timeout=20000"
      },
      "devDependencies": {
        "mocha": "^8.0.0",
        "proxyquire": "^2.0.0",
        "sinon": "^9.0.0"
      },
      "dependencies": {
        "@google-cloud/compute": "^2.0.0"
      }
    }
    
  17. Clique em Deploy na parte inferior da página.

gcloud

Crie os tópicos do Pub/Sub.

gcloud pubsub topics create start-instance-event
gcloud pubsub topics create stop-instance-event

Receber o código

  1. Faça o download do código.

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    Outra alternativa é fazer o download da amostra como um arquivo ZIP e extraí-lo.

  2. Acesse o diretório correto.

    cd nodejs-docs-samples/functions/scheduleinstance/
    

Criar as funções de inicialização e parada

Você deve estar no diretório nodejs-docs-samples/functions/scheduleinstance/.

gcloud functions deploy startInstancePubSub \
    --trigger-topic start-instance-event \
    --runtime nodejs10 \
    --allow-unauthenticated
gcloud functions deploy stopInstancePubSub \
    --trigger-topic stop-instance-event \
    --runtime nodejs10 \
    --allow-unauthenticated

(Opcional) Verificar se as funções são executadas corretamente

Console

Interromper a instância

  1. Acesse a página Cloud Functions no Console do Cloud.
    Acessar a página Cloud Functions.
  2. Clique na função denominada stopInstancePubSub.
  3. Você verá várias guias: Geral, Acionador, Origem, Permissões e Testes. Clique na guia Testes.
  4. Em Evento acionador, digite o seguinte:

    {"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}
    

    • Essa é simplesmente a sequência codificada em base64 para {"zone":"us-west1-b", "label":"env=dev"}

    • Se quiser codificar sua própria string, use qualquer ferramenta de codificação base64 on-line.

  5. Clique no botão Testar a função.

  6. Quando terminar de executar, você verá Successfully stopped instance dev-instance impresso em Saída. A execução pode levar até 60 segundos para ser concluída.

    • Se você vir error: 'Error: function failed to load.', aguarde 10 segundos ou mais para que a função conclua a implantação e tente novamente.

    • Se você vir error: 'Error: function execution attempt timed out.', passe para a próxima etapa para ver se a instância está demorando muito para ser encerrada.

    • Se a execução for encerrada e nenhuma informação for exibida, provavelmente o tempo expirou. Basta seguir para a próxima etapa e confirmar se a instância está demorando muito para ser desativada.

  7. Acesse a página Instâncias de VM no Console do Cloud.
    Faça isso neste link

  8. Verifique se a instância chamada dev-instance possui um quadrado cinza ao lado do nome, indicando que parou. Pode levar até 30 segundos para a desativação ser concluída.

    • Se a instância não for encerrada, clique em Atualizar na parte superior da página.

Iniciar a instância

  1. Acesse a página Cloud Functions no Console do Cloud.
    Acessar a página Cloud Functions.
  2. Clique na função denominada startInstancePubSub.
  3. Você verá várias guias: Geral, Acionador, Origem, Permissões e Testes. Clique na guia Testes.
  4. Em Evento acionador, digite o seguinte:

    {"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}
    

    • Novamente, essa é simplesmente a sequência codificada em base64 para {"zone":"us-west1-b", "label":"env=dev"}
  5. Clique no botão Testar a função.

  6. Quando terminar de executar, você verá Successfully started instance dev-instance impresso em Saída.

  7. Acesse a página Instâncias de VM no Console do Cloud.
    Faça isso neste link

  8. Verifique se a instância chamada dev-instance possui uma marca de seleção verde ao lado do nome, indicando que está em execução. Pode levar até 30 segundos para a inicialização ser concluída.

gcloud

Interromper a instância

  1. Chame a função para interromper a instância.

    gcloud functions call stopInstancePubSub \
        --data '{"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}'
    
    • Essa é simplesmente a sequência codificada em base64 para {"zone":"us-west1-b", "label":"env=dev"}

    • Se você quiser codificar sua própria string, poderá utilizar qualquer ferramenta. Aqui está um exemplo usando a ferramenta de linha de comando base64:

      echo '{"zone":"us-west1-b", "label":"env=dev"}' | base64
      
      eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo=
      

    Quando a função for encerrada, você verá o seguinte:

    result: Successfully stopped instance dev-instance
    

    A execução pode levar até 60 segundos para ser concluída.

    • Se, em vez disso, você receber o erro:

      error: 'Error: function failed to load.`
      

      Aguarde cerca de 10 segundos até que a implantação seja concluída e tente novamente.

    • Se, em vez disso, você receber o erro:

      error: `Error: function execution attempt timed out.`
      

      Siga para a próxima etapa e confirme se a instância está demorando muito para ser desativada.

    • Se, em vez disso, você não receber resultados, provavelmente o tempo limite da função expirou. Siga para a próxima etapa e confirme se a instância está demorando muito para ser desativada.

  2. Verifique se a instância tem um status TERMINATED. Pode levar até 30 segundos para que a desativação seja concluída.

    gcloud compute instances describe dev-instance \
        --zone us-west1-b \
        | grep status
    
    status: TERMINATED
    

Iniciar a instância

  1. Chame a função para iniciar a instância.

    gcloud functions call startInstancePubSub \
        --data '{"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}'
    
    • Novamente, essa é simplesmente a sequência codificada em base64 para {"zone":"us-west1-b", "label":"env=dev"}

    Quando a função for encerrada, você verá o seguinte:

    result: Successfully started instance dev-instance
    
  2. Verifique se a instância tem um status RUNNING. Pode levar até 30 segundos para a inicialização ser concluída.

    gcloud compute instances describe dev-instance \
        --zone us-west1-b \
        | grep status
    
    status: RUNNING
    

Configure os trabalhos do Cloud Scheduler para chamar o Pub/Sub

Criar os jobs

Console

Criar o job de inicialização

  1. Vá para a página Cloud Scheduler no Cloud Console.
    Acessar a página do Cloud Scheduler.
  2. Clique em Criar job.
  3. Mantenha a região padrão e clique em Avançar na parte inferior da página.
  4. Defina o Nome como startup-dev-instances.
  5. Em Frequência, insira 0 9 * * 1-5.
    • Isso será executado às 9h todos os dias, de segunda a sexta-feira.
  6. Em Fuso horário, selecione o país e o fuso horário desejados. Este exemplo usará United States e Los Angeles.
  7. Para Destino, selecione Pub/Sub.
  8. Para Tópico, digite start-instance-event.
  9. Em Payload, digite o seguinte:
    {"zone":"us-west1-b","label":"env=dev"}
    
  10. Clique em Criar.

Criar o job de parada

  1. Você deve estar na página Cloud Scheduler no Cloud Console.
  2. Clique em Criar job.
  3. Mantenha a região padrão e clique em Avançar na parte inferior da página.
  4. Defina o Nome como shutdown-dev-instances.
  5. Em Frequência, insira 0 17 * * 1-5.
    • Isso será executado às 17h todos os dias, de segunda a sexta-feira.
  6. Em Fuso horário, selecione o país e o fuso horário desejados. Este exemplo usará United States e Los Angeles.
  7. Para Destino, selecione Pub/Sub.
  8. Para Tópico, digite stop-instance-event.
  9. Em Payload, digite o seguinte:
    {"zone":"us-west1-b","label":"env=dev"}
    
  10. Clique em Criar.

gcloud

Criar o job de inicialização

gcloud beta scheduler jobs create pubsub startup-dev-instances \
    --schedule '0 9 * * 1-5' \
    --topic start-instance-event \
    --message-body '{"zone":"us-west1-b", "label":"env=dev"}' \
    --time-zone 'America/Los_Angeles'

Criar o job de parada

gcloud beta scheduler jobs create pubsub shutdown-dev-instances \
    --schedule '0 17 * * 1-5' \
    --topic stop-instance-event \
    --message-body '{"zone":"us-west1-b", "label":"env=dev"}' \
    --time-zone 'America/Los_Angeles'

(Opcional) Verificar se os jobs são executados corretamente

Console

Interromper a instância

  1. Vá para a página Cloud Scheduler no Cloud Console.
    Acessar a página do Cloud Scheduler.
  2. Para o job chamado shutdown-dev-instances, clique no botão Executar agora no lado direito da página.
  3. Acesse a página Instâncias de VM no Console do Cloud.
    Faça isso neste link
  4. Verifique se a instância chamada dev-instance possui um quadrado cinza ao lado do nome, indicando que parou. Pode levar até 30 segundos para a desativação ser concluída.

Iniciar a instância

  1. Vá para a página Cloud Scheduler no Cloud Console.
    Acessar a página do Cloud Scheduler.
  2. Para o job chamado startup-dev-instances, clique no botão Executar agora no lado direito da página.
  3. Acesse a página Instâncias de VM no Console do Cloud.
    Faça isso neste link
  4. Verifique se a instância chamada dev-instance possui uma marca de seleção verde ao lado do nome, indicando que está em execução. Pode demorar até 30 segundos para a inicialização ser concluída.

gcloud

Interromper a instância

  1. Execute o job do programador para interromper a instância.

    gcloud beta scheduler jobs run shutdown-dev-instances
    
  2. Verifique se a instância tem um status TERMINATED. Pode levar até 30 segundos para a desativação ser concluída.

    gcloud compute instances describe dev-instance \
        --zone us-west1-b \
        | grep status
    
    status: TERMINATED
    

Iniciar a instância

  1. Execute o job do programador para iniciar a instância.

    gcloud beta scheduler jobs run startup-dev-instances
    
  2. Verifique se a instância tem um status RUNNING. Pode levar até 30 segundos para a inicialização ser concluída.

    gcloud compute instances describe dev-instance \
        --zone us-west1-b \
        | grep status
    
    status: RUNNING
    

Limpar

Depois de concluir o tutorial de agendamento da instância, você pode limpar os recursos que criou no Google Cloud para que eles não atinjam a cota e não sejam cobrados por eles no futuro. Veja como excluir e desativar esses recursos nas seções a seguir.

Excluir os jobs do Cloud Scheduler

  1. Vá para a página Cloud Scheduler no Cloud Console.

    Acessar a página do Cloud Scheduler.

  2. Clique nas caixas de seleção ao lado dos seus jobs.

  3. Clique no botão Excluir na parte superior da página e confirme.

Excluir os tópicos do Pub/Sub

  1. Acesse a página Pub/Sub no Console do Cloud.

    Acessar a página do Pub/Sub

  2. Clique nas caixas de seleção ao lado dos seus tópicos.

  3. Clique em Excluir na parte superior da página e confirme.

Excluir as funções do Cloud Functions

  1. Acesse a página Cloud Functions no Console do Cloud.

    Acessar a página Cloud Functions.

  2. Clique nas caixas de seleção ao lado das funções.

  3. Clique no botão Excluir na parte superior da página e confirme.

Excluir a instância do Compute Engine

Para excluir uma instância do Compute Engine:

  1. No Console do Cloud, acesse a página Instâncias de VM.

    Acessar a página "Instâncias de VMs"

  2. Marque a caixa de seleção para instância que você quer excluir.
  3. Clique em Excluir para remover a instância.

Exclua o projeto

O jeito mais fácil de evitar cobranças é excluir o projeto que você criou para o tutorial.

Para excluir o projeto:

  1. No Console do Cloud, acesse a página Gerenciar recursos:

    Acessar a página "Gerenciar recursos"

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.

A seguir