Tutorial sull'utilizzo di Cloud Storage FUSE con Cloud Run


Questo tutorial mostra come montare Cloud Storage come file system di rete su un servizio Cloud Run. Lo stesso approccio può essere utilizzato per un job Cloud Run.

Il tutorial utilizza l'adattatore open source FUSE per condividere dati tra più container e servizi.

Per montare un file system, il servizio deve utilizzare l'ambiente di esecuzione di seconda generazione di Cloud Run. I job Cloud Run utilizzano automaticamente l'ambiente di seconda generazione.

L'ambiente di esecuzione di seconda generazione consente di montare file system di rete in una directory all'interno di un container. Il montaggio di un file system consente la condivisione delle risorse tra un sistema host e le istanze e la persistenza delle risorse dopo la garbage collection di un'istanza.

L'utilizzo di un file system di rete con Cloud Run richiede una conoscenza avanzata di Docker perché il container deve eseguire più processi, tra cui il montaggio del file system e il processo dell'applicazione. Questo tutorial illustra i concetti necessari insieme a un esempio funzionante. Tuttavia, quando adatti questo tutorial alla tua applicazione, assicurati di comprendere le implicazioni di eventuali modifiche che potresti apportare.

Panoramica sulla progettazione

architettura-file system

Il diagramma mostra il servizio Cloud Run che si connette al bucket Cloud Storage tramite l'adattatore FUSE gcsfuse. Il servizio Cloud Run e il bucket Cloud Storage si trovano all'interno della stessa regione per rimuovere i costi di rete e ottenere le migliori prestazioni.

Limitazioni

  • Questo tutorial non descrive come scegliere un file system e non illustra la preparazione alla produzione. Esamina le Differenze principali rispetto a un file system POSIX e altre semantiche di Cloud Storage FUSE.

  • Questo tutorial non illustra come lavorare con un file system o illustra i pattern di accesso ai file.

Obiettivi

  • Creare un bucket Cloud Storage da usare come condivisione file.

  • Crea un Dockerfile con pacchetti di sistema e init-process per gestire i processi di montaggio e applicazione.

  • Esegui il deployment in Cloud Run e verifica l'accesso al file system nel servizio.

Costi

Questo tutorial utilizza i componenti fatturabili di Google Cloud, tra cui:

Prima di iniziare

  1. Accedi al tuo account Google Cloud. Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti gratuiti per l'esecuzione, il test e il deployment dei carichi di lavoro.
  2. Nella pagina del selettore di progetti della console Google Cloud, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  3. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.

  4. Nella pagina del selettore di progetti della console Google Cloud, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  5. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.

  6. Abilita le API Cloud Run, Cloud Storage, Artifact Registry, and Cloud Build .

    Abilita le API

  7. Installa e inizializza gcloud CLI.

Ruoli obbligatori

Per ottenere le autorizzazioni necessarie per completare il tutorial con il set minimo di ruoli, chiedi all'amministratore di concederti i seguenti ruoli IAM per il tuo progetto:

Per saperne di più sulla concessione dei ruoli, consulta Gestire l'accesso.

Potresti anche essere in grado di ottenere le autorizzazioni richieste tramite i ruoli personalizzati o altri ruoli predefiniti.

Configurazione delle impostazioni predefinite di gcloud

Per configurare gcloud con i valori predefiniti per il tuo servizio Cloud Run:

  1. Imposta il progetto predefinito:

    gcloud config set project PROJECT_ID

    Sostituisci PROJECT_ID con il nome del progetto che hai creato per questo tutorial.

  2. Configura gcloud per la regione scelta:

    gcloud config set run/region REGION

    Sostituisci REGION con l'area geografica di Cloud Run supportata a tua scelta.

Località di Cloud Run

Cloud Run è regionale, il che significa che l'infrastruttura che gestisce i tuoi servizi Cloud Run si trova in una regione specifica ed è gestita da Google per essere disponibile in modo ridondante in tutte le zone all'interno di quella regione.

