Esecuzione di Rails nell'ambiente Cloud Run

Scopri come eseguire il deployment di un'applicazione Rails di esempio in Cloud Run e come integrare database gestiti, archiviazione di oggetti, secret criptati e creare pipeline con il serverless computing.

Il deployment di applicazioni Rails comporta l'integrazione di più servizi insieme per formare un progetto coeso. Questo tutorial presuppone che tu abbia familiarità con lo sviluppo web di Rails.

Questo tutorial richiede Ruby 3.0 o versioni successive (è supportato anche Ruby 2.7, consulta la sezione Comprendere il codice) e Rails 6 o versioni successive.

Diagramma che mostra l'architettura del deployment.
Il sito Rails viene gestito da Cloud Run, che utilizza più servizi di backup per archiviare diversi tipi di dati (informazioni di database relazionale, asset multimediali, secret di configurazione e immagini container). I servizi di backend vengono aggiornati da Cloud Build come parte di un'attività di creazione e migrazione.

Obiettivi

  • Creare e connettere un database Cloud SQL ad Active Record
  • Creare e utilizzare Secret Manager per archiviare e accedere in modo sicuro a una chiave master Rails
  • Ospitare file multimediali e file caricati dagli utenti su Cloud Storage da Active Storage
  • Usa Cloud Build per automatizzare le migrazioni di build e database
  • Esegui il deployment di un'app Rails in Cloud Run

Costi

Prima di iniziare

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the Cloud Run, Cloud SQL, Cloud Build, Secret Manager, and Compute Engine APIs.

    Enable the APIs

  5. Install the Google Cloud CLI.
  6. To initialize the gcloud CLI, run the following command:

    gcloud init
  7. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  8. Make sure that billing is enabled for your Google Cloud project.

  9. Enable the Cloud Run, Cloud SQL, Cloud Build, Secret Manager, and Compute Engine APIs.

    Enable the APIs

  10. Install the Google Cloud CLI.
  11. To initialize the gcloud CLI, run the following command:

    gcloud init
  12. Assicurati di disporre di autorizzazioni sufficienti per l'account utilizzato per questo tutorial.

Preparazione dell'ambiente

Imposta il progetto predefinito

Imposta la configurazione predefinita del progetto per l'interfaccia a riga di comando gcloud eseguendo il comando seguente:

gcloud config set project PROJECT_ID

Sostituisci PROJECT_ID con l'ID progetto Google Cloud che hai appena creato

Clonazione dell'app Rails

Il codice per l'app di esempio Rails si trova nel repository GoogleCloudPlatform/ruby-docs-samples su GitHub.

  1. Clona il repository:

    git clone https://github.com/GoogleCloudPlatform/ruby-docs-samples.git
    
  2. Vai alla directory che contiene il codice di esempio ed esegui questi comandi per assicurarti che l'applicazione sia configurata correttamente con le gemme e le dipendenze necessarie:

    Linux/macOS

    cd ruby-docs-samples/run/rails
    bundle install
    

    Windows

    cd ruby-docs-samples\run\rails
    bundle install
    

Preparazione dei servizi di supporto

Questo tutorial utilizza diversi servizi Google Cloud per fornire il database, l'archiviazione multimediale e l'archiviazione segreta che supportano il progetto Rails di cui è stato eseguito il deployment. Il deployment di questi servizi è previsto in un'area geografica specifica. Per aumentare l'efficienza tra i servizi, è preferibile eseguire il deployment di tutti i servizi nella stessa area geografica. Per ulteriori informazioni sull'area geografica più vicina a te, consulta Prodotti disponibili per area geografica.

Configura un'istanza Cloud SQL per PostgreSQL

Rails supporta più database relazionali, inclusi diversi offerti da Cloud SQL. Questo tutorial utilizza PostgreSQL, un database open source comunemente utilizzato dalle app Rails.

Le seguenti sezioni descrivono la creazione di un'istanza, un database e un utente di database PostgreSQL per la tua app Rails.

Crea un'istanza PostgreSQL

