O tempo de execução do Node.js

O tempo de execução do Node.js é a pilha de software responsável por instalar o código da aplicação e as dependências, e, em seguida, executar essa aplicação no ambiente flexível.

Versões do Node.js

O Node.js 24 (pré-visualização) usa buildpacks. O motor Node.js predefinido usa a versão LTS mais recente. Para ver a lista completa das versões do Node.js suportadas e a respetiva versão do Ubuntu, consulte a programação de suporte de tempo de execução.

Para usar uma versão do Node.js suportada, tem de:

  • Instale a versão gcloud CLI 420.0.0 ou posterior. Pode atualizar as ferramentas da CLI executando o comando gcloud components update. Para ver a versão instalada, execute o comando gcloud version.

  • Inclua as definições runtime_config e operating_system no ficheiro app.yaml para especificar um sistema operativo.

  • Opcionalmente, especifique uma versão:

    • Adicionar a definição runtime_version no ficheiro app.yaml. Por predefinição, é usada a versão mais recente do Node.js se a definição runtime_version não for especificada. Por exemplo:

      • Para especificar o Node.js 24 (pré-visualização) no Ubuntu 24:

          runtime: nodejs
          env: flex
        
          runtime_config:
              operating_system: "ubuntu24"
              runtime_version: "24"
        
      • Para especificar a versão mais recente suportada do Node.js no Ubuntu 24:

          runtime: nodejs
          env: flex
        
          runtime_config:
              operating_system: "ubuntu24"
        

        A definição runtime_version suporta semver.

    • Incluir a versão mais recente suportada do Node.js no ficheiro package.json da sua aplicação através do campo engines. Quando usa o campo engines para especificar uma versão, a definição runtime_version tem precedência. Para evitar falhas inesperadas, recomendamos que especifique uma versão do Node.js no campo engines, juntamente com runtime_version. Por exemplo:

        {
          "engines": {
            "node": "24.x"
          }
        }
      

      A propriedade engines.node pode ser um intervalo semver. Se especificar esta propriedade, o tempo de execução transfere e instala a versão mais recente do Node.js que corresponde ao intervalo semver. Se não for encontrada nenhuma correspondência, a aplicação não é implementada e o tempo de execução devolve um erro.

Versões de tempo de execução anteriores

Para o tempo de execução do Node.js versão 16 e anterior, especifique uma versão no ficheiro package.json da sua aplicação através do campo engines.

O exemplo seguinte configura o tempo de execução para usar a versão do Node 9:

{
  "engines": {
    "node": "9.x"
  }
}

A propriedade engines.node pode ser um intervalo semver. Se especificar esta propriedade, o tempo de execução transfere e instala a versão mais recente do Node.js que corresponde ao intervalo semver. Se não for encontrada nenhuma correspondência, a implementação da aplicação falha e o tempo de execução devolve uma mensagem de erro.

Suporte para outros tempos de execução do Node.js

Se precisar de usar uma versão do Node.js que não seja suportada, pode criar um tempo de execução personalizado e selecionar uma imagem base válida com a versão do Node.js de que precisa.

Para imagens base fornecidas pela Google ou imagens base do Docker Node.js, consulte o artigo Criar tempos de execução personalizados.

Gestor de pacotes

Durante a implementação, o tempo de execução usa o gestor de pacotes npm, yarn ou Pnpm para instalar dependências e iniciar a aplicação. O gestor de pacotes é definido com a seguinte lógica:

  • O gestor de pacotes predefinido é npm.
  • Se um ficheiro yarn.lock estiver presente no diretório raiz da sua aplicação, o tempo de execução usa o gestor de pacotes yarn.
  • Apenas para a versão 18 e posteriores do Node.js, se existir um ficheiro pnpm-lock.yaml no diretório raiz da sua aplicação, o tempo de execução usa o gestor de pacotes Pnpm.
  • Se existirem um package-lock.json e um yarn.lock ou um pnpm-lock.yaml, a implementação falha com um erro. Se precisar do ficheiro package-lock.json, tem de especificar os outros ficheiros do gestor de pacotes na secção skip_files do ficheiro app.yaml para resolver que gestor de pacotes usar.

Versão do gestor de pacotes

A imagem de tempo de execução destina-se a usar a versão yarn mais recente e a versão npm que está disponível na versão LTS mais recente do Node.js.

Pode especificar uma versão diferente do gestor de pacotes a usar no ficheiro package.json da sua aplicação através do campo engines. Neste caso, o tempo de execução garante que o gestor de pacotes usado para a implementação tem uma versão que corresponde à especificação indicada no campo engines.

Se forem especificadas as versões yarn e npm, apenas o gestor de pacotes usado para a implementação é atualizado, se necessário. Isto poupa tempo de implementação, pois não instala uma versão personalizada de um gestor de pacotes se não estiver a ser usada para implementar a sua aplicação.

O exemplo seguinte configura o tempo de execução para usar uma versão personalizada do npm:

{
  "engines": {
    "npm": "5.x"
  }
}

O exemplo seguinte configura o tempo de execução para usar uma versão personalizada de yarn:

{
  "engines": {
    "yarn": ">=1.0.0 <2.0.0"
  }
}

As propriedades engines.npm e engines.yarn podem ser um intervalo semver.

Dependências

Durante a implementação, o tempo de execução usa o gestor de pacotes npm ou yarn para instalar dependências executando npm install ou yarn install. Consulte a secção Gestor de pacotes para ver mais informações sobre como o tempo de execução seleciona o gestor de pacotes a usar.

