Agende o início ou a paragem de uma VM do Compute Engine


Este tutorial mostra como usar as funções do Cloud Scheduler e do Cloud Run para iniciar e parar automaticamente instâncias do Compute Engine num horário regular usando etiquetas de recursos.

Objetivos

  • Escreva e implemente um conjunto de funções com funções do Cloud Run que iniciam e param instâncias do Compute Engine.
  • Crie um conjunto de tarefas com o Cloud Scheduler que agendem instâncias com uma etiqueta de recurso dev para serem executadas das 09:00 às 17:00, de segunda a sexta-feira, para corresponder ao horário de funcionamento típico.

Custos

Neste documento, usa os seguintes componentes faturáveis do Google Cloud:

  • Cloud Scheduler
  • Cloud Run functions
  • Pub/Sub
  • Compute Engine

Para gerar uma estimativa de custos com base na sua utilização projetada, use a calculadora de preços.

Os novos Google Cloud utilizadores podem ser elegíveis para uma avaliação gratuita.

Antes de começar

  1. Configure o seu ambiente para o Cloud Scheduler.

    Configurar o seu ambiente

  2. Enable the Cloud Run functions, Pub/Sub, and Compute Engine APIs.

    Enable the APIs

Arquitetura de aplicações

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

Diagrama de arquitetura do sistema que mostra o Cloud Scheduler a agendar uma instância do Compute Engine através do Pub/Sub

Requisitos de localização

Alguns componentes só são suportados em determinadas regiões:

  • Instância do Compute Engine: suportada em qualquer região listada em Regiões e zonas.
  • Funções do Cloud Run: suportadas nas regiões indicadas em Localizações.
  • Mensagens do Pub/Sub: suportadas globalmente, uma vez que o Pub/Sub é um serviço global.
  • Tarefas do Cloud Scheduler com destinos do Pub/Sub: suportadas em qualquer Google Cloud localização.

Por que motivo não usar HTTP em vez de Pub/Sub?

Pode simplificar esta arquitetura usando funções do Cloud Run Acionadores HTTP em vez de Acionadores do Pub/Sub.

Este tutorial usa o Pub/Sub como o acionador das funções do Cloud Run porque este método era anteriormente mais seguro do que usar HTTP. No entanto, o HTTP também é uma escolha válida e agora pode ser protegido através da exigência de autenticação.

Para saber como proteger as funções do Cloud Run, consulte a vista geral da segurança das funções do Cloud Run. Para uma comparação entre acionadores HTTP e Pub/Sub, consulte a documentação Acionadores de funções do Cloud Run.

Configure a instância do Compute Engine

Consola

  1. Aceda à página Instâncias de VM na Google Cloud consola.
    Aceda à página de instâncias de VM.
  2. Clique em Criar instância.
  3. Defina o Nome como dev-instance.
  4. Em Etiquetas, clique em Adicionar etiquetas.
  5. Clique em Adicionar etiqueta.
  6. Introduza env para Chave e dev para Valor.
  7. Para Região, selecione us-west1.
  8. Para Zona, selecione us-west1-b.
  9. Clique em Guardar.
  10. 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

Implemente funções acionadas pelo Pub/Sub através de funções do Cloud Run

Crie e implemente as funções

Consola