Console

  1. In Google Cloud Console, vai alla pagina Istanze Cloud SQL.

    Vai alla pagina Istanze Cloud SQL

  2. Fai clic su Crea istanza.

  3. Fai clic su Scegli PostgreSQL.

  4. Nel campo ID istanza, inserisci un nome per l'istanza (INSTANCE_NAME).

  5. Nel campo Password, inserisci una password per l'utente postgres.

  6. Utilizza i valori predefiniti per gli altri campi.

  7. Fai clic su Crea istanza.

gcloud

  • Crea l'istanza PostgreSQL:

    gcloud sql instances create INSTANCE_NAME \
        --database-version POSTGRES_12 \
        --tier db-f1-micro \
        --region REGION
    

    Sostituisci quanto segue:

    La creazione dell'istanza richiede poco tempo per la preparazione e l'uso.

Crea un database

Console

  1. In Google Cloud Console, vai alla pagina Istanze Cloud SQL.

    Vai alla pagina Istanze Cloud SQL

  2. Seleziona l'istanza INSTANCE_NAME.

  3. Vai alla scheda Database.

  4. Fai clic su Crea database.

  5. Nella finestra di dialogo Nome database, inserisci DATABASE_NAME.

  6. Fai clic su Crea.

gcloud

  • Crea il database all'interno dell'istanza creata di recente:

    gcloud sql databases create DATABASE_NAME \
        --instance INSTANCE_NAME
    

    Sostituisci DATABASE_NAME con un nome del database all'interno dell'istanza.

Crea un utente

Genera una password casuale per l'utente del database e scrivila in un file denominato dbpassword:

cat /dev/urandom | LC_ALL=C tr -dc '[:alpha:]'| fold -w 50 | head -n1 > dbpassword

Console

  1. In Google Cloud Console, vai alla pagina Istanze Cloud SQL.

    Vai alla pagina Istanze Cloud SQL

  2. Seleziona l'istanza INSTANCE_NAME.

  3. Vai alla scheda Utenti.

  4. Fai clic su Aggiungi account utente.

  5. Nella finestra di dialogo Autenticazione integrata:

    1. Inserisci il nome utente DATABASE_USERNAME.
    2. Inserisci i contenuti del file dbpassword come password PASSWORD.
  6. Fai clic su Aggiungi.

gcloud

  • Crea l'utente all'interno dell'istanza creata di recente e imposta la relativa password come contenuto di dbpassword:

    gcloud sql users create DATABASE_USERNAME \
       --instance=INSTANCE_NAME --password=$(cat dbpassword)
    

    Sostituisci DATABASE_USERNAME con un nome per l'utente all'interno dell'istanza.

Configurare un bucket Cloud Storage

Con Cloud Storage puoi ospitare asset statici e multimediali caricati dagli utenti e archiviati in oggetti ad alta disponibilità.

Console

  1. In the Google Cloud console, go to the Cloud Storage Buckets page.

    Go to Buckets page

  2. Click Create bucket.
  3. On the Create a bucket page, enter your bucket information. To go to the next step, click Continue.
    • For Name your bucket, enter a name that meets the bucket naming requirements.
    • For Location, select the following: us-central1
    • For Choose a default storage class for your data, select the following: Standard.
    • For Choose how to control access to objects, select an Access control option.
    • For Advanced settings (optional), specify an encryption method, a retention policy, or bucket labels.
  4. Click Create.

gcloud

Lo strumento a riga di comando gsutil è stato installato durante l'installazione dell'interfaccia a riga di comando gcloud.

  • Creare un bucket Cloud Storage. Per creare un nome univoco per il bucket Cloud Storage, utilizza PROJECT_ID e un suffisso a tua scelta, MEDIA_BUCKET_SUFFIX. In Cloud Storage, i nomi dei bucket devono essere univoci a livello globale.

    gsutil mb -l REGION gs://PROJECT_ID-MEDIA_BUCKET_SUFFIX
    

Dopo aver creato un bucket, per rendere pubbliche le immagini caricate, modifica le autorizzazioni degli oggetti immagine in modo che siano leggibili da tutti.

