Tutorial: como usar o Cloud Storage FUSE com o Cloud Run


Este tutorial mostra a instalação do Cloud Storage como um sistema de arquivos de rede em um serviço do Cloud Run. A mesma abordagem pode ser usada para um job do Cloud Run.

Neste tutorial, o adaptador FUSE (em inglês) de código aberto é usado para compartilhar dados entre vários contêineres e serviços.

Para ativar um sistema de arquivos, o serviço precisa usar o ambiente de execução de segunda geração do Cloud Run. Os jobs do Cloud Run usam o ambiente de segunda geração automaticamente.

O ambiente de execução de segunda geração permite que sistemas de arquivos de rede sejam ativados em um diretório no contêiner. Montar um sistema de arquivos permite compartilhar recursos entre um sistema host e instâncias, bem como manter os recursos após a coleta de lixo.

O uso de um sistema de arquivos de rede com o Cloud Run exige conhecimento avançado sobre o Docker, já que seu contêiner precisa executar vários processos, incluindo o processo de montagem e o aplicativo de sistema de arquivos. Neste tutorial, explicamos os conceitos necessários com um exemplo prático. No entanto, ao adaptar este tutorial ao seu aplicativo, é preciso entender as implicações de quaisquer alterações que você possa fazer.

Visão geral do design

filesystem-architecture

O diagrama mostra o serviço do Cloud Run conectado ao bucket do Cloud Storage pelo adaptador FUSE gcsfuse. O serviço do Cloud Run e o bucket do Cloud Storage estão localizados na mesma região para remover o custo de rede e ter um melhor desempenho.

Limitações

  • Neste tutorial, não descrevemos como escolher um sistema de arquivos nem abordamos a preparação para a produção. Analise as Principais diferenças de um sistema de arquivos POSIX e outras semânticas do Cloud Storage FUSE.

  • Neste tutorial, não mostramos como trabalhar com um sistema de arquivos ou discutir padrões de acesso a arquivos.

Objetivos

  • Criar um bucket do Cloud Storage para servir como compartilhamento de arquivos.

  • Crie um Dockerfile com pacotes do sistema e init-process para gerenciar os processos de montagem e de aplicativo.

  • Implante no Cloud Run e verifique o acesso ao sistema de arquivos no serviço.

Custos

Neste tutorial, há componentes faturáveis do Google Cloud, entre eles:

Antes de começar

  1. Faça login na sua conta do Google Cloud. Se você começou a usar o Google Cloud agora, crie uma conta para avaliar o desempenho de nossos produtos em situações reais. Clientes novos também recebem US$ 300 em créditos para executar, testar e implantar cargas de trabalho.
  2. No console do Google Cloud, na página do seletor de projetos, selecione ou crie um projeto do Google Cloud.

    Acessar o seletor de projetos

  3. Verifique se a cobrança está ativada para o seu projeto do Google Cloud.

  4. No console do Google Cloud, na página do seletor de projetos, selecione ou crie um projeto do Google Cloud.

    Acessar o seletor de projetos

  5. Verifique se a cobrança está ativada para o seu projeto do Google Cloud.

  6. Ative as APIs Cloud Run, Cloud Storage, Artifact Registry, and Cloud Build .

    Ative as APIs

  7. Instale e inicialize a CLI gcloud.

Funções exigidas

Para ter as permissões necessárias para concluir o tutorial com o conjunto mínimo de papéis, peça ao administrador para conceder a você os seguintes papéis do IAM no seu projeto:

Para mais informações sobre como conceder papéis, consulte Gerenciar acesso.

Também é possível conseguir as permissões necessárias com papéis personalizados ou outros papéis predefinidos.

Como configurar padrões do gcloud

Para configurar a gcloud com os padrões do serviço do Cloud Run, realize as etapas a seguir:

  1. Defina seu projeto padrão:

    gcloud config set project PROJECT_ID

    Substitua PROJECT_ID pelo nome do projeto que você criou para este tutorial.

  2. Configure a gcloud para a região escolhida:

    gcloud config set run/region REGION

    Substitua REGION pela região compatível do Cloud Run.