Soddisfare i requisiti di latenza, disponibilità o durabilità sono fattori principali per selezionare la regione in cui vengono eseguiti i servizi Cloud Run. In genere puoi selezionare la regione più vicina ai tuoi utenti, ma devi prendere in considerazione la località degli altri prodotti Google Cloud utilizzati dal tuo servizio Cloud Run. L'utilizzo dei prodotti Google Cloud insieme in più località può influire sulla latenza e sui costi del tuo servizio.

Cloud Run è disponibile nelle seguenti regioni:

Soggetto ai prezzi di Livello 1

Soggetto ai prezzi di Livello 2

  • asia-east2 (Hong Kong)
  • asia-northeast3 (Seul, Corea del Sud)
  • asia-southeast1 (Singapore)
  • asia-southeast2 (Giacarta)
  • asia-south1 (Mumbai, India)
  • asia-south2 (Delhi, India)
  • australia-southeast1 (Sydney)
  • australia-southeast2 (Melbourne)
  • europe-central2 (Varsavia, Polonia)
  • europe-west10 (Berlino)
  • europe-west12 (Torino)
  • europe-west2 (Londra, Regno Unito) icona foglia A basse emissioni di CO2
  • europe-west3 (Francoforte, Germania) icona foglia A basse emissioni di CO2
  • europe-west6 (Zurigo, Svizzera) icona foglia A basse emissioni di CO2
  • me-central1 (Doha)
  • me-central2 (Dammam)
  • northamerica-northeast1 (Montreal) icona foglia A basse emissioni di CO2
  • northamerica-northeast2 (Toronto) icona foglia A basse emissioni di CO2
  • southamerica-east1 (San Paolo, Brasile) icona foglia A basse emissioni di CO2
  • southamerica-west1 (Santiago, Cile) icona foglia A basse emissioni di CO2
  • us-west2 (Los Angeles)
  • us-west3 (Salt Lake City)
  • us-west4 (Las Vegas)

Se hai già creato un servizio Cloud Run, puoi visualizzare la regione nella dashboard di Cloud Run nella console Google Cloud.

Recupero dell'esempio di codice

Per recuperare l'esempio di codice da utilizzare:

  1. Clona il repository dell'app di esempio nella tua macchina locale:

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    In alternativa, puoi scaricare l'esempio come file ZIP ed estrarlo.

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    In alternativa, puoi scaricare l'esempio come file ZIP ed estrarlo.

    Java

    git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git

    In alternativa, puoi scaricare l'esempio come file ZIP ed estrarlo.

  2. Passa alla directory che contiene il codice di esempio Cloud Run:

    Node.js

    cd nodejs-docs-samples/run/filesystem/

    Python

    cd python-docs-samples/run/filesystem/

    Java

    cd java-docs-samples/run/filesystem/

Nozioni di base sul codice

Solitamente, devi eseguire un singolo processo o un'applicazione all'interno di un container. L'esecuzione di un singolo processo per container riduce la complessità della gestione del ciclo di vita di più processi: gestione dei riavvii, arresto del container se un processo non funziona e responsabilità del PID 1, ad esempio inoltro del segnale e raccolta dei dati secondari zombie. Tuttavia, l'utilizzo di file system di rete in Cloud Run richiede l'uso di container multi-processo per eseguire sia il processo di montaggio del file system sia l'applicazione. Questo tutorial mostra come terminare il container in caso di errore del processo e gestire le responsabilità PID 1. Il comando mount ha funzionalità integrate per gestire i nuovi tentativi.

Puoi utilizzare un gestore di processi per eseguire e gestire più processi come punto di ingresso del contenitore. Questo tutorial utilizza tini, una sostituzione di inizializzazione che pulisce i processi zombie ed esegue l'inoltro del segnale. In particolare, questo processo di inizializzazione consente al segnale SIGTERM di arresto di propagarsi all'applicazione. Il segnale SIGTERM può essere rilevato per la terminazione controllata dell'applicazione. Scopri di più sul ciclo di vita di un container su Cloud Run.

Definizione della configurazione dell'ambiente con il Dockerfile

Questo servizio Cloud Run richiede uno o più pacchetti di sistema aggiuntivi non disponibili per impostazione predefinita. L'istruzione RUN installerà tini come processo init e gcsfuse, l'adattatore FUSE. Scopri di più sull'utilizzo dei pacchetti di sistema nel servizio Cloud Run nel tutorial sull'utilizzo dei pacchetti di sistema.