Console

  1. In Google Cloud Console, vai alla pagina Bucket di Cloud Storage.

    Vai a Bucket

  2. Nell'elenco dei bucket, fai clic sul nome del bucket che vuoi rendere pubblico.

  3. Seleziona la scheda Autorizzazioni nella parte superiore della pagina.

  4. Fai clic sul pulsante Aggiungi membri.

    Viene visualizzata la finestra di dialogo Aggiungi membri.

  5. Nel campo Nuovi membri, inserisci allUsers.

  6. Nel menu a discesa Seleziona un ruolo, seleziona il sottomenu Cloud Storage e fai clic sull'opzione Visualizzatore oggetti Storage.

  7. Fai clic su Salva.

Dopo la condivisione pubblica, per ogni oggetto nella colonna accesso pubblico è visualizzata un'icona link. Puoi fare clic su questa icona per recuperare l'URL dell'oggetto.

Per scoprire come ottenere informazioni dettagliate sugli errori sulle operazioni Ruby non riuscite in Google Cloud Console, consulta la sezione Risoluzione dei problemi.

gcloud

  • Utilizza il comando gsutil iam ch per rendere pubblici tutti gli oggetti. Utilizza il valore di MEDIA_BUCKET_SUFFIX che hai utilizzato durante la creazione del bucket.

    gsutil iam ch allUsers:objectViewer gs://PROJECT_ID-MEDIA_BUCKET_SUFFIX
    

Archivia valori segreti in Secret Manager

Ora che i servizi di supporto sono configurati, Rails richiede informazioni sicure, come le password, per accedere a questi servizi. Anziché inserire questi valori direttamente nel codice sorgente di Rails, questo tutorial utilizza Credenziali per le linee guida e Secret Manager per archiviare queste informazioni in modo sicuro.

Crea file di credenziali criptate e chiave di archiviazione come secret di Secret Manager

Rails memorizza i secret in un file criptato chiamato 'config/credentials.yml.enc'. Il file può essere decriptato con il config/master.key locale o la variabile di ambiente ENV[“RAILS_MASTER_KEY”]. Nel file delle credenziali, puoi archiviare la password del database delle istanze Cloud SQL e altre chiavi di accesso per le API esterne.

Puoi archiviare questa chiave in modo sicuro in Secret Manager. Quindi, puoi concedere a Cloud Run e Cloud Build l'accesso alla chiave concedendo l'accesso ai rispettivi account di servizio. Gli account di servizio sono identificati da un indirizzo email che contiene il numero di progetto.

  1. Genera il file config/credentials.yml.enc con il seguente comando:

    bin/rails credentials:edit
    

    Se la file principale non è definita, il comando creerà un file config/master.key e, se il file non esiste, verrà creato un file config/credentials.yml.enc. Nel file $EDITOR si aprirà un file temporaneo con i contenuti decriptati da aggiungere ai secret.

  2. Copia e incolla la password del database dell'istanza PostgreSQL appena creata dal file dbpassword nel file delle credenziali:

    secret_key_base: GENERATED_VALUE
    gcp:
      db_password: PASSWORD
    

    È possibile accedere ai secret con Rails.application.credentials. Ad esempio, Rails.application.credentials.secret_key_base dovrebbe restituire la base della chiave segreta dell'applicazione e Rails.application.credentials.gcp[:db_passsword] dovrebbe restituire la password del tuo database.

  3. Le chiavi config/credentials/yml.enc sono archiviate in forma criptata, ma config/master.key possono essere archiviate in Secret Manager.

    Console

    1. In Google Cloud Console, vai alla pagina di Secret Manager.

      Vai alla pagina Secret Manager

    2. Fai clic su Crea secret.

    3. Nel campo Nome, inserisci un nome per il secret RAILS_SECRET_NAME.

    4. Nella finestra di dialogo Valore secret, incolla il valore mater.key nella casella.

    5. Fai clic su Crea secret.

    6. Nella pagina dei dettagli del secret, prendi nota del numero del progetto:

      projects/PROJECTNUM/secrets/RAILS_SECRET_NAME

    7. Nella scheda Autorizzazioni, fai clic su Aggiungi membro

    8. Nel campo Nuovi membri, inserisci PROJECTNUM-compute@developer.gserviceaccount.com, quindi premi Enter.

    9. Nel campo Nuovi membri, inserisci PROJECTNUM@cloudbuild.gserviceaccount.com, quindi premi Enter.

    10. Nel menu a discesa Ruolo, seleziona Secret Manager Secret Manager.

    11. Fai clic su Salva.

    gcloud

    1. Crea un nuovo secret con il valore di config/master.key:

      gcloud secrets create RAILS_SECRET_NAME --data-file config/master.key
      

      Sostituisci RAILS_SECRET_NAME con un nome per il nuovo secret.

    2. Per confermare la creazione del secret, controlla che:

      gcloud secrets describe RAILS_SECRET_NAME
      
      gcloud secrets versions access latest --secret RAILS_SECRET_NAME
      
    3. Recupera il valore del numero del progetto:

      gcloud projects describe PROJECT_ID --format='value(projectNumber)'
      
    4. Concedi l'accesso al secret all'account di servizio Cloud Run:

      gcloud secrets add-iam-policy-binding RAILS_SECRET_NAME \
          --member serviceAccount:PROJECTNUM-compute@developer.gserviceaccount.com \
          --role roles/secretmanager.secretAccessor
      

      Sostituisci PROJECTNUM con il valore del numero di progetto riportato sopra.

    5. Concedi l'accesso al secret all'account di servizio Cloud Build:

      gcloud secrets add-iam-policy-binding RAILS_SECRET_NAME \
          --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \
          --role roles/secretmanager.secretAccessor
      

      Nell'output, conferma che bindings elenca i due account di servizio come membri.