Locais do Cloud Run

O Cloud Run é regional, o que significa que a infraestrutura que executa seus serviços do Cloud Run está localizada em uma região específica e é gerenciada pelo Google para estar disponível de maneira redundante em todas as zonas da região.

Atender aos seus requisitos de latência, disponibilidade ou durabilidade são os principais fatores para selecionar a região em que seus serviços do Cloud Run são executados. Geralmente, é possível selecionar a região mais próxima de seus usuários, mas considere a localização dos outros produtos do Google Cloud usados pelo serviço do Cloud Run. O uso de produtos do Google Cloud em vários locais pode afetar a latência e o custo do serviço.

O Cloud Run está disponível nas regiões a seguir:

Sujeitas aos preços do nível 1

  • asia-east1 (Taiwan)
  • asia-northeast1 (Tóquio)
  • asia-northeast2 (Osaka)
  • europe-north1 (Finlândia) ícone de folha Baixo CO2
  • europe-southwest1 (Madrid)
  • europe-west1 (Bélgica) ícone de folha Baixo CO
  • europe-west4 (Países Baixos)
  • europe-west8 (Milão)
  • europe-west9 (Paris) ícone de folha Baixo CO2
  • me-west1 (Tel Aviv)
  • us-central1 (Iowa) ícone de folha Baixo CO2
  • us-east1 (Carolina do Sul)
  • us-east4 (Norte da Virgínia)
  • us-east5 (Columbus)
  • us-south1 (Dallas)
  • us-west1 (Oregon) ícone de folha Baixo CO2

Sujeitas aos preços do nível 2

  • asia-east2 (Hong Kong)
  • asia-northeast3 (Seul, Coreia do Sul)
  • asia-southeast1 (Singapura)
  • asia-southeast2 (Jacarta)
  • asia-south1 (Mumbai, Índia)
  • asia-south2 (Déli, Índia)
  • australia-southeast1 (Sydney)
  • australia-southeast2 (Melbourne)
  • europe-central2 (Varsóvia, Polônia)
  • europe-west10 (Berlim)
  • europe-west12 (Turim)
  • europe-west2 (Londres, Reino Unido) ícone de folha Baixo CO2
  • europe-west3 (Frankfurt, Alemanha) ícone de folha Baixo CO2
  • europe-west6 (Zurique, Suíça) ícone de folha Baixo CO2
  • me-central1 (Doha)
  • me-central2 (Damã)
  • northamerica-northeast1 (Montreal) ícone de folha Baixo CO2
  • northamerica-northeast2 (Toronto) ícone de folha Baixo CO2
  • southamerica-east1 (São Paulo, Brasil) ícone de folha Baixo CO2
  • southamerica-west1 (Santiago, Chile) ícone de folha Baixo CO2
  • us-west2 (Los Angeles)
  • us-west3 (Salt Lake City)
  • us-west4 (Las Vegas)

Se você já criou um serviço do Cloud Run, é possível visualizar a região no painel do Cloud Run no console do Google Cloud.

Como recuperar o exemplo de código

Para recuperar o exemplo de código para uso, siga estas etapas:

  1. Clone o repositório do aplicativo de amostra na máquina local:

    Node.js

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

    Outra alternativa é fazer o download da amostra como um arquivo ZIP e extraí-lo.

    Python

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

    Outra alternativa é fazer o download da amostra como um arquivo ZIP e extraí-lo.

    Java

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

    Outra alternativa é fazer o download da amostra como um arquivo ZIP e extraí-lo.

  2. Mude para o diretório que contém o código de amostra do Cloud Run:

    Node.js

    cd nodejs-docs-samples/run/filesystem/

    Python

    cd python-docs-samples/run/filesystem/

    Java

    cd java-docs-samples/run/filesystem/

Noções básicas sobre o código

