O ambiente de execução do Node.js

Visão geral

O ambiente de execução do Node.js é a pilha de software responsável por instalar o código do aplicativo e as dependências dele, além de executá-lo. O ambiente de execução é declarado em app.yaml como runtime: nodejs:

runtime: nodejs
env: flex

No ambiente flexível, os tempos de execução são criados usando o Docker. O ambiente de execução do Node.js tem como base o Ubuntu 16.04, e o respectivo código-fonte está disponível para acesso público no GitHub (ambos em inglês).

Gerenciador de pacotes

Durante a implantação, o ambiente de execução usa um dos gerenciadores de pacotes npm (em inglês) ou yarn 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.
  • Se houver um package-lock.json e um yarn.lock, ocorrerá um erro na implantação. Se os dois arquivos forem necessários, será possível adicionar um deles à seção skip_files do arquivo app.yaml para decidir qual gerenciador de pacotes usar.

Mecanismos

Versão do Node.js

O ideal é que o mecanismo padrão do Node.js seja a versão mais recente do LTS (em inglês). Especifique uma versão diferente do Node.js no arquivo package.json do aplicativo usando o campo engines. Para evitar interrupções inesperadas, especifique uma versão do Node.js.

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ê especificá-lo, 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 deixará de ser implantado, e o ambiente de execução retornará uma mensagem de erro.

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 (em inglês).

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.

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.

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

Use o ambiente de execução padrão do Node.js para criar um ambiente de execução personalizado. Para fazer isso, use gcloud beta app gen-config --custom para criar os arquivos Dockerfile e .dockerignore de base. Depois, será possível personalizar esses arquivos conforme necessário. Observe que, se você criar Dockerfile, precisa especificar runtime: custom em vez de runtime: nodejs no arquivo app.yaml.

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 = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`App listening on port ${PORT}`);
  console.log('Press Ctrl+C to quit.');
});