Collega l'app Rails al database e all'archiviazione di produzione

Questo tutorial utilizza un'istanza PostgreSQL come database di produzione e Cloud Storage come backend di archiviazione. Affinché Rails si connetta al database e al bucket di archiviazione appena creati, devi specificare tutte le informazioni necessarie per accedervi nel file .env. Il file .env contiene la configurazione per le variabili di ambiente dell'applicazione. L'applicazione leggerà questo file utilizzando la gem dotenv. Poiché i secret sono archiviati in credentials.yml.enc e Secret Manager, .env non deve essere criptato perché non contiene credenziali sensibili.

  1. Per configurare l'app Rails in modo che si connetta al database e al bucket di archiviazione, apri il file .env.
  2. Modifica la configurazione del file .env come segue. Utilizza il valore di MEDIA_BUCKET_SUFFIX che hai utilizzato durante la creazione del bucket.

    PRODUCTION_DB_NAME: DATABASE_NAME
    PRODUCTION_DB_USERNAME: DATABASE_USERNAME
    CLOUD_SQL_CONNECTION_NAME: PROJECT_ID:REGION:INSTANCE_NAME
    GOOGLE_PROJECT_ID: PROJECT_ID
    STORAGE_BUCKET_NAME: PROJECT_ID-MEDIA_BUCKET_SUFFIX
    

    L'app Rails è ora configurata per utilizzare Cloud SQL e Cloud Storage durante il deployment in Cloud Run.

Concedi a Cloud SQL l'accesso a Cloud SQL

Affinché Cloud Build applichi le migrazioni del database, devi concedere le autorizzazioni per accedere a Cloud SQL a Cloud Build.

Console

  1. In Google Cloud Console, vai alla pagina Identity and Access Management.

    Vai alla pagina Identity and Access Management

  2. Per modificare la voce di un membro di PROJECTNUM@cloudbuild.gserviceaccount.com, fai clic su Modifica membro.

  3. Fai clic su Aggiungi un altro ruolo.

  4. Nella finestra di dialogo Seleziona un ruolo, seleziona Client Cloud SQL.

  5. Fai clic su Salva

gcloud

  • Concedi a Cloud Build l'autorizzazione per accedere a Cloud SQL:

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \
        --role roles/cloudsql.client
    

Deployment dell'app in Cloud Run