Normalmente, você precisa executar um único processo ou aplicativo em um contêiner. Executar um único processo por contêiner reduz a complexidade do gerenciamento do ciclo de vida de vários processos: gerenciamento de reinicializações, encerramento do contêiner se algum deles falhar e responsabilidades do PID 1, como encaminhamento de sinal e filho zumbi colhendo. No entanto, o uso de sistemas de arquivos de rede no Cloud Run exige que você use contêineres de vários processos para executar o aplicativo e o processo de montagem do sistema de arquivos. Neste tutorial, mostramos como encerrar o contêiner em caso de falha no processo e gerenciar as responsabilidades do PID 1. O comando de ativação tem funcionalidade integrada para lidar com novas tentativas.

É possível usar um gerenciador de processos para executar e gerenciar vários processos como o ponto de entrada do contêiner. Este tutorial usa tini, uma substituição de init que limpa processos zumbi e executa o encaminhamento de sinais. Especificamente, esse processo init permite que o sinal SIGTERM no encerramento seja propagado para o aplicativo. O sinal SIGTERM pode ser capturado para encerramento correto do aplicativo. Saiba mais sobre o ciclo de vida de um contêiner no Cloud Run.

Como definir sua configuração de ambiente com o Dockerfile

Esse serviço do Cloud Run requer um ou mais pacotes de sistema adicionais não disponíveis por padrão. A instrução RUN instalará tini como nosso processo inicial e gcsfuse, o adaptador FUSE. Leia mais sobre como trabalhar com pacotes do sistema no serviço do Cloud Run no tutorial Como usar pacotes do sistema.

O próximo conjunto de instruções cria um diretório de trabalho, copia o código-fonte e instala as dependências do app.

O ENTRYPOINT especifica o binário init-process que é anexado às instruções do CMD. Neste caso, é o script de inicialização. Isso inicia um único processo tini e faz o proxy de todos os sinais recebidos para uma sessão com acesso root nesse processo filho.

A instrução CMD define o comando a ser executado ao executar a imagem, o script de inicialização. Ele também fornece argumentos padrão para o ENTRYPOINT. Entenda como CMD e ENTRYPOINT interagem.

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"]

Como definir seus processos no script de inicialização

O script de inicialização cria o diretório do ponto de ativação, onde o bucket do Cloud Storage ficará acessível. Em seguida, o script anexa o bucket do Cloud Storage ao ponto de ativação do serviço usando o comando gcsfuse e inicia o servidor do aplicativo. O comando gcsfuse tem a funcionalidade de repetição integrada. Portanto, não é necessário mais scripts bash. Por fim, o comando wait é usado para detectar todos os processos em segundo plano para sair e sair do 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

Como trabalhar com arquivos

Node.js

Consulte index.js para interagir com o sistema de arquivos.

Python

Consulte main.py para interagir com o sistema de arquivos.

Java

Consulte FilesystemApplication.java para interagir com o sistema de arquivos.

Como enviar o serviço

  1. Crie um bucket do Cloud Storage ou reutilize um bucket atual:

    gsutil mb -l REGION gs://BUCKET_NAME
    

    Substitua BUCKET_NAME pelo nome do bucket do Cloud Storage, por exemplo, my-fuse-bucket. Os nomes dos buckets do Cloud Storage precisam ser globalmente exclusivos e estão sujeitos aos requisitos de nomenclatura.

    Defina -l para especificar o local do bucket. Por exemplo, us-central1. Para melhorar o desempenho e evitar cobranças de rede entre regiões, verifique se o bucket do Cloud Storage está localizado na mesma região que os serviços do Cloud Run que precisam acessá-lo.

  2. Crie uma conta de serviço para servir como a identidade de serviço:

    gcloud iam service-accounts create fs-identity
  3. Conceda à conta de serviço acesso ao bucket do Cloud Storage:

    gcloud projects add-iam-policy-binding PROJECT_ID \
         --member "serviceAccount:fs-identity@PROJECT_ID.iam.gserviceaccount.com" \
         --role "roles/storage.objectAdmin"
    
  4. Para implantar a partir da origem, exclua o Dockerfile extra e renomeie o tutorial:

    rm Dockerfile
    cp gcsfuse.Dockerfile Dockerfile
    
  5. Crie e implante a imagem do contêiner no Cloud Run:

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

    Esse comando cria e implanta o serviço Cloud Run e especifica o ambiente de execução da segunda geração. A implantação da origem criará a imagem com base no Dockerfile e enviará a imagem ao repositório do Artifact Registry: cloud-run-source-deploy.

    Saiba mais sobre como implantar a partir do código-fonte.