Il successivo insieme di istruzioni crea una directory di lavoro, copia il codice sorgente e installa le dipendenze dell'app.

ENTRYPOINT specifica il programma binario init-process che viene anteposto alle istruzioni CMD. In questo caso si tratta dello script di avvio. Questo avvia un singolo processo tini e quindi esegue il proxy di tutti i segnali ricevuti a una sessione radicata in quel processo figlio.

L'istruzione CMD imposta il comando da eseguire quando viene eseguita l'immagine, ovvero lo script di avvio. Fornisce inoltre argomenti predefiniti per ENTRYPOINT. Informazioni sull'interazione tra CMD e ENTRYPOINT.

Node.js


# Use the official Node.js image.
# https://hub.docker.com/_/node
FROM node:20-slim

# Install system dependencies
RUN apt-get update && apt-get install -y \
    curl \
    gnupg \
    lsb-release \
    tini && \
    gcsFuseRepo=gcsfuse-`lsb_release -c -s` && \
    echo "deb https://packages.cloud.google.com/apt $gcsFuseRepo main" | \
    tee /etc/apt/sources.list.d/gcsfuse.list && \
    curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
    apt-key add - && \
    apt-get update && \
    apt-get install -y gcsfuse && \
    apt-get clean

# Set fallback mount directory
ENV MNT_DIR /mnt/gcs

# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY package*.json ./

# Install production dependencies.
RUN npm install --only=production

# Copy local code to the container image.
COPY . ./

# Ensure the script is executable
RUN chmod +x /app/gcsfuse_run.sh

# Use tini to manage zombie processes and signal forwarding
# https://github.com/krallin/tini
ENTRYPOINT ["/usr/bin/tini", "--"]

# Pass the wrapper script as arguments to tini
CMD ["/app/gcsfuse_run.sh"]

Python

# Use the official lightweight Python image.
# https://hub.docker.com/_/python
FROM python:3.11-buster

# Install system dependencies
RUN set -e; \
    apt-get update -y && apt-get install -y \
    tini \
    lsb-release; \
    gcsFuseRepo=gcsfuse-`lsb_release -c -s`; \
    echo "deb https://packages.cloud.google.com/apt $gcsFuseRepo main" | \
    tee /etc/apt/sources.list.d/gcsfuse.list; \
    curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
    apt-key add -; \
    apt-get update; \
    apt-get install -y gcsfuse \
    && apt-get clean

# Set fallback mount directory
ENV MNT_DIR /mnt/gcs

# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./

# Install production dependencies.
RUN pip install -r requirements.txt

# Ensure the script is executable
RUN chmod +x /app/gcsfuse_run.sh

# Use tini to manage zombie processes and signal forwarding
# https://github.com/krallin/tini
ENTRYPOINT ["/usr/bin/tini", "--"]

# Pass the startup script as arguments to Tini
CMD ["/app/gcsfuse_run.sh"]

Java

# Use the official maven/Java 11 image to create a build artifact.
# https://hub.docker.com/_/maven
FROM maven:3-eclipse-temurin-17-alpine as builder

# Copy local code to the container image.
WORKDIR /app
COPY pom.xml .
COPY src ./src

# Build a release artifact.
RUN mvn package -DskipTests

# Use Eclipse Temurin for base image.
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM eclipse-temurin:18-jdk-focal

# Install system dependencies
RUN set -e; \
    apt-get update -y && apt-get install -y \
    gnupg2 \
    tini \
    lsb-release; \
    gcsFuseRepo=gcsfuse-`lsb_release -c -s`; \
    echo "deb https://packages.cloud.google.com/apt $gcsFuseRepo main" | \
    tee /etc/apt/sources.list.d/gcsfuse.list; \
    curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
    apt-key add -; \
    apt-get update; \
    apt-get install -y gcsfuse && apt-get clean

# Set fallback mount directory
ENV MNT_DIR /mnt/gcs

# Copy the jar to the production image from the builder stage.
COPY --from=builder /app/target/filesystem-*.jar /filesystem.jar