Dopo aver configurato i servizi di supporto, puoi eseguire il deployment dell'app come servizio Cloud Run.

  1. Utilizzando il modello cloudbuild.yaml fornito, usa Cloud Build per creare l'immagine, eseguire le migrazioni dei database e completare gli asset statici:

    gcloud builds submit --config cloudbuild.yaml \
        --substitutions _SERVICE_NAME=SERVICE_NAME,_INSTANCE_NAME=INSTANCE_NAME,_REGION=REGION,_SECRET_NAME=RAILS_SECRET_NAME
    

    Sostituisci SERVICE_NAME con il nome del tuo servizio. Il completamento di questa prima build richiede alcuni minuti. Se la build è scaduta, aumenta la durata del timeout inserendo --timeout=2000s nel comando di build riportato sopra.

  2. Quando la build ha esito positivo, esegui il deployment del servizio Cloud Run per la prima volta, impostando la regione, l'immagine di base e l'istanza Cloud SQL connessa del servizio:

    gcloud run deploy SERVICE_NAME \
         --platform managed \
         --region REGION \
         --image gcr.io/PROJECT_ID/SERVICE_NAME \
         --add-cloudsql-instances PROJECT_ID:REGION:INSTANCE_NAME \
         --allow-unauthenticated
    

    Dovresti vedere l'output che mostra il deployment riuscito, con un URL di servizio:

    Service [SERVICE_NAME] revision [SERVICE_NAME-00001-tug] has been deployed
     and is serving 100 percent of traffic at https://SERVICE_NAME-HASH-uc.a.run.app

  3. Per visualizzare il servizio di cui hai eseguito il deployment, vai all'URL del servizio.

    Screenshot della pagina di destinazione dell'applicazione dell'album gatto.
    Se l'URL del servizio mostra Album di foto di gatti, sei sulla home page dell'app.

  4. Prova a caricare una nuova foto. Se la foto viene caricata correttamente, il deployment dell'applicazione Rails è stato eseguito correttamente.

    Screenshot della pagina di destinazione dell'applicazione dell'album di un gatto con una foto.

Aggiornamento dell'applicazione in corso...

Sebbene i passaggi iniziali di provisioning e deployment fossero complessi, apportare aggiornamenti è un processo più semplice:

  1. Esegui lo script di creazione e migrazione di Cloud Build:

    gcloud builds submit --config cloudbuild.yaml \
         --substitutions _SERVICE_NAME=SERVICE_NAME,_INSTANCE_NAME=INSTANCE_NAME,_REGION=REGION,_SECRET_NAME=RAILS_SECRET_NAME
    
  2. Esegui il deployment del servizio, specificando solo l'area geografica e l'immagine:

    gcloud run deploy SERVICE_NAME \
         --platform managed \
         --region REGION \
         --image gcr.io/PROJECT_ID/SERVICE_NAME
    

Nozioni di base sul codice

L'app di esempio Rails è stata creata usando i comandi standard di Rails. I seguenti comandi creano l'app cat_album e utilizzano il comando scaffold per generare un modello, un controller e le visualizzazioni per la risorsa foto:

rails new cat_album
rails generate scaffold Photo caption:text

Connessione al database

Il file config/database.yml contiene la configurazione necessaria per accedere ai tuoi database in diversi ambienti (sviluppo, test, produzione). Ad esempio, il database di produzione è configurato per l'esecuzione in Cloud SQL per PostgreSQL. Il nome e il nome utente del database vengono impostati tramite le variabili di ambiente nel file .env, mentre la password del database viene archiviata nel file config/credentials.yml.enc, che richiede la decriptazione di RAILS_MASTER_KEY.

Quando l'app viene eseguita su Cloud Run (completamente gestito), si connette all'istanza PostgreSQL utilizzando un socket fornito dall'ambiente Cloud Run. Quando l'app è in esecuzione sulla tua macchina locale, si connette all'istanza PostgreSQL utilizzando il proxy di autenticazione Cloud SQL.

production:
  <<: *default
  database: <%= ENV["PRODUCTION_DB_NAME"] %>
  username: <%= ENV["PRODUCTION_DB_USERNAME"] %>
  password: <%= Rails.application.credentials.gcp[:db_password] %>
  host: "<%= ENV.fetch("DB_SOCKET_DIR") { '/cloudsql' } %>/<%= ENV["CLOUD_SQL_CONNECTION_NAME"] %>"