Além disso, para mais informações sobre a gestão de pacotes Node.js no Google App Engine, consulte o artigo Usar bibliotecas Node.js.

Para permitir a utilização de pacotes Node.js que requerem extensões nativas, os pacotes Ubuntu seguintes estão pré-instalados na imagem Docker.

  • build-essential
  • ca-certificates
  • curl
  • git
  • imagemagick
  • libkrb5-dev
  • netbase
  • python

Se a sua aplicação precisar de dependências adicionais ao nível do sistema operativo, tem de usar um tempo de execução personalizado baseado neste tempo de execução para instalar os pacotes adequados.

Script de compilação do NPM

Para o tempo de execução do Node.js versão 18 e posterior, o ambiente de tempo de execução executa npm run build se for detetado um script build em package.json por predefinição. Se precisar de controlo adicional sobre os passos de compilação antes de iniciar a aplicação, pode fornecer um passo de compilação personalizado adicionando um script gcp-build ao ficheiro package.json.

Para impedir que a compilação execute o script npm run build, tem de:

  • Adicione um script gcp-build com um valor vazio no seu ficheiro package.json: "gcp-build":"".
  • Adicione a variável de ambiente GOOGLE_NODE_RUN_SCRIPTS com um valor vazio no seu ficheiro app.yaml.

    build_env_variables:
      GOOGLE_NODE_RUN_SCRIPTS: ''
    
Para ver detalhes sobre a especificação de variáveis do ambiente de compilação, consulte a secção build_env_variables no ficheiro app.yaml.

Arranque da aplicação

O tempo de execução inicia a sua aplicação através de npm start, que usa o comando especificado em package.json. Por exemplo:

"scripts": {
  "start": "node app.js"
}

O script de início deve iniciar um servidor Web que responda a pedidos HTTP na porta especificada pela variável de ambiente PORT, normalmente 8080.

Prolongar o tempo de funcionamento

Pode usar tempos de execução personalizados para adicionar funcionalidade adicional a uma app Node.js em execução no ambiente flexível do App Engine. Para configurar um tempo de execução personalizado, substitua a seguinte linha no ficheiro app.yaml:

runtime: nodejs

com esta linha:

runtime: custom

Também tem de adicionar ficheiros Dockerfile e .dockerignore no mesmo diretório que contém o ficheiro app.yaml.

Visite a documentação de tempos de execução personalizados para saber como definir um Dockerfile num tempo de execução personalizado.

HTTPS e proxies de encaminhamento

O App Engine termina a ligação HTTPS no balanceador de carga e encaminha o pedido para a sua aplicação. Algumas aplicações precisam de determinar o IP e o protocolo do pedido original. O endereço IP do utilizador está disponível no cabeçalho X-Forwarded-For padrão. As aplicações que requerem estas informações devem configurar a respetiva estrutura Web para confiar no proxy.

Com o Express.js, use a definição trust proxy:

app.set('trust proxy', true);

Para ver informações sobre a aplicação de ligações HTTPS, consulte o artigo Como são processados os pedidos.

Variáveis de ambiente

As seguintes variáveis de ambiente são definidas pelo ambiente de tempo de execução:

Variável de ambiente Descrição
GAE_INSTANCE O nome da instância atual.
GAE_MEMORY_MB A quantidade de memória disponível para o processo da aplicação.
GAE_SERVICE O nome do serviço especificado no ficheiro app.yaml da sua aplicação ou, se não for especificado nenhum nome do serviço, é definido como default.
GAE_VERSION A etiqueta da versão da aplicação atual.
GOOGLE_CLOUD_PROJECT O ID do projeto associado à sua aplicação, que é visível na Google Cloud consola
NODE_ENV Quando a sua app é implementada, o valor é production.
PORT A porta que vai receber pedidos HTTP. Definido como 8080.

Pode definir variáveis de ambiente adicionais com app.yaml.

Servidor de metadados

Cada instância da sua aplicação pode usar o servidor de metadados do Compute Engine para consultar informações sobre a instância, incluindo o respetivo nome do anfitrião, endereço IP externo, ID da instância, metadados personalizados e informações da conta de serviço. O App Engine não lhe permite definir metadados personalizados para cada instância, mas pode definir metadados personalizados ao nível do projeto e lê-los a partir das instâncias do App Engine e do Compute Engine.

Esta função de exemplo usa o servidor de metadados para obter o endereço IP externo da instância.

import express from 'express';
import fetch from 'node-fetch';

const app = express();
app.enable('trust proxy');

const METADATA_NETWORK_INTERFACE_URL =
  'http://metadata/computeMetadata/v1/' +
  '/instance/network-interfaces/0/access-configs/0/external-ip';

const getExternalIp = async () => {
  const options = {
    headers: {
      'Metadata-Flavor': 'Google',
    },
    json: true,
  };

  try {
    const response = await fetch(METADATA_NETWORK_INTERFACE_URL, options);
    const ip = await response.json();
    return ip;
  } catch (err) {
    console.log('Error while talking to metadata server, assuming localhost');
    return 'localhost';
  }
};

app.get('/', async (req, res, next) => {
  try {
    const externalIp = await getExternalIp();
    res.status(200).send(`External IP: ${externalIp}`).end();
  } catch (err) {
    next(err);
  }
});

const PORT = parseInt(process.env.PORT) || 8080;
app.listen(PORT, () => {
  console.log(`App listening on port ${PORT}`);
  console.log('Press Ctrl+C to quit.');
});