O tempo de execução do Ruby

O tempo de execução do Ruby é 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 Ruby

O Ruby 3.4 usa buildpacks. Para ver a lista completa das versões do Ruby suportadas e a versão correspondente do Ubuntu, consulte a Programação de suporte de tempo de execução.

Para usar uma versão Ruby suportada, tem de:

  • Especifique uma versão do Ruby no seu Gemfile.

    RUBY VERSION
      ruby 3.4.x
    
  • Instale a versão 420.0.0 ou posterior da CLI gcloud. Pode atualizar as ferramentas da CLI executando o comando gcloud components update. Para ver a versão instalada, pode executar o comando gcloud version.

  • Especifique a definição operating_system no ficheiro app.yaml:

      runtime: ruby
      env: flex
    
      runtime_config:
          operating_system: "ubuntu22"
    
  • Opcionalmente, pode especificar uma versão do intérprete Ruby através de um ficheiro .ruby-version no diretório da aplicação. Por exemplo, 3.4.x

Versões anteriores

Para usar a versão 3.1 e anteriores do tempo de execução do Ruby, especifique uma versão do intérprete do Ruby através de um ficheiro .ruby-version no diretório da sua aplicação.

Quando este ficheiro está presente, o tempo de execução instala a versão pedida do Ruby quando implementa a sua aplicação através do rbenv. Se não for possível instalar a versão pedida, o App Engine apresenta uma mensagem de erro durante a implementação.

Se não fornecer um ficheiro .ruby-version, o tempo de execução do Ruby usa a versão 2.7 por predefinição. Tenha em atenção que a predefinição pode ser alterada em qualquer altura, pelo que é recomendável que a sua app especifique uma versão do Ruby.

Suporte para outros tempos de execução do Ruby

Se precisar de usar uma versão do Ruby 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 Ruby de que precisa.

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

Dependências

O tempo de execução procura um ficheiro Gemfile no diretório de origem da sua aplicação e usa Bundler para instalar todas as dependências antes de iniciar a aplicação. Para mais informações sobre como declarar e gerir pacotes, consulte o artigo Usar bibliotecas Ruby.

Usar bibliotecas C com Ruby

Para bibliotecas Ruby que requerem extensões C, os cabeçalhos para a versão atual do Ruby e os seguintes pacotes Ubuntu estão pré-instalados no sistema.

  • autoconf
  • build-essential
  • ca-certificates
  • cmake
  • curl
  • file
  • git
  • imagemagick
  • libcurl3
  • libcurl3-gnutls
  • libcurl4-openssl-dev
  • libffi-dev
  • libgdbm-dev
  • libgit2-dev
  • libgmp-dev
  • libicu-dev
  • libjemalloc-dev
  • libjemalloc1
  • libmagickwand-dev
  • libmysqlclient-dev
  • libncurses5-dev
  • libpq-dev
  • libqdbm-dev
  • libreadline6-dev
  • libsqlite3-dev
  • libssl-dev
  • libxml2-dev
  • libxslt-dev
  • libyaml-dev
  • libz-dev
  • systemtap
  • tzdata

Estes pacotes permitem a instalação das bibliotecas Ruby mais populares. Se a sua aplicação requerer dependências adicionais ao nível do sistema operativo, tem de usar um tempo de execução personalizado com base neste tempo de execução para instalar os pacotes adequados.

Arranque da aplicação

O tempo de execução inicia a sua aplicação através do entrypoint definido em app.yaml. O ponto de entrada deve iniciar um processo que responde a pedidos HTTP na porta definida pela variável de ambiente PORT. Por exemplo:

entrypoint: bundle exec rails server -p $PORT

A maioria das aplicações Web usa um servidor Web compatível com Rack, como Puma, Unicorn ou Thin.

Tem de adicionar o servidor como uma dependência no ficheiro de configuração Gemfile da sua aplicação. O tempo de execução instala todas as dependências antes de o ponto de entrada ser chamado.

source "https://rubygems.org"

gem "rack"
gem "puma"

Um exemplo de ponto de entrada que usa o puma para uma aplicação Rails:

entrypoint: bundle exec rails server Puma -p $PORT

Um ponto de entrada de exemplo que usa o puma para qualquer aplicação Rack:

entrypoint: bundle exec rackup -s Puma -p $PORT

Para aplicações que podem processar pedidos sem um servidor Rack, basta executar um script Ruby:

entrypoint: bundle exec ruby app.rb

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
PORT A porta que vai receber pedidos HTTP.
RACK_ENV Definido como production.
RAILS_ENV Definido como production.
RAILS_SERVE_STATIC_FILES Definido como true.

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 suas instâncias do App Engine e Compute Engine.

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

require "sinatra"
require "net/http"

get "/" do
  uri = URI.parse(
    "http://metadata.google.internal/computeMetadata/v1" +
    "/instance/network-interfaces/0/access-configs/0/external-ip"
  )

  request = Net::HTTP::Get.new uri.path
  request.add_field "Metadata-Flavor", "Google"

  http = Net::HTTP.new uri.host, uri.port

  response = http.request request

  "External IP: #{response.body}"
end