# Copy the statup script
COPY gcsfuse_run.sh ./gcsfuse_run.sh
RUN chmod +x ./gcsfuse_run.sh

# Use tini to manage zombie processes and signal forwarding
# https://github.com/krallin/tini
ENTRYPOINT ["/usr/bin/tini", "--"]

# Run the web service on container startup.
CMD ["/gcsfuse_run.sh"]

Definizione dei processi nello script di avvio

Lo script di avvio crea la directory del punto di montaggio, in cui il bucket Cloud Storage sarà reso accessibile. Successivamente, lo script collega il bucket Cloud Storage al punto di montaggio del servizio utilizzando il comando gcsfuse e avvia il server applicazioni. Il comando gcsfuse dispone di una funzionalità incorporata per la ripetizione dei tentativi, pertanto non è necessario eseguire ulteriori script Bash. Infine, il comando wait viene utilizzato per rimanere in ascolto dei processi in background per uscire e poi uscire dallo script.

Node.js

#!/usr/bin/env bash
set -eo pipefail

# Create mount directory for service
mkdir -p $MNT_DIR

echo "Mounting GCS Fuse."
gcsfuse --debug_gcs --debug_fuse $BUCKET $MNT_DIR
echo "Mounting completed."

# Start the application
node index.js &

# Exit immediately when one of the background processes terminate.
wait -n

Python

#!/usr/bin/env bash
set -eo pipefail

# Create mount directory for service
mkdir -p $MNT_DIR

echo "Mounting GCS Fuse."
gcsfuse --debug_gcs --debug_fuse $BUCKET $MNT_DIR
echo "Mounting completed."

# Run the web service on container startup. Here we use the gunicorn
# webserver, with one worker process and 8 threads.
# For environments with multiple CPU cores, increase the number of workers
# to be equal to the cores available.
# Timeout is set to 0 to disable the timeouts of the workers to allow Cloud Run to handle instance scaling.
exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

Java

#!/usr/bin/env bash
set -eo pipefail

# Create mount directory for service
mkdir -p $MNT_DIR

echo "Mounting GCS Fuse."
gcsfuse --debug_gcs --debug_fuse $BUCKET $MNT_DIR
echo "Mounting completed."

# Start the application
java -jar filesystem.jar

# Exit immediately when one of the background processes terminate.
wait -n

Lavorare con i file

Node.js

Consulta index.js per informazioni sull'interazione con il file system.

Python

Vedi main.py per interagire con il file system.

Java

Vedi FilesystemApplication.java per interagire con il filesystem.

Spedizione del servizio

  1. Crea un bucket Cloud Storage o riutilizza un bucket esistente:

    gsutil mb -l REGION gs://BUCKET_NAME
    

    Sostituisci BUCKET_NAME con il nome del bucket Cloud Storage, ad esempio my-fuse-bucket. I nomi dei bucket Cloud Storage devono essere univoci a livello globale e sono soggetti ai requisiti di denominazione.

    Imposta -l per specificare la località del bucket. Ad esempio, us-central1. Per ottenere le migliori prestazioni ed evitare addebiti di networking tra regioni, assicurati che il bucket Cloud Storage si trovi nella stessa regione dei servizi Cloud Run che devono accedervi.

  2. Crea un account di servizio da utilizzare come identità di servizio:

    gcloud iam service-accounts create fs-identity
  3. Concedi all'account di servizio l'accesso al bucket Cloud Storage:

    gcloud projects add-iam-policy-binding PROJECT_ID \
         --member "serviceAccount:fs-identity@PROJECT_ID.iam.gserviceaccount.com" \
         --role "roles/storage.objectAdmin"
    
  4. Per eseguire il deployment dall'origine, elimina il Dockerfile aggiuntivo e rinomina il Dockerfile del tutorial:

    rm Dockerfile
    cp gcsfuse.Dockerfile Dockerfile
    
  5. Crea ed esegui il deployment dell'immagine container in Cloud Run:

    gcloud run deploy filesystem-app --source . \
        --execution-environment gen2 \
        --allow-unauthenticated \
        --service-account fs-identity \
        --update-env-vars BUCKET=BUCKET_NAME
    

    Questo comando crea ed esegue il deployment del servizio Cloud Run e specifica l'ambiente di esecuzione di seconda generazione. Il deployment dal codice sorgente creerà l'immagine in base al Dockerfile ed eseguirà il push dell'immagine nel repository Artifact Registry: cloud-run-source-deploy.

    Scopri di più sul deployment dal codice sorgente.