Como depurar

Se a implantação não for bem-sucedida, verifique os detalhes do Cloud Logging.

Se você quiser que todos os registros do processo de ativação usem a sinalização --foreground em combinação com o comando de ativação no script de inicialização, gcsfuse_run.sh:

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

  • Adição de --debug_http para saída de depuração de solicitação/resposta HTTP.
  • Adição de --debug_fuse para ativar a saída de depuração relacionada a fusível.
  • Adição de --debug_gcs para imprimir informações de tempo e solicitação do GCS.

Veja mais dicas em Solução de problemas.

Como testar

Para testar o serviço completo:

  1. Navegue até o URL fornecido pela etapa de implantação acima.
  2. Você verá um arquivo recém-criado no seu bucket do Cloud Storage.
  3. Clique no arquivo para ver o conteúdo.

Se você optar por continuar desenvolvendo esses serviços, lembre-se de que eles têm acesso restrito do gerenciamento de identidade e acesso (IAM, na sigla em inglês) ao restante do Google Cloud e precisarão receber mais papéis do IAM para acessar muitos outros serviços.

Discussão sobre custos

Os preços do Cloud Storage dependem muito do armazenamento de dados, da quantidade de dados armazenados pela classe de armazenamento e do local dos seus buckets e do uso da rede, a quantidade de dados lidos ou movidos entre os buckets. Saiba mais sobre as cobranças incorridas com o Cloud Storage FUSE.

O Cloud Run tem o preço calculado por uso de recursos, arredondado para os 100 ms mais próximos, para memória, CPU, número de solicitações e rede. Portanto, o custo varia de acordo com as configurações do serviço, o número de solicitações e o tempo de execução.

Por exemplo, 1 TiB de dados armazenados em um bucket de armazenamento Standard hospedado em Iowa (us-central1) custa US$ 0,02 por mês por GiB, o que equivale a aproximadamente 1.024 GiB * US$ 0,02 = US$ 20,48. Essa estimativa depende do serviço do Cloud Run e do bucket do Cloud Storage hospedado na mesma região para negar os custos de saída.

Acesse as páginas de preços individuais para ver os valores mais atualizados ou explore uma estimativa na calculadora de preços do Google Cloud.

Limpeza

Se você criou um novo projeto para este tutorial, exclua o projeto. Se você usou um projeto atual e quer mantê-lo sem as alterações incluídas neste tutorial, exclua os recursos criados para o tutorial.

Como excluir o projeto

O jeito mais fácil de evitar cobranças é excluindo o projeto que você criou para o tutorial.

Para excluir o projeto:

  1. No Console do Google Cloud, acesse a página Gerenciar recursos.

    Acessar "Gerenciar recursos"

  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir .
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.

Como excluir recursos do tutorial

  1. Exclua o serviço do Cloud Run que você implantou neste tutorial:

    gcloud run services delete SERVICE-NAME

    SERVICE-NAME é o nome escolhido do serviço.

    Também é possível excluir os serviços do Cloud Run no Console do Google Cloud.

  2. Remova a configuração da região padrão da gcloud que você adicionou durante a configuração do tutorial:

     gcloud config unset run/region
    
  3. Remova a configuração do projeto:

     gcloud config unset project
    
  4. Exclua outros recursos do Google Cloud criados neste tutorial:

A seguir