Crie a função de início.

  1. Aceda à página Funções do Cloud Run na Google Cloud consola.
    Aceda à página de funções do Cloud Run.
  2. Clique em Criar função.
  3. Para Ambiente, selecione 1.ª geração.
  4. Defina o Nome da função como startInstancePubSub.
  5. Mantenha o valor predefinido de Região.
  6. Em Tipo de acionador, selecione Cloud Pub/Sub.
  7. Em Selecionar um tópico do Cloud Pub/Sub, clique em Criar um tópico.
  8. Deve aparecer uma caixa de diálogo Criar tópico.
    1. Em ID do tópico, introduza start-instance-event.
    2. Clique em Criar para concluir a caixa de diálogo.
  9. Clique em Guardar na parte inferior da caixa Acionador.
  10. Clique em Seguinte na parte inferior da página.
  11. Para Tempo de execução, selecione Node.js 16 ou posterior.
  12. Para Entry point, introduza startInstancePubSub.
  13. No lado esquerdo do editor de código, selecione index.js.
  14. Substitua o código inicial pelo seguinte código:

    const compute = require('@google-cloud/compute');
    const instancesClient = new compute.InstancesClient();
    const operationsClient = new compute.ZoneOperationsClient();
    
    async function waitForOperation(projectId, operation) {
      while (operation.status !== 'DONE') {
        [operation] = await operationsClient.wait({
          operation: operation.name,
          project: projectId,
          zone: operation.zone.split('/').pop(),
        });
      }
    }
    
    /**
     * 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 project = await instancesClient.getProjectId();
        const payload = _validatePayload(event);
        const options = {
          filter: `labels.${payload.label}`,
          project,
          zone: payload.zone,
        };
    
        const [instances] = await instancesClient.list(options);
    
        await Promise.all(
          instances.map(async instance => {
            const [response] = await instancesClient.start({
              project,
              zone: payload.zone,
              instance: instance.name,
            });
    
            return waitForOperation(project, response.latestResponse);
          })
        );
    
        // 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 = event => {
      let payload;
      try {
        payload = JSON.parse(Buffer.from(event.data, 'base64').toString());
      } catch (err) {
        throw new Error('Invalid Pub/Sub message: ' + err);
      }
      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 código:

    {
      "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": ">=16.0.0"
      },
      "scripts": {
        "test": "c8 mocha -p -j 2 test/*.test.js --timeout=20000"
      },
      "devDependencies": {
        "c8": "^10.0.0",
        "mocha": "^10.0.0",
        "proxyquire": "^2.0.0",
        "sinon": "^18.0.0"
      },
      "dependencies": {
        "@google-cloud/compute": "^4.0.0"
      }
    }
    
  17. Clique em Implementar na parte inferior da página.

Crie a função de paragem.

  1. Deve estar na página Funções do Cloud Run na Google Cloud consola.
  2. Clique em Criar função.
  3. Para Ambiente, selecione 1.ª geração.
  4. Defina o Nome da função como stopInstancePubSub.
  5. Mantenha o valor predefinido de Região.
  6. Em Tipo de acionador, selecione Cloud Pub/Sub.
  7. Em Selecionar um tópico do Cloud Pub/Sub, clique em Criar um tópico.
  8. Deve aparecer uma caixa de diálogo Criar tópico.
    1. Em ID do tópico, introduza stop-instance-event.
    2. Clique em Criar para concluir a caixa de diálogo.
  9. Clique em Guardar na parte inferior da caixa Acionador.
  10. Clique em Seguinte na parte inferior da página.
  11. Para Tempo de execução, selecione Node.js 16 ou posterior.
  12. Para Entry point, introduza stopInstancePubSub.
  13. No lado esquerdo do editor de código, selecione index.js.
  14. Substitua o código inicial pelo seguinte código:

    const compute = require('@google-cloud/compute');
    const instancesClient = new compute.InstancesClient();
    const operationsClient = new compute.ZoneOperationsClient();
    
    async function waitForOperation(projectId, operation) {
      while (operation.status !== 'DONE') {
        [operation] = await operationsClient.wait({
          operation: operation.name,
          project: projectId,
          zone: operation.zone.split('/').pop(),
        });
      }
    }
    
    /**
     * 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 project = await instancesClient.getProjectId();
        const payload = _validatePayload(event);
        const options = {
          filter: `labels.${payload.label}`,
          project,
          zone: payload.zone,
        };
    
        const [instances] = await instancesClient.list(options);
    
        await Promise.all(
          instances.map(async instance => {
            const [response] = await instancesClient.stop({
              project,
              zone: payload.zone,
              instance: instance.name,
            });
    
            return waitForOperation(project, response.latestResponse);
          })
        );
    
        // 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 = event => {
      let payload;
      try {
        payload = JSON.parse(Buffer.from(event.data, 'base64').toString());
      } catch (err) {
        throw new Error('Invalid Pub/Sub message: ' + err);
      }
      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 código:

    {
      "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": ">=16.0.0"
      },
      "scripts": {
        "test": "c8 mocha -p -j 2 test/*.test.js --timeout=20000"
      },
      "devDependencies": {
        "c8": "^10.0.0",
        "mocha": "^10.0.0",
        "proxyquire": "^2.0.0",
        "sinon": "^18.0.0"
      },
      "dependencies": {
        "@google-cloud/compute": "^4.0.0"
      }
    }
    
  17. Clique em Implementar 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

Obter o código

  1. Transfira o código.

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

    Em alternativa, pode transferir o exemplo como um ficheiro ZIP e extraí-lo.

  2. Aceda ao diretório correto.

    cd nodejs-docs-samples/functions/scheduleinstance/

Crie as funções de início e fim.

Deve estar no diretório nodejs-docs-samples/functions/scheduleinstance/.

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

(Opcional) Valide se as funções funcionam

Consola

Pare a instância

  1. Aceda à página Funções do Cloud Run na Google Cloud consola.
    Aceda à página de funções do Cloud Run.
  2. Clique na função denominada stopInstancePubSub.
  3. Deve ver vários separadores: Geral, Acionador, Origem, Autorizações e Testes. Clique no separador Testes.
  4. Para Evento de acionamento, introduza o seguinte:

    {"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}
    

    • Esta é simplesmente a string codificada em base64 para {"zone":"us-west1-b", "label":"env=dev"}

    • Se quiser codificar a sua própria string, pode usar qualquer ferramenta de codificação base64 online.

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

  6. Quando a execução estiver concluída, deve ver Successfully stopped instance dev-instance impresso em Output. A execução pode demorar até 60 segundos.

    • Se, em alternativa, vir error: 'Error: function failed to load.', basta aguardar cerca de 10 segundos para que a função termine a implementação e tentar novamente.

    • Se, em vez disso, vir error: 'Error: function execution attempt timed out.', avance para o passo seguinte para ver se a instância está apenas a demorar muito tempo a ser encerrada.

    • Se, em vez disso, terminar a execução, mas não mostrar nada, é provável que o tempo limite também tenha sido excedido. Basta avançar para o passo seguinte para ver se a instância está a demorar muito tempo a ser encerrada.

  7. Aceda à página Instâncias de VM na Google Cloud consola.
    Aceda à página de instâncias de VM.

  8. Verifique se a instância denominada dev-instance tem um quadrado cinzento junto ao nome, o que indica que foi interrompida. O encerramento pode demorar até 30 segundos.

    • Se não parecer estar a terminar, experimente clicar em Atualizar na parte superior da página.

Inicie a instância

  1. Aceda à página Funções do Cloud Run na Google Cloud consola.
    Aceda à página de funções do Cloud Run.
  2. Clique na função denominada startInstancePubSub.
  3. Deve ver vários separadores: Geral, Acionador, Origem, Autorizações e Testes. Clique no separador Testes.
  4. Para Evento de acionamento, introduza o seguinte:

    {"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}
    

    • Mais uma vez, esta é simplesmente a string codificada em base64 para {"zone":"us-west1-b", "label":"env=dev"}
  5. Clique no botão Testar a função.

  6. Quando a execução estiver concluída, deve ver Successfully started instance dev-instance impresso em Output.

  7. Aceda à página Instâncias de VM na Google Cloud consola.
    Aceda à página de instâncias de VM.

  8. Verifique se a instância denominada dev-instance tem uma marca de verificação verde junto ao nome, o que indica que está em execução. O arranque pode demorar até 30 segundos.

gcloud

Pare a instância

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

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

    • Se quiser codificar a sua própria string, pode usar qualquer ferramenta. Segue-se um exemplo com a ferramenta de linha de comandos base64:

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

    Quando a função terminar, deve ver o seguinte:

    result: Successfully stopped instance dev-instance
    

    A execução pode demorar até 60 segundos.

    • Se, em vez disso, receber o erro:

      error: 'Error: function failed to load.`
      

      Aguarde cerca de 10 segundos para que a função termine a implementação e tente novamente.

    • Se, em vez disso, receber o erro:

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

      Avance para o passo seguinte para ver se a instância está apenas a demorar muito tempo a ser encerrada.

    • Se, em alternativa, não receber nenhum resultado, é provável que a função tenha excedido o tempo limite. Avance para o passo seguinte para ver se a instância está apenas a demorar muito tempo a ser encerrada.

  2. Verifique se a instância tem o estado TERMINATED. O encerramento pode demorar até 30 segundos.

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

Inicie a instância

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

    gcloud functions call startInstancePubSub \
        --data '{"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}'
    
    • Mais uma vez, esta é simplesmente a string codificada em base64 para {"zone":"us-west1-b", "label":"env=dev"}

    Quando a função terminar, deve ver o seguinte:

    result: Successfully started instance dev-instance
    
  2. Verifique se a instância tem o estado RUNNING. O arranque pode demorar até 30 segundos.

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

Configure as tarefas do Cloud Scheduler para chamar o Pub/Sub

Crie os trabalhos

Consola

Crie a tarefa de início.

  1. Aceda à página Cloud Scheduler na Google Cloud consola.
    Aceda à página do Cloud Scheduler.
  2. Clique em Criar tarefa.
  3. Deixe a região predefinida.
  4. Defina o Nome como startup-dev-instances.
  5. Para Frequência, introduza 0 9 * * 1-5.
    • Esta ação é executada todos os dias úteis às 09:00.
  6. Para Fuso horário, selecione o país e o fuso horário pretendidos. Este exemplo vai usar United States e Los Angeles.
  7. Clique em Continuar.
  8. Para Tipo de segmentação, selecione Pub/Sub.
  9. Selecione start-instance-event no menu pendente de tópicos.
  10. Para Mensagem, introduza o seguinte:
    {"zone":"us-west1-b","label":"env=dev"}
    
  11. Clique em Criar.

Crie o trabalho de paragem.

  1. Deve estar na página Cloud Scheduler na Google Cloud consola.
  2. Clique em Criar tarefa.
  3. Deixe a região predefinida e clique em Seguinte na parte inferior da página.
  4. Defina o Nome como shutdown-dev-instances.
  5. Para Frequência, introduza 0 17 * * 1-5.
    • Esta ação é executada todos os dias úteis às 17:00.
  6. Para Fuso horário, selecione o país e o fuso horário pretendidos. Este exemplo vai usar United States e Los Angeles.
  7. Clique em Continuar.
  8. Para Tipo de segmentação, selecione Pub/Sub.
  9. Selecione stop-instance-event no menu pendente de tópicos.
  10. Para Mensagem, introduza o seguinte:
    {"zone":"us-west1-b","label":"env=dev"}
    
  11. Clique em Criar.

gcloud

Crie a tarefa de início.

gcloud 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' \
    --location us-central1

Crie o trabalho de paragem.

gcloud 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' \
    --location us-central1

(Opcional) Valide se os trabalhos funcionam

Consola

Pare a instância

  1. Aceda à página Cloud Scheduler na Google Cloud consola.
    Aceda à página do Cloud Scheduler.
  2. Para a tarefa denominada shutdown-dev-instances, clique no botão Executar agora no lado direito da página.
  3. Aceda à página Instâncias de VM na Google Cloud consola.
    Aceda à página de instâncias de VM.
  4. Verifique se a instância denominada dev-instance tem um quadrado cinzento junto ao nome, o que indica que foi interrompida. Pode demorar até 30 segundos a concluir o encerramento.

Inicie a instância

  1. Aceda à página Cloud Scheduler na Google Cloud consola.
    Aceda à página do Cloud Scheduler.
  2. Para a tarefa denominada startup-dev-instances, clique no botão Executar agora no lado direito da página.
  3. Aceda à página Instâncias de VM na Google Cloud consola.
    Aceda à página de instâncias de VM.
  4. Verifique se a instância denominada dev-instance tem uma marca de verificação verde junto ao nome, o que indica que está em execução. O arranque pode demorar até 30 segundos.

gcloud

Pare a instância

  1. Execute a tarefa do programador para parar a instância.

    gcloud beta scheduler jobs run shutdown-dev-instances
    
  2. Verifique se a instância tem o estado TERMINATED. Pode demorar até 30 segundos para que o dispositivo seja desligado.

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

Inicie a instância

  1. Execute a tarefa do programador para iniciar a instância.

    gcloud beta scheduler jobs run startup-dev-instances
    
  2. Verifique se a instância tem o estado RUNNING. O arranque pode demorar até 30 segundos.

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

Limpar

Depois de concluir o tutorial, pode limpar os recursos que criou para que deixem de usar a quota e incorrer em custos. As secções seguintes descrevem como eliminar ou desativar estes recursos.

Elimine as tarefas do Cloud Scheduler

  1. Aceda à página Cloud Scheduler na Google Cloud consola.

    Aceda à página do Cloud Scheduler.

  2. Clique nas caixas de verificação junto aos seus trabalhos.

  3. Clique no botão Eliminar na parte superior da página e confirme a eliminação.

Elimine os tópicos do Pub/Sub

  1. Aceda à página Pub/Sub na Google Cloud consola.

    Aceda à página do Pub/Sub

  2. Clique nas caixas de verificação junto aos seus tópicos.

  3. Clique em Eliminar na parte superior da página e confirme a eliminação.

Elimine as funções implementadas através das funções do Cloud Run

  1. Aceda à página Funções do Cloud Run na Google Cloud consola.

    Aceda à página de funções do Cloud Run.

  2. Clique nas caixas de verificação junto às suas funções.

  3. Clique no botão Eliminar na parte superior da página e confirme a eliminação.

Elimine a instância do Compute Engine

Para eliminar uma instância do Compute Engine:

  1. In the Google Cloud console, go to the VM instances page.

    Go to VM instances

  2. Select the checkbox for the instance that you want to delete.
  3. To delete the instance, click More actions, click Delete, and then follow the instructions.

Elimine o projeto

A forma mais fácil de eliminar a faturação é eliminar o projeto que criou para o tutorial.

Para eliminar o projeto:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

O que se segue?