Debug

Se il deployment non riesce, controlla Cloud Logging per ulteriori dettagli.

Per visualizzare tutti i log del processo di montaggio, utilizza il flag --foreground in combinazione con il comando mount nello script di avvio, gcsfuse_run.sh:

  gcsfuse --foreground --debug_gcs --debug_fuse GCSFUSE_BUCKET MNT_DIRECTORY &
  

  • Aggiungi --debug_http per l'output di debug di richiesta/risposta HTTP.
  • Aggiungi --debug_fuse per attivare l'output di debug relativo ai fusibili.
  • Aggiungi --debug_gcs per stampare le informazioni sulle tempistiche e sulla richiesta GCS.

Leggi altri suggerimenti per la risoluzione dei problemi.

Provalo

Per provare il servizio completo:

  1. Vai nel browser all'URL fornito nel passaggio di deployment riportato sopra.
  2. Dovresti vedere un file appena creato nel tuo bucket Cloud Storage.
  3. Fai clic sul file per visualizzarne i contenuti.

Se scegli di continuare a sviluppare questi servizi, ricorda che questi hanno un accesso limitato a Identity and Access Management (IAM) al resto di Google Cloud e dovranno disporre di ruoli IAM aggiuntivi per accedere a molti altri servizi.

Discussione sui costi

I prezzi di Cloud Storage dipendono molto dall'archiviazione dei dati, dalla quantità di dati archiviati in base alla classe di archiviazione e alla località dei bucket, nonché dall'utilizzo della rete, ovvero dalla quantità di dati letti o spostati tra i bucket. Scopri di più sugli addebiti sostenuti con Cloud Storage FUSE.

I prezzi di Cloud Run si basano sull'utilizzo delle risorse, arrotondati ai 100 ms più vicini, per memoria, CPU, numero di richieste e networking. Pertanto il costo varierà in base alle impostazioni del servizio, al numero di richieste e al tempo di esecuzione.

Ad esempio, 1 TiB di dati archiviati in un bucket di archiviazione Standard ospitato in Iowa (us-central1) costa 0,02 $al mese per GiB, ovvero circa 1024 GiB * 0,02 $ = 20,48 $. Questa stima dipende dal servizio Cloud Run e dal bucket Cloud Storage ospitati nella stessa regione per negare i costi del traffico in uscita.

Visita le singole pagine dei prezzi per conoscere i prezzi più aggiornati o esplora una stima nel Calcolatore prezzi di Google Cloud.

Esegui la pulizia

Se hai creato un nuovo progetto per questo tutorial, elimina il progetto. Se hai utilizzato un progetto esistente e vuoi conservarlo senza le modifiche aggiunte in questo tutorial, elimina le risorse create per il tutorial.

Elimina il progetto

Il modo più semplice per eliminare la fatturazione è eliminare il progetto che hai creato per il tutorial.

Per eliminare il progetto:

  1. Nella console Google Cloud, vai alla pagina Gestisci risorse.

    Vai a Gestisci risorse

  2. Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
  3. Nella finestra di dialogo, digita l'ID del progetto e fai clic su Chiudi per eliminare il progetto.

Eliminazione delle risorse del tutorial

  1. Elimina il servizio Cloud Run di cui hai eseguito il deployment in questo tutorial:

    gcloud run services delete SERVICE-NAME

    Dove SERVICE-NAME è il nome del servizio che hai scelto.

    Puoi anche eliminare i servizi Cloud Run dalla console Google Cloud.

  2. Rimuovi la configurazione della regione predefinita di gcloud che hai aggiunto durante la configurazione del tutorial:

     gcloud config unset run/region
    
  3. Rimuovi la configurazione del progetto:

     gcloud config unset project
    
  4. Elimina le altre risorse Google Cloud create in questo tutorial:

Passaggi successivi