Ambiente de execução do Node.js

O ambiente de execução do Node.js é a pilha de software responsável por instalar o código e as dependências do aplicativo e, em seguida, executá-lo no ambiente flexível.

Versões do Node.js

O Node.js 20 usa buildpacks. O mecanismo padrão do Node.js usa a versão mais recente do LTS. Para ver a lista completa de versões compatíveis do Node.js e a versão correspondente do Ubuntu, consulte a Programação de suporte do ambiente de execução.

Para usar uma versão compatível do Node.js, é preciso:

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

  • Inclua as configurações runtime_config e operating_system no arquivo app.yaml para especificar um sistema operacional.

  • Opcionalmente, especifique uma versão:

    • Adicionando a configuração runtime_version ao seu arquivo app.yaml. Por padrão, a versão mais recente do Node.js será usada se a configuração runtime_version não for especificada. Exemplo:

      • Para especificar o Node.js 20 no Ubuntu 22:

          runtime: nodejs
          env: flex
        
          runtime_config:
              operating_system: "ubuntu22"
              runtime_version: "20"
        
      • Para especificar a versão mais recente compatível do Node.js no Ubuntu 22:

          runtime: nodejs
          env: flex
        
          runtime_config:
              operating_system: "ubuntu22"
        
    • Inclua a versão mais recente do Node.js com suporte no arquivo package.json do aplicativo usando o campo engines. Ao usar o campo engines para especificar uma versão, a configuração runtime_version tem prioridade. Para evitar interrupções inesperadas, é recomendável especificar uma versão do Node.js no campo engines. Exemplo:

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

      A propriedade engines.node pode ser um intervalo semver. Se você especificar essa propriedade, o ambiente de execução fará o download e instalará a versão mais recente do Node.js correspondente ao intervalo semver. Se nenhuma correspondência for encontrada, o aplicativo não será implantado e o ambiente de execução retornará um erro.

Versões anteriores do ambiente de execução

Para o ambiente de execução do Node.jsversão 16 e anteriores, especifique uma versão no arquivo package.json usando o campo engines.

O exemplo a seguir configura o ambiente de execução para usar a versão mais recente do Node 9.

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

A propriedade engines.node pode ser um intervalo semver. Se você especificar essa propriedade, o ambiente de execução fará o download e instalará a versão mais recente do Node.js correspondente ao intervalo semver. Se nenhuma correspondência for encontrada, ocorrerá uma falha na implantação do aplicativo e o ambiente de execução retornará uma mensagem de erro.

Suporte para outros ambientes de execução Node.js

Se você precisa usar uma versão do Node.js que não é compatível, crie um ambiente de execução personalizado e selecione uma imagem de base válida com a versão do Node.js necessária.

Para imagens de base fornecidas pelo Google ou imagens de base do Docker Go, consulte Como criar ambientes de execução personalizados.

Gerenciador de pacotes

Durante a implantação, o ambiente de execução usa um dos gerenciadores de pacotes npm, yarn ou Pnpm para instalar dependências e iniciar o aplicativo. O gerenciador de pacotes é definido com a seguinte lógica:

  • O comportamento padrão é npm.
  • Se um arquivo yarn.lock estiver no diretório raiz do aplicativo, o ambiente de execução usará o gerenciador de pacotes yarn.
  • Apenas para o Node.js versão 18 e mais recentes, se um arquivo pnpm-lock.yaml estiver presente no diretório raiz do aplicativo, o ambiente de execução vai usar o gerenciador de pacotes Pnpm.
  • Se houver um package-lock.json e um yarn.lock ou pnpm-lock.yaml, ocorrerá um erro na implantação. Se você precisar do arquivo package-lock.json você precisa especificar os outros arquivos do gerenciador de pacotes no arquivo skip_files da sua app.yaml para decidir qual gerenciador de pacotes usar.

Versão do gerenciador de pacotes

O ideal é que a imagem do ambiente de execução use a versão mais recente do yarn e a versão do npm disponível na versão mais recente do LTS do Node.js (em inglês).

Para especificar uma versão diferente do gerenciador de pacotes para usar no package.json do aplicativo, use o campo engines campo. Nesse caso, o ambiente de execução garantirá que o gerenciador de pacotes usado na implantação tenha uma versão correspondente à especificação listada no campo engines.

Caso seja fornecida uma especificação de versão yarn e npm, somente o gerenciador de pacotes usado para a implantação será atualizado, se necessário. Isso economiza tempo de implantação, não instalando uma versão personalizada de um gerenciador de pacotes, caso ela não esteja sendo usada para implantar o aplicativo.

No exemplo a seguir, o ambiente de execução é configurado para usar uma versão personalizada de npm:

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

No próximo exemplo, o ambiente de execução é usado 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 implantação, o ambiente de execução usará um dos gerenciadores de pacotes npm ou yarn para instalar dependências executando npm install ou yarn install. Consulte a seção Gerenciador de pacotes para mais informações sobre como o ambiente de execução seleciona o gerenciador de pacotes a ser usado.

Além disso, para mais informações sobre como gerenciar pacotes do Node.js no Google App Engine, consulte Como usar bibliotecas do Node.js.

Para que o uso de pacotes Node.js que exigem extensões nativas seja possível, os seguintes pacotes Ubuntu são pré-instalados na imagem do Docker.

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

Se o aplicativo exigir outras dependências no nível do sistema operacional, você precisará usar um ambiente de execução personalizado com base nesse ambiente de execução para instalar os pacotes apropriados.

Script de build do NPM

No ambiente de execução do Node.js versão 18 e mais recentes, o ambiente de execução vai executar npm run build se um script build for detectado em package.json por padrão. Se você precisar de mais controle sobre as etapas do build antes de iniciar o aplicativo, forneça uma etapa de build personalizada adicionando um script gcp-build ao arquivo package.json.

Para evitar que sua versão execute o script npm run build, siga um destes procedimentos:

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

    build_env_variables:
      GOOGLE_NODE_RUN_SCRIPTS: ''
    
Para ver detalhes sobre como especificar variáveis de ambiente de build, consulte a seção build_env_variables no arquivo app.yaml.

Inicialização do aplicativo

O ambiente de execução inicia o aplicativo usando npm start, que usa o comando especificado em package.json. Exemplo:

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

É necessário que seu script de inicialização inicie um servidor da Web que responda a solicitações HTTP na porta especificada pela variável de ambiente PORT, geralmente 8080.

Como ampliar o tempo de execução

É possível usar ambientes de execução personalizados para adicionar mais funcionalidades em um aplicativo Node.js em execução no ambiente flexível do App Engine. Para configurar um ambiente de execução personalizado, substitua a seguinte linha no arquivo app.yaml:

runtime: nodejs

pela linha:

runtime: custom

Também é necessário adicionar os arquivos Dockerfile e .dockerignore no mesmo diretório que contém o arquivo app.yaml.

Acesse a documentação Ambientes de execução personalizados para saber como definir um Dockerfile em um ambiente de execução personalizado.

HTTPS e proxies de encaminhamento

No App Engine, a conexão HTTPS é encerrada no balanceador de carga e a solicitação é encaminhada para o seu aplicativo. Para alguns aplicativos, é necessário determinar o IP e o protocolo de solicitação originais. O endereço IP do usuário está disponível no cabeçalho X-Forwarded-For padrão. Os aplicativos que precisam dessa informação precisam configurar a biblioteca da Web para confiar no proxy.

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

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

Para informações sobre como impor conexões HTTPS, consulte Como as solicitações são processadas.

Variáveis de ambiente

As variáveis de ambiente a seguir são definidas pelo ambiente do ambiente 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 do aplicativo.
GAE_SERVICE O nome do serviço especificado no arquivo app.yaml do aplicativo. Se nenhum nome de serviço for especificado, será definido como default.
GAE_VERSION O rótulo da versão do aplicativo atual.
GOOGLE_CLOUD_PROJECT O ID do projeto associado ao seu aplicativo, que fica visível no Console do Google Cloud
NODE_ENV Quando o app for implantado, o valor será production.
PORT A porta que receberá as solicitações HTTP. Defina como 8080.

É possível definir mais variáveis de ambiente com app.yaml.

Servidor de metadados

Cada instância do aplicativo pode usar o servidor de metadados do Compute Engine para consultar informações sobre a instância, inclusive o nome do host, o endereço IP externo, o código da instância, os metadados personalizados e as informações da conta de serviço. Não é possível definir metadados personalizados para cada instância no App Engine. Em vez disso, defina metadados personalizados para o projeto e leia esses metadados das instâncias do App Engine e do Compute Engine.

A função de exemplo abaixo usa o servidor de metadados para receber o endereço IP externo da instância.

const express = require('express');
const fetch = require('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.');
});