Elemento multimediale caricato da un utente archiviato nel cloud

Rails utilizza Active Storage per caricare file nei provider di spazio di archiviazione sul cloud. I file config/storage.yml e config/environments/production.rb specificano Cloud Storage come fornitore di servizi nell'ambiente di produzione.

google:
  service: GCS
  project: <%= ENV["GOOGLE_PROJECT_ID"] %>
  bucket: <%= ENV["STORAGE_BUCKET_NAME"] %>
# Store uploaded files on the local file system (see config/storage.yml for options).
config.active_storage.service = :google

Automazione con Cloud Build

Il file cloudbuild.yaml esegue non solo i normali passaggi di creazione di un'immagine (creando l'immagine container ed eseguendo il push in Container Registry), ma anche le migrazioni dei database di Rails. Questi richiedono l'accesso al database, che viene eseguito tramite il provider app-engine-exec-wrapper, che è utile per il proxy di autenticazione Cloud SQL.

steps:
  - id: "build image"
    name: "gcr.io/cloud-builders/docker"
    entrypoint: 'bash'
    args: ["-c", "docker build --build-arg MASTER_KEY=$$RAILS_KEY -t gcr.io/${PROJECT_ID}/${_SERVICE_NAME} . "]
    secretEnv: ["RAILS_KEY"]

  - id: "push image"
    name: "gcr.io/cloud-builders/docker"
    args: ["push", "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"]

  - id: "apply migrations"
    name: "gcr.io/google-appengine/exec-wrapper"
    entrypoint: "bash"
    args:
      [
        "-c",
        "/buildstep/execute.sh -i gcr.io/${PROJECT_ID}/${_SERVICE_NAME} -s ${PROJECT_ID}:${_REGION}:${_INSTANCE_NAME} -e RAILS_MASTER_KEY=$$RAILS_KEY -- bundle exec rails db:migrate"
      ]
    secretEnv: ["RAILS_KEY"]

substitutions:
  _REGION: us-central1
  _SERVICE_NAME: rails-cat-album
  _INSTANCE_NAME: cat-album
  _SECRET_NAME: rails-master-key

availableSecrets:
  secretManager:
  - versionName: projects/${PROJECT_ID}/secrets/${_SECRET_NAME}/versions/latest
    env: RAILS_KEY

images:
  - "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"

In questa configurazione vengono utilizzate le variabili di sostituzione. Se modifichi direttamente i valori nel file, il flag --substitutions potrà essere eliminato al momento della migrazione.

In questa configurazione, vengono applicate solo le migrazioni esistenti nella directory db/migrate. Per creare i file di migrazione, consulta Migrazione delle registrazioni attive.

Per creare l'immagine e applicare migrazioni, la configurazione di Cloud Build deve accedere al secret RAILS_MASTER_KEY da Secret Manager. Il campo availableSecrets imposta la versione e le variabili di ambiente da utilizzare per il secret. Il secret della chiave master viene passato come argomento nel passaggio dell'immagine build e viene impostato come RAILS_MASTER_KEY nel Dockerfile durante la creazione dell'immagine.

ARG MASTER_KEY
ENV RAILS_MASTER_KEY=${MASTER_KEY}

Per estendere la configurazione di Cloud Build in modo da includere il deployment in un'unica configurazione senza dover eseguire due comandi, consulta la pagina relativa al deployment continuo da git utilizzando Cloud Build. Questo richiede modifiche IAM, come descritto.

Supporto per Ruby 2.7

Anche se questo tutorial utilizza Ruby 3.0, può supportare anche Ruby 2.7. Per utilizzare Ruby 2.7, modifica l'immagine di base Ruby nel Dockerfile in 2.7

# Pinning the OS to buster because the nodejs install script is buster-specific.
# Be sure to update the nodejs install command if the base image OS is updated.
FROM ruby:3.0-buster

Esegui la pulizia

  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.