Workshop de modernização de apps

1. Introdução

Última atualização:01/11/2024

Como modernizar um aplicativo PHP antigo para o Google Cloud?

(📽️ assista a um vídeo introdutório de 7 minutos deste codelab)

É comum ter aplicativos legados em execução no local que precisam ser modernizados. Isso significa torná-los escalonáveis, seguros e implantáveis em diferentes ambientes.

Neste workshop, você vai:

  1. Conteinerizar o aplicativo PHP.
  2. Migrar para um serviço de banco de dados gerenciado ( Cloud SQL).
  3. Implante no Cloud Run, que é uma alternativa sem operações para o GKE/Kubernetes.
  4. Proteja o aplicativo com o Identity and Access Management (IAM) e o Secret Manager.
  5. Defina um pipeline de CI/CD usando o Cloud Build. O Cloud Build pode ser conectado ao repositório Git hospedado em provedores de Git conhecidos, como GitHub ou GitLab, e ser acionado em qualquer push para o main, por exemplo.
  6. Hospedar as imagens do aplicativo no Cloud Storage. Isso é feito pela montagem, e nenhum código é necessário para mudar o app.
  7. Apresente a funcionalidade da Gen AI usando o Gemini, orquestrado pelo Cloud Functions (sem servidor).
  8. Familiarize-se com os SLO e como operar seu app recém-atualizado.

Ao seguir estas etapas, você pode modernizar gradualmente seu aplicativo PHP, melhorando a escalonabilidade, a segurança e a flexibilidade de implantação. Além disso, a migração para o Google Cloud permite aproveitar a infraestrutura e os serviços poderosos para garantir que o aplicativo seja executado sem problemas em um ambiente nativo da nuvem.

Acreditamos que o que você vai aprender seguindo estas etapas simples pode ser aplicado ao seu próprio aplicativo e organização com diferentes idiomas/pilhas e casos de uso.

Sobre o app

O aplicativo ( código, sob licença MIT) que você clonará é um aplicativo PHP 5.7 básico com autenticação do MySQL. A ideia principal do app é fornecer uma plataforma em que os usuários podem fazer upload de fotos e os administradores podem marcar imagens inadequadas. O aplicativo tem duas tabelas:

  • Usuários. Vem pré-compilado com administradores. Novas pessoas podem se registrar.
  • Images Vem com algumas imagens de exemplo. Os usuários conectados podem fazer upload de novas imagens. Vamos adicionar um pouco de magia aqui.

Sua meta

Queremos modernizar o aplicativo antigo para que ele seja executado no Google Cloud. Vamos aproveitar as ferramentas e os serviços para melhorar a escalabilidade, a segurança, a automação do gerenciamento de infraestrutura e a integração de recursos avançados, como processamento de imagens, monitoramento e armazenamento de dados, usando serviços como o Cloud SQL, o Cloud Run, o Cloud Build, o Secret Manager e outros.

445f7a9ae37e9b4d.png

Mais importante, queremos fazer isso passo a passo para que você possa aprender qual é o processo de pensamento por trás de cada etapa. Geralmente, cada etapa desbloqueia novas possibilidades para as próximas (por exemplo, módulos 2 a 3 e 6 a 7).

Ainda não está convencido? Confira este vídeo de 7 minutos no YouTube.

O que é necessário

  • Um computador com um navegador conectado à Internet.
  • Alguns créditos do GCP. Peça a um fã do Google perto de você ;)
  • O comando gcloud está funcionando.
  • Você está trabalhando localmente? Faça o download aqui. Você também vai precisar de um editor legal (por exemplo, vscode ou intellij).
  • Quer fazer tudo na nuvem? Nesse caso, use o Cloud Shell.
  • Usuário do GitHub. Você vai precisar disso para ramificar o código original 🧑🏻‍💻 gdgpescara/app-mod-workshop com seu próprio repositório do Git. Isso é necessário para ter seu próprio pipeline de CI/CD (commit automático -> build -> deploy)

Confira exemplos de soluções:

Este workshop pode ser consumido no seu computador local ou inteiramente em um navegador.

2. Configuração de crédito e Fork

6dafc658860c0ce5.png

Resgatar o crédito do GCP e configurar seu ambiente do GCP [opcional]

Para realizar este workshop, você precisa de uma conta de faturamento com algum crédito. Se você já tem sua própria cobrança, pule esta etapa.

Crie uma conta do Gmail do Google (*) para vincular ao seu crédito do GCP. Peça ao seu professor o link para resgatar o crédito do GCP ou use os créditos aqui: bit.ly/PHP-Amarcord-credits .

Faça login com a conta recém-criada e siga as instruções.

ff739240dbd84a30.png

(

) Por que preciso de uma conta do Gmail nova?*

Vimos pessoas reprovarem o codelab porque a conta delas (principalmente e-mails de trabalho ou de estudantes) já tinha tido contato com o GCP e tinha políticas organizacionais que limitavam a capacidade de fazer isso. Recomendamos criar uma nova conta do Gmail ou usar uma conta do Gmail (gmail.com) sem exposição anterior ao GCP.

Clique no botão para resgatar o crédito.

331658dc50213403.png

Preencha o formulário a seguir com seu nome e sobrenome e aceite os Termos e Condições.

Talvez seja necessário esperar alguns segundos até que a conta de faturamento apareça aqui: https://console.cloud.google.com/billing

Depois, abra o console do Google Cloud e crie um novo projeto clicando no seletor de projetos no menu suspenso no canto superior esquerdo, onde "Sem organização" é exibido. Consulte abaixo

bd7548f78689db0b.png

Crie um projeto se você não tiver um, conforme mostrado na captura de tela abaixo. Há uma opção "NOVO PROJETO" no canto superior direito.

6c82aebcb9f5cd47.png

Vincule o novo projeto à conta de faturamento de teste do GCP da seguinte maneira.

f202527d254893fb.png

Tudo pronto para usar a Google Cloud Platform. Se você é iniciante ou só quer fazer tudo em um ambiente do Cloud, acesse o Cloud Shell e o editor dele pelo botão no canto superior esquerdo, conforme mostrado abaixo.

7d732d7bf0deb12e.png

Verifique se o novo projeto está selecionado no canto superior esquerdo:

Não selecionado (ruim):

c2ffd36a781b276a.png

Selecionado (bom):

594563c158f4f590.png

Bifurcar o app do GitHub

  1. Acesse o app de demonstração: https://github.com/gdgpescara/app-mod-workshop
  2. Clique em 🍴 bifurcar.
  3. Se você não tiver uma conta do GitHub, crie uma.
  4. Edite o que quiser.

734e51bfc29ee5df.png

  1. Clone o código do app usando
  2. git clone https://github.com/YOUR-GITHUB-USER/YOUR-REPO-NAME
  1. Abra a pasta do projeto clonado com seu editor favorito. Se você escolher o Cloud Shell, clique em Abrir editor, conforme mostrado abaixo.

40f5977ea4c1d1cb.png

Você tem tudo o que precisa com o editor do Google Cloud Shell, como mostra a figura a seguir

a4e5ffb3e9a35e84.png

Para fazer isso, clique em "Abrir pasta" e selecione a pasta, provavelmente app-mod-workshop na sua pasta inicial.

3. Módulo 1: criar uma instância do SQL

645902e511a432a6.png

Criar a instância do Google Cloud SQL

Nosso app PHP vai se conectar a um banco de dados MySQL e, portanto, precisamos fazer a replicação dele no Google Cloud para uma migração sem problemas. O Cloud SQL é a combinação perfeita, porque permite executar um banco de dados MySQL totalmente gerenciado na Nuvem. Siga estas etapas:

  1. Acesse a página do Cloud SQL: https://console.cloud.google.com/sql/instances.
  2. Clique em "Criar instância".
  3. Ative a API (se necessário). Isso pode demorar alguns segundos…
  4. Escolha MySQL.
  5. Estamos tentando oferecer a versão mais barata para que ela dure mais:
  • Edição: Enterprise
  • Predefinição: desenvolvimento (testamos o sandbox e não funcionou para nós)
  • Mysql Ver: 5.7 (uau, uma lembrança do passado!)
  1. ID da instância: escolha appmod-phpapp. Se você mudar isso, lembre-se de mudar também os scripts e soluções futuros.
  2. Senha: qualquer coisa, mas anote como CLOUDSQL_INSTANCE_PASSWORD
  3. Região: mantenha a mesma escolha para o restante do app (por exemplo, Milão = europe-west8)
  4. Disponibilidade zonal: zona única (estamos economizando dinheiro para a demonstração)

Clique no botão "Criar instância" para implantar o banco de dados do Cloud SQL. ⌛ A conclusão leva cerca de 10 minutos⌛. Enquanto isso, continue lendo a documentação. Você também pode começar a resolver o próximo módulo ("Containerize your PHP App"), já que ele não tem dependências nesse módulo na primeira parte (até que você corrija a conexão do banco de dados).

Observação: Essa instância custará cerca de US$ 7/dia. Desligue-o após o workshop.

Criar o banco de dados image_catalog e o usuário no Cloud SQL

O projeto do app vem com uma pasta db/ que contém dois arquivos SQL:

  1. 01_schema.sql : contém o código SQL para criar duas tabelas com dados de usuários e imagens.
  2. 02_seed.sql: contém o código SQL para inserir dados nas tabelas criadas anteriormente.

Esses arquivos serão usados mais tarde, quando o banco de dados image_catalog for criado. Para fazer isso, siga estas etapas:

  1. Abra a instância e clique na guia "Bancos de dados":
  2. Clique em "Criar banco de dados".
  3. Chame-o de image_catalog (como na configuração do app PHP).

997ef853e5ebd857.png

Em seguida, criamos o usuário do banco de dados. Com isso, podemos fazer a autenticação no banco de dados image_catalog.

  1. Agora clique na guia Usuários.
  2. Clique em "Adicionar conta de usuário".
  3. Usuário: vamos criar um:
  • Nome de usuário: appmod-phpapp-user
  • Senha: escolha algo que você possa lembrar ou clique em "Gerar"
  • Mantenha Permitir qualquer host (%).
  1. Clique em "ADICIONAR".

Abra o banco de dados para IPs conhecidos.

Todos os bancos de dados no Cloud SQL são criados "isolados". É necessário configurar explicitamente uma rede para que ela seja acessível.

  1. Clique na sua instância.
  2. Abra o menu "Conexões".
  3. Clique na guia "Rede".
  4. Clique em "Redes autorizadas". Agora adicione uma rede (ou seja, uma sub-rede).
  • Por enquanto, vamos escolher uma configuração rápida, mas INSEGURA, para que o app funcione. Talvez você queira restringir a configuração a IPs confiáveis mais tarde:
  • Nome: "Todos no mundo - INSEGURO".
  • Rede: "0.0.0.0/0"" (observação: essa é a parte INSEGURA).
  • Clique em "CONCLUÍDO".
  1. Clique em "Salvar".

Você verá algo como:

5ccb9062a7071964.png

Observação: Essa solução é um bom compromisso para terminar o workshop em O(horas). No entanto, consulte o documento SEGURANÇA para ajudar a proteger sua solução para produção.

É hora de testar a conexão do banco de dados!

Vamos conferir se o usuário image_catalog que criamos antes funciona.

Acesse o "Cloud SQL Studio" na instância e insira o banco de dados, o usuário e a senha para autenticação, conforme mostrado abaixo:

d56765c6154c11a4.png

Agora que você está conectado, pode abrir o Editor SQL e passar para a próxima seção.

Importar o banco de dados da base de código

Use o editor SQL para importar as tabelas image_catalog com os dados. Copie o código SQL dos arquivos no repositório ( 01_schema.sql e 02_seed.sql) e execute-os um após o outro em ordem sequencial.

Depois disso, você vai ter duas tabelas no image_catalog, que são users e images, conforme mostrado abaixo:

65ba01e4c6c2dac0.png

Para testar, execute o seguinte no editor: select * from images;

Anote também o endereço IP público da instância do Cloud SQL, porque você vai precisar dele mais tarde. Para conferir o IP, acesse a página principal da instância do Cloud SQL em Visão geral. (Visão geral > Conectar-se a esta instância > Endereço IP público).

4. Módulo 2: conteinerizar seu app PHP

e7f0e9979d8805f5.png

Queremos criar este app para a nuvem.

Isso significa empacotar o código em algum tipo de arquivo ZIP que contenha todas as informações para executá-lo na nuvem.

Há algumas maneiras de fazer isso:

  • Docker Muito popular, mas bastante complexo de configurar corretamente.
  • Buildpacks. Menos popular, mas tende a "adivinhar automaticamente" o que construir e o que executar. Muitas vezes, funciona!

No contexto deste workshop, vamos supor que você use o Docker.

Se você escolheu usar o Cloud Shell, é hora de reabrir (clique no canto superior direito do console do Cloud).

ec6a6b90b39e03e.png

Isso vai abrir um shell conveniente na parte de baixo da página, onde você deve ter bifurcado o código na etapa de configuração.

6999b906c0dedeb7.png

Docker

Se você quer ter controle, essa é a solução certa. Isso faz sentido quando você precisa configurar bibliotecas específicas e injetar determinados comportamentos não óbvios (um chmod em uploads, um executável não padrão no app etc.).

Como queremos implantar nosso aplicativo conteinerizado no Cloud Run, consulte a documentação a seguir. Como você faria a portabilidade do PHP 8 para o PHP 5.7? Talvez você possa usar o Gemini para isso. Como alternativa, use esta versão pré-preparada:

fbd8c2ace2faa70b.png

A versão mais recente do Dockerfile está disponível aqui.

Para testar nosso aplicativo localmente, precisamos mudar o arquivo config.php de modo que o app PHP se conecte ao banco de dados MYSQL disponível no Google CloudSQL. Com base no que você configurou antes, preencha os espaços em branco:

<?php
// Database configuration
$db_host = '____________';
$db_name = '____________';
$db_user = '____________';
$db_pass = '____________';

try {
    $pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("Errore di connessione: " . $e->getMessage());
}

session_start();
?>
  • DB_HOST é o endereço IP público do Cloud SQL. Ele pode ser encontrado no console do SQL:

bd27071bf450a8d0.png

  • DB_NAME não deve ser alterado: image_catalog
  • DB_USER precisa ser appmod-phpapp-user
  • DB_PASS é algo que você escolheu. Configure-o com aspas simples e use o escape conforme necessário.

Além disso, sinta-se à vontade para traduzir as poucas 🇮🇹 partes em italiano para o inglês com a ajuda do Gemini!

Ok, agora que você tem o Dockerfile e configurou o app PHP para se conectar ao banco de dados, vamos testar isso.

Instale o Docker, se ainda não tiver ( link). Você não precisa fazer isso se estiver usando o Cloud Shell.

Agora tente criar e executar o app PHP conteinerizado com os comandos de criação e execução do Docker apropriados.

# Build command - don't forget the final . This works if Dockerfile is inside the code folder:
$ docker build -t my-php-app-docker .   

# Local Run command: most likely ports will be 8080:8080
$ docker run -it -p <CONTAINER_PORT>:<LOCAL_MACHINE_PORT> my-php-app-docker

Se tudo estiver funcionando, você vai conseguir acessar a página da Web a seguir quando estiver conectado ao host local. Agora, seu app está sendo executado na porta 8080. Clique no ícone "Visualização na Web" (um navegador com um olho) e em Visualizar na porta 8080 (ou "Mudar porta" para qualquer outra porta).

33a24673f4550454.png

Como testar o resultado no navegador

Agora, seu aplicativo vai ficar assim:

2718ece96b1f18b6.png

Se você fizer login com Admin/admin123, verá algo como isto.

68b62048c2e86aea.png

Ótimo!!! Além do texto em italiano, está funcionando. 🎉🎉🎉

Se a dockerização estiver correta, mas as credenciais do banco de dados estiverem incorretas, você vai receber uma mensagem como esta:

e22f45b79bab86e1.png

Tente de novo. Você está quase lá!

Como salvar no Artifact Registry [opcional]

Agora você tem um aplicativo PHP conteinerizado funcional pronto para ser implantado na nuvem. Em seguida, precisamos de um lugar na nuvem para armazenar nossa imagem do Docker e torná-la acessível para implantação em serviços do Google Cloud, como o Cloud Run. Essa solução de armazenamento é chamada de Artifact Registry, um serviço totalmente gerenciado do Google Cloud projetado para armazenar artefatos de aplicativos, incluindo imagens de contêineres do Docker, pacotes do Maven, módulos npm e muito mais.

Vamos criar um repositório no Google Cloud Artifact Registry usando o botão apropriado.

e1123f0c924022e6.png

Escolha um nome válido, o formato e a região adequada para armazenar os artefatos.

4e516ed209c470ee.png

Volte para a tag do ambiente de desenvolvimento local e envie a imagem do contêiner do app para o repositório do Artifact Registry que você acabou de criar. Para fazer isso, execute os comandos a seguir.

  • docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
  • docker push TARGET_IMAGE[:TAG]

O resultado vai ficar parecido com a captura de tela a seguir.

1e498feb4e88be9f.png

Oba 🎉🎉🎉, você pode passar para o próximo nível. Antes disso, talvez você queira tentar fazer upload/login/logout e se familiarizar com os endpoints do app.Você vai precisar deles mais tarde.

Possíveis erros

Se você receber erros de contêinerização, tente usar o Gemini para explicar e corrigir o erro, fornecendo:

  • Seu Dockerfile atual
  • O erro recebido
  • [Se necessário] o código PHP que está sendo executado.

Permissões de upload. Tente também o endpoint /upload.php e faça o upload de uma imagem. Você pode receber o erro abaixo. Se for o caso, você precisa corrigir o chmod/chown no Dockerfile.

Aviso: move_uploaded_file(uploads/image (3).png): não foi possível abrir o fluxo: permissão negada em /var/www/html/upload.php na linha 11

PDOException "não foi possível encontrar o driver" (ou "Errore di connessione: não foi possível encontrar o driver"). Verifique se o Dockerfile tem as bibliotecas PDO adequadas para mysql (pdo_mysql) para se conectar ao banco de dados. Inspire-se com as soluções aqui.

Não foi possível encaminhar sua solicitação para um back-end. Não foi possível se conectar a um servidor na porta 8080. Isso significa que você provavelmente está expondo a porta errada. Verifique se você está expondo a porta de onde o Apache/Nginx está sendo veiculado. Isso não é trivial. Se possível, tente usar a porta 8080, que facilita a vida com o Cloud Run. Se você quiser manter a porta 80 (por exemplo, porque o Apache exige isso), use um comando diferente para executá-la:

$ docker run -it -p 8080:80 # force 80

# Use the PORT environment variable in Apache configuration files.

# https://cloud.google.com/run/docs/reference/container-contract#port

RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf

5. Módulo 3: implantar o app no Cloud Run

9ffca42774f6c5d1.png

Por que usar o Cloud Run?

Boa pergunta. Há alguns anos, você certamente teria escolhido o Google App Engine.

Simplificando, hoje o Cloud Run tem uma pilha de tecnologia mais recente, é mais fácil de implantar, mais barato e reduz a escala para 0 quando você não o usa. Com a flexibilidade de executar qualquer contêiner sem estado e a integração com vários serviços do Google Cloud, ele é ideal para implantar microsserviços e aplicativos modernos com o mínimo de sobrecarga e a máxima eficiência.

Mais especificamente, o Cloud Run é uma plataforma totalmente gerenciada pelo Google Cloud que permite executar aplicativos conteinerizados sem estado em um ambiente sem servidor. Ele processa toda a infraestrutura de forma automática, escalonando de zero para atender ao tráfego de entrada e diminuindo quando ocioso, o que torna o processo econômico e eficiente. O Cloud Run oferece suporte a qualquer linguagem ou biblioteca desde que ela seja empacotada em um contêiner, permitindo uma grande flexibilidade no desenvolvimento. Ele se integra bem a outros serviços do Google Cloud e é adequado para criar microsserviços, APIs, sites e aplicativos orientados a eventos sem precisar gerenciar a infraestrutura do servidor.

Pré-requisitos

Para realizar essa tarefa, você precisa ter o gcloud instalado na sua máquina local. Confira as instruções aqui. Se você estiver no Google Cloud Shell, não será necessário fazer nada.

Antes da implantação

Se você estiver trabalhando no ambiente local, faça a autenticação no Google Cloud com o seguinte:

  • $ gcloud auth login –update-adc # not needed in Cloud Shell

Isso vai autenticar você usando um login OAuth no navegador. Faça login no Chrome com o mesmo usuário (por exemplo, vattelapesca@gmail.com) que fez login no Google Cloud com o faturamento ativado.

Ative a API Cloud Run com o seguinte comando:

  • $ gcloud services enable run.googleapis.com cloudbuild.googleapis.com

Agora, tudo está pronto para ser implantado no Cloud Run.

Implantar seu app no Cloud Run usando o gcloud

O comando que permite implantar o app no Cloud Run é o gcloud run deploy. Há várias opções para definir e alcançar sua meta. O conjunto mínimo de opções (que você pode fornecer pela linha de comando ou a ferramenta vai solicitar com uma solicitação interativa) é o seguinte:

  1. Nome do serviço do Cloud Run que você quer implantar no app. Um serviço do Cloud Run vai retornar um URL que fornece um endpoint para o app.
  2. Região do Google Cloud em que o app será executado. (--region REGION)
  3. Imagem do contêiner que envolve seu app.
  4. Variáveis de ambiente que o app precisa usar durante a execução.
  5. A flag "allow-unauthenticated" permite que todos acessem seu app sem autenticação.

Consulte a documentação (ou role a tela para baixo e encontre uma possível solução) para saber como aplicar essa opção à sua linha de comando.

A implantação vai levar alguns minutos. Se tudo estiver correto, você verá algo como isto no console do Google Cloud.

ef1029fb62f8de81.png

f7191d579c21ca3e.png

Clique no URL fornecido pelo Cloud Run e teste seu aplicativo. Depois de autenticado, você vai ver algo como isto.

d571a90cd5a373f9.png

"gcloud run deploy" sem argumentos

Você pode ter notado que o gcloud run deploy faz as perguntas certas e preenche os espaços em branco que você deixou. Que máximo!

No entanto, em alguns módulos, vamos adicionar esse comando a um acionador do Cloud Build para não permitir perguntas interativas. Precisamos preencher todas as opções no comando. Você quer criar o gcloud run deploy --option1 blah --foo bar --region your-fav-region dourado. Como fazer isso?

  1. Repita as etapas 2 a 3 a 4 até que o gcloud pare de fazer perguntas:
  2. [LOOP] gcloud run deploy com opções encontradas até o momento
  3. [LOOP] Os sistemas solicitam a opção X
  4. [LOOP] Pesquise nas documentações públicas como configurar X na CLI adicionando a opção --my-option [my-value].
  5. Volte para a etapa 2, a menos que o gcloud conclua sem mais perguntas.
  6. O gcloud run deploy BLAH BLAH BLAH é demais! Salve o comando em algum lugar, porque você vai precisar dele mais tarde para a etapa do Cloud Build.

Uma possível solução está aqui. Confira os documentos aqui.

Parabéns 🎉🎉🎉 Você implantou seu app no Google Cloud e concluiu a primeira etapa da modernização.

6. Módulo 4: Limpar a senha com o Secret Manager

95cd57b03b4e3c73.png

Na etapa anterior, conseguimos implantar e executar o app no Cloud Run. No entanto, fizemos isso com uma prática de segurança inadequada: fornecer alguns segredos em texto não criptografado.

Primeira iteração: atualize o config.php para usar o ENV

Você pode ter notado que colocamos a senha do banco de dados diretamente no código no arquivo config.php. Isso é bom para fins de teste e para conferir se o app funciona. Mas não é possível confirmar/usar esse código em um ambiente de produção. A senha (e outros parâmetros de conexão do banco de dados) precisa ser lida dinamicamente e fornecida ao app no momento da execução. Mude o arquivo config.php para que ele leia os parâmetros do banco de dados das variáveis de ambiente. Se isso falhar, considere definir valores padrão. Isso é bom caso você não consiga carregar o ENV. Assim, a saída da página vai informar se ele está usando os valores padrão. Preencha os espaços em branco e substitua o código no arquivo config.php.

<?php
// Database configuration with ENV variables. Set default values as well 
$db_host = getenv('DB_HOST') ?: 'localhost';
$db_name = getenv('DB_NAME') ?: 'image_catalog';
$db_user = getenv('DB_USER') ?: 'appmod-phpapp-user';
$db_pass = getenv('DB_PASS') ?: 'wrong_password';
// Note getenv() is PHP 5.3 compatible
try {
    $pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("Errore di connessione: " . $e->getMessage());
}

session_start();
?>

Como o app é conteinerizado, você precisa fornecer uma maneira de fornecer as variáveis ENV ao app. Isso pode ser feito de algumas maneiras:

  • No momento do build, no Dockerfile. Adicione os quatro parâmetros ao Dockerfile anterior usando a sintaxe ENV DB_VAR=ENV_VAR_VALUE. Isso vai configurar valores padrão que podem ser substituídos no momento da execução. Por exemplo, "DB_NAME" e "DB_USER" podem ser definidos aqui e em nenhum outro lugar.
  • No momento da execução. É possível configurar essas variáveis para o Cloud Run, usando a CLI ou a interface. Este é o lugar certo para colocar todas as quatro variáveis, a menos que você queira manter os padrões definidos no Dockerfile.

No localhost, talvez seja melhor colocar as variáveis ENV em um arquivo .env (confira a pasta solutions).

Além disso, verifique se o .env foi adicionado ao .gitignore. Não envie seus segredos para o GitHub.

echo .env >> .gitignore

Depois disso, teste a instância localmente:

docker run -it -p 8080:8080 --env-file .env my-php-app-docker

Agora você conseguiu o seguinte:

  1. O app vai ler a variável dinamicamente do ambiente
  2. Você melhorou a segurança, porque removeu a senha do banco de dados do código.

Agora é possível implantar uma nova revisão no Cloud Run. Vamos acessar a interface e definir as variáveis de ambiente manualmente:

  • Acesse https://console.cloud.google.com/run.
  • Clique no seu app.
  • Clique em "Editar e implantar uma nova revisão".
  • Na primeira guia "Contêineres", clique na guia inferior "Variáveis e secrets".
  • Clique em "+ Adicionar variável" e adicione todas as variáveis necessárias. O resultado será algo como:

7a5fbfa448544d3.png

f2780c35585388ca.png

Isso é perfeito? Não. Seu cartão ainda está visível para a maioria dos operadores. Isso pode ser mitigado com o Google Cloud Secret Manager.

Segunda iteração: Secret Manager

Suas senhas desapareceram do seu próprio código: vitória! Mas espere, estamos seguros?

Suas senhas ainda estão visíveis para qualquer pessoa que tenha acesso ao Console do Google Cloud. Na verdade, se você acessar o arquivo de implantação YAML do Cloud Run, vai conseguir fazer a recuperação. Se você tentar editar ou implantar uma nova revisão do Cloud Run, a senha vai aparecer na seção "Variáveis e chaves secretas", conforme mostrado nas capturas de tela abaixo.

O Secret Manager do Google Cloud é um serviço seguro e centralizado para gerenciar informações sensíveis, como chaves de API, senhas, certificados e outros segredos.

Ele permite armazenar, gerenciar e acessar secrets com permissões detalhadas e criptografia robusta. Integrado ao Identity and Access Management (IAM) do Google Cloud, o Secret Manager permite controlar quem pode acessar segredos específicos, garantindo a segurança dos dados e a conformidade regulatória.

Ele também oferece suporte à rotação e ao controle de versões automáticas de segredos, simplificando o gerenciamento do ciclo de vida de segredos e melhorando a segurança em aplicativos em todos os serviços do Google Cloud.

Para acessar o Secret Manager, navegue do menu de navegação para os serviços de segurança e encontre-o na seção Proteção de dados, conforme mostrado na captura de tela abaixo.

6df83a1c3cb757f6.png

Ative a API Secret Manager conforme a imagem abaixo.

a96c312e2c098db1.png

  • Agora clique em Criar um secret: vamos chamar de racional:
  • Nome: php-amarcord-db-pass
  • Valor secreto: sua senha de DB (ignore a parte "upload file").
  • annotate this secret link, deverá ser semelhante a projects/123456789012/secrets/php-amarcord-db-pass. Esse é o ponteiro exclusivo do secret (para Terraform, Cloud Run e outros). Esse número é exclusivo do seu projeto.

Dica: tente usar uma convenção de nomenclatura consistente para seus segredos, especializando-se da esquerda para a direita, por exemplo: cloud-devrel-phpamarcord-dbpass

  • Organização (com a empresa)
  • Equipe (dentro da organização)
  • Solicitação (dentro da equipe)
  • Nome da variável (no app)

Isso permite que você tenha expressões regulares fáceis para encontrar todos os segredos de um único app.

Criar uma nova revisão do Cloud Run

Agora que temos um novo secret, precisamos nos livrar da variável de ambiente DB_PASS e substituí-la pelo novo secret. Então:

  • Acessar o Cloud Run usando o console do Google Cloud
  • Escolha o app.
  • Clique em "Editar e implantar uma nova revisão".
  • localize a guia "Variáveis e secrets".
  • Use o botão "+ Reference a Secret" para redefinir a variável de ambiente DB_PASS.
  • Use o mesmo "DB_PASS" para os segredos referenciados e use a versão mais recente.

9ed4e35be7654dcb.png

Depois disso, você vai receber o seguinte erro:

da0ccd7af39b04ed.png

Tente descobrir como corrigir o problema. Para resolver isso, acesse a seção IAM e administrador e mude as permissões de concessão. Boa depuração!

Depois de descobrir, volte ao Cloud Run e implante uma nova revisão. O resultado vai ficar assim:

e89f9ca780169b6b.png

Dica: o console do desenvolvedor (IU) é ótimo para apontar problemas de permissão. Navegue por todos os links das suas entidades do Cloud.

7. Módulo 5: configurar seu CI/CD com o Cloud Build

ba49b033c11be94c.png

Por que usar um pipeline de CI/CD?

Até agora, você já deve ter digitado gcloud run deploy algumas vezes, talvez respondendo à mesma pergunta várias vezes.

Cansou de implantar o app manualmente com o gcloud run deploy? Não seria ótimo se o app pudesse ser implantado automaticamente sempre que você enviasse uma nova alteração para o repositório do Git?

Para usar um pipeline de CI/CD, você precisa de duas coisas:

  1. Um repositório pessoal do Git: felizmente, você já deve ter bifurcado o repositório do workshop na sua conta do GitHub na etapa 2. Caso contrário, volte e conclua essa etapa. O repositório bifurcado vai ficar assim: https://github.com/<YOUR_GITHUB_USER>/app-mod-workshop
  2. Cloud Build. Esse serviço incrível e barato permite configurar a automação de build para quase tudo: Terraform, apps dockerizados etc.

Esta seção vai se concentrar na configuração do Cloud Build.

Entrar no Cloud Build

Vamos usar o Cloud Build para fazer o seguinte:

  • crie sua fonte (com o Dockerfile). Pense nisso como um "arquivo ZIP grande" que contém tudo o que você precisa para criar e executar (o "artefato de build").
  • Envie esse artefato para o Artifact Registry (AR).
  • Em seguida, faça uma implantação do AR para o Cloud Run para o app "php-amarcord".
  • Isso vai criar uma nova versão ("revisão") do app atual (pense em uma camada com o novo código) e vamos configurá-la para desviar o tráfego para a nova versão, se o push for bem-sucedido.

Este é um exemplo de alguns builds para meu app php-amarcord:

f30f42d4571ad5e2.png

Como fazer tudo isso?

  1. Ao criar um arquivo YAML perfeito: cloudbuild.yaml
  2. Criando um gatilho do Cloud Build.
  3. Conectando-se ao nosso repositório do GitHub pela interface do Cloud Build.

Criar gatilho (e conectar repositório)

  • Acesse https://console.cloud.google.com/cloud-build/triggers.
  • Clique em "Criar gatilho".
  • Compilar:
  • Nome: algo significativo, como on-git-commit-build-php-app
  • Evento: enviar por push para a ramificação
  • Origem: "Conectar novo repositório" texto alternativo
  • Isso vai abrir uma janela à direita: "Conectar repositório".
  • Provedor de origem: "Github" (primeiro)
  • "Continuar"
  • A autenticação vai abrir uma janela no GitHub para fazer a autenticação cruzada. Siga o fluxo e seja paciente. Se você tiver muitos repositórios, isso pode levar um tempo.
  • "Select repo": selecione sua conta/repo e marque a parte "I understand...".
  • Se você recebeu a mensagem de erro: "O app GitHub não está instalado em nenhum dos seus repositórios", clique em "Instalar o Google Cloud Build" e siga as instruções.
  • 23e0e0f1219afea3.pngClique em "Conectar"
  • bafd904ec07122d2.png
  • Bingo! Seu repositório está conectado.
  • Voltando à parte do acionador...
  • Configuração: Detectado automaticamente (*)
  • Avançado: selecione a conta de serviço "[PROJECT_NUMBER]- compute@developer.gserviceaccount.com"
  • xxxxx é o ID do projeto.
  • A conta de serviço de computação padrão é adequada para uma abordagem de laboratório. Não a use em produção. Saiba mais.
  • Deixe tudo como está.
  • Clique no botão "Criar".

(*) Essa é a maneira mais simples, porque verifica o Dockerfile ou o cloudbuild.yaml. No entanto, o cloudbuild.yaml dá a você o poder real de decidir o que fazer em cada etapa.

Eu tenho o poder!

O acionador não vai funcionar a menos que você conceda à conta de serviço do Cloud Build (o que é uma conta de serviço? O e-mail de um "robô" que atua em seu nome para uma tarefa. Neste caso, criar coisas na nuvem.

O SA não vai conseguir criar e implantar se você não der a ele permissão para fazer isso. Felizmente, é fácil.

  • Acesse "Cloud Build" > "Configurações".
  • Conta de serviço "[PROJECT_NUMBER]- compute@developer.gserviceaccount.com"
  • Marque estas caixas:
  • Cloud Run
  • Secret Manager
  • Contas de serviço
  • Cloud Build
  • Marque também a opção "Definir como conta de serviço preferencial".

8715acca72286a46.png

Onde está o YAML do Cloud Build?

Recomendamos que você passe algum tempo criando seu próprio YAML do Cloud Build.

No entanto, se você não tiver tempo ou não quiser fazer isso, pode se inspirar nesta pasta de soluções: .solutions

Agora você pode enviar uma mudança para o GitHub e observar o Cloud Build.

Configurar o Cloud Build pode ser complicado. É possível que haja algumas idas e vindas:

  • Ver os registros em https://console.cloud.google.com/cloud-build/builds;region=global
  • Como encontrar o erro.
  • Correção no código e emissão de novo git commit / git push.
  • Às vezes, o erro não está no código, mas em alguma configuração. Nesse caso, é possível emitir um novo build na interface (build na nuvem > "Triggers" > Executar).

97acd16980a144ab.png

Se você usar essa solução, ainda vai precisar fazer mais algumas coisas. Por exemplo, você precisa definir as variáveis ENV para os endpoints de desenvolvimento/produção recém-criados:

3da8723e4ff80c0a.png

Faça isso de duas maneiras:

  • Pela interface, definindo as variáveis de ambiente novamente
  • Com a CLI, criando o script "perfeito" para você. Confira um exemplo aqui: gcloud-run-deploy.sh . Você precisa ajustar algumas coisas, por exemplo, o endpoint e o número do projeto. Você pode encontrar o número do projeto na Visão geral do Cloud.

Como faço para confirmar o código no GitHub?

Este workshop não ensina a melhor maneira de git push para o github. No entanto, se você estiver com problemas e estiver no Cloud Shell, há duas maneiras:

  1. CLI. Adicione uma chave SSH localmente e adicione um controle remoto com git@github.com:YOUR_USER/app-mod-workshop.git (em vez de http)
  2. VSCode. Se você usa o editor do Cloud Shell, pode usar a guia "Controle de origem" (Ctrl-Shift-G), clicar em "Sincronizar mudanças" e seguir as instruções. Você poderá autenticar sua conta do GitHub no VSCode, e o pull/push será muito fácil.

f0d53f839c7fa3b6.png

Não se esqueça de git add clodubuild.yaml entre outros arquivos, ou ele não vai funcionar.

"Paridade de desenvolvimento/produção" profunda x superficial [opcional]

Se você copiou a versão do modelo deste link, terá duas versões idênticas de DESENVOLVIMENTO e PRODUÇÃO. Isso é legal e está de acordo com a regra 10 do app de 12 fatores.

No entanto, estamos usando dois endpoints da Web diferentes para que um app aponte para o mesmo banco de dados. Isso é bom o suficiente para um workshop. No entanto, na vida real, você precisa dedicar algum tempo para criar um ambiente de produção adequado. Isso significa ter dois bancos de dados (um para desenvolvimento e outro para produção) e também escolher onde colocá-los para recuperação de desastres / alta disponibilidade. Isso vai além do escopo deste workshop, mas é um bom tema para reflexão.

Se você tiver tempo para fazer uma versão "profunda" da produção, considere todos os recursos que precisa duplicar, como:

  • Banco de dados do Cloud SQL (e provavelmente a instância do SQL).
  • Bucket do GCS
  • Função do Cloud.
  • Você pode usar o Gemini 1.5 Flash como um modelo em desenvolvimento (mais barato e rápido) e o Gemini 1.5 Pro (mais poderoso).

Em geral, sempre que você fizer algo relacionado ao app, pense criticamente: a produção precisa ter esse mesmo valor ou não? Se não, duplique seu esforço. Isso é muito mais fácil com o Terraform, em que você pode injetar seu ambiente (-dev, -prod) como um sufixo aos seus recursos.

8. Módulo 6: Mover para o Google Cloud Storage

a680e0f287dd2dfb.png

Armazenamento

dc3a4b8ea92aaef6.png

Atualmente, o app armazena o estado em um contêiner do Docker. Se a máquina quebrar, o app explodir ou você enviar uma nova revisão, uma nova revisão será programada, com um novo armazenamento vazio: 🙈

Como corrigir o problema? Há várias abordagens.

  1. Armazene imagens no banco de dados. Foi o que acabei fazendo com meu app PHP anterior. É a solução mais simples, porque não adiciona complexidade. Mas isso aumenta a latência e a carga no seu banco de dados.
  2. Migrar seu app do Cloud Run para uma solução compatível com armazenamento: GCE + disco permanente? Talvez GKE + Armazenamento? Observação: o que você ganha em controle, você perde em agilidade.
  3. Mover para o GCS. O Google Cloud Storage oferece o melhor armazenamento para todo o Google Cloud e é a solução mais idiomática do Cloud. No entanto, isso exige que você se suja com bibliotecas PHP. Temos bibliotecas do PHP 5.7 para o GCS? O PHP 5.7 oferece suporte a Composer? Parece que o PHP 5.3.2 é a versão mais antiga com suporte do Composer.
  4. Talvez usar um sidecar do Docker?
  5. Ou use as montagens de volume do Cloud Run do GCS. Isso é incrível.

🤔 Migrar armazenamento (sem limite)

[Aberta] Neste exercício, queremos que você encontre uma solução para mover suas imagens de uma forma que seja mantida de alguma forma.

Teste de aceitação

Não quero dizer a solução, mas quero que isso aconteça:

  1. Você faz upload de newpic.jpg. Você vai encontrar essa informação no app.
  2. Você atualiza o app para uma nova versão.
  3. newpic.jpg ainda está lá, visível.

💡 Solução possível (montagens de volume do Cloud Run do GCS)

Essa é uma solução muito elegante que permite fazer uploads de arquivos com estado sem tocar no código (exceto para mostrar uma descrição da imagem, mas isso é trivial e apenas para satisfação visual).

Isso permite que você monte uma pasta do Cloud Run para o GCS:

  1. Todos os uploads para o GCS vão ficar visíveis no seu app.
  2. Todos os uploads no seu app serão enviados para o GCS
  3. A mágica vai acontecer com os objetos enviados para o GCS (capítulo 7).

Observação: Leia os detalhes do FUSE. Isso NÃO é adequado se a performance for um problema.

Crie um bucket do GCS

O GCS é o serviço de armazenamento onipresente do Google Cloud. Ele foi testado e é usado por todos os serviços do GCP que precisam de armazenamento.

O Cloud Shell exporta PROJECT_ID como GOOGLE_CLOUD_PROJECT:

$ export PROJECT_ID=$GOOGLE_CLOUD_PROJECT

#!/bin/bash

set -euo pipefail

# Your Cloud Run Service Name, eg php-amarcord-dev
SERVICE_NAME='php-amarcord-dev'
BUCKET="${PROJECT_ID}-public-images"
GS_BUCKET="gs://${BUCKET}"

# Create bucket
gsutil mb -l "$GCP_REGION" -p "$PROJECT_ID" "$GS_BUCKET/"

# Copy original pictures there - better if you add an image of YOURS before.
gsutil cp ./uploads/*.png "$GS_BUCKET/"

Configure o Cloud Run para montar o bucket na pasta /uploads/

Agora vamos para a parte elegante. Criamos um volume php_uploads e instruímos o Cloud Run a fazer uma montagem FUSE em MOUNT_PATH (algo como /var/www/html/uploads/):

#!/bin/bash

set -euo pipefail

# .. keep variables from previous script..

# Uploads folder within your docker container.
# Tweak it for your app code.
MOUNT_PATH='/var/www/html/uploads/'

# Inject a volume mount to your GCS bucket in the right folder.
gcloud --project "$PROJECT_ID" beta run services update "$SERVICE_NAME" \
    --region $GCP_REGION \
    --execution-environment gen2 \
    --add-volume=name=php_uploads,type=cloud-storage,bucket="$BUCKET"  \
    --add-volume-mount=volume=php_uploads,mount-path="$MOUNT_PATH"

Agora, repita esta etapa para todos os endpoints que você quer apontar para o Cloud Storage.

Também é possível fazer isso na interface

  1. Na guia "Volumes", crie um Volume Mounts que aponte para seu bucket, do tipo "bucket do Cloud Storage", por exemplo, com o nome "php_uploads".
  2. Em "Container(s)> Volume Mounts", monte o volume que você acabou de criar no ponto de volume solicitado pelo app. Isso depende do dockerfile, mas pode ser semelhante a var/www/html/uploads/ .

De qualquer forma, se funcionar, a edição da nova revisão do Cloud Run vai mostrar algo como isto:

6c2bb98fc1b0e077.png

Agora teste o novo aplicativo fazendo o upload de uma nova imagem para o endpoint /upload.php.

As imagens devem fluir perfeitamente no GCS sem escrever uma única linha de PHP:

70032b216afee2d7.png

O que acabou de acontecer?

Algo muito mágico aconteceu.

Um aplicativo antigo com um código antigo ainda está fazendo o trabalho. Uma pilha nova e modernizada permite que todas as imagens do nosso app fiquem confortavelmente em um bucket do Cloud com estado. Agora o céu é o limite:

  • Quer enviar um e-mail sempre que uma imagem com "perigoso" ou "nudo" for recebida? Isso pode ser feito sem tocar no código PHP.
  • Quer usar um modelo multimodal do Gemini sempre que uma imagem for enviada para descrever e fazer upload do DB com a descrição? Isso pode ser feito sem tocar no código PHP. Você não acredita em mim? Continue lendo no capítulo 7.

Acabamos de abrir um grande espaço de oportunidades.

9. Módulo 7: Aprimorar seu app com o Google Gemini

c00425f0ad83b32c.png

Agora você tem um novo app PHP moderno e moderno (como um Fiat 126 2024) com armazenamento na nuvem.

O que você pode fazer com ele?

Pré-requisitos

No capítulo anterior, uma solução de modelo nos permitiu montar imagens /uploads/ no GCS, de fato separando a lógica do app do armazenamento de imagens.

Neste exercício, você precisa:

  • Ter concluído o exercício do capítulo 6 (armazenamento).
  • Ter um bucket do GCS com os uploads de imagem, em que as pessoas fazem upload de imagens no seu app e as imagens fluem para o bucket.

Configurar uma função do Cloud (em Python)

Você já se perguntou como implementar um aplicativo orientado a eventos? Por exemplo:

  • quando <event> acontece => enviar um e-mail
  • quando <event> acontece => se <condition> for verdadeira, atualize o banco de dados.

O evento pode ser qualquer coisa, desde um novo registro disponível no BigQuery, um novo objeto alterado em uma pasta no GCS ou uma nova mensagem aguardando em uma fila no Pub/Sub.

O Google Cloud oferece suporte a vários paradigmas para isso. Em especial:

Neste exercício, vamos nos aprofundar na função do Cloud para alcançar um resultado bastante espetacular. E vamos oferecer exercícios opcionais para você.

O código de exemplo está disponível em .solutions/.

Configurar uma função do Cloud (🐍 Python)

Estamos tentando criar um GCF muito ambicioso.

  1. Quando uma nova imagem é criada no GCS. (provavelmente porque alguém fez o upload no app, mas não só isso)
  2. .. call Gemini to describe it and get a textual description of the image .. (seria bom verificar o MIME e garantir que seja uma imagem e não um PDF, MP3 ou texto)
  3. .. e atualize o banco de dados com essa descrição. Isso pode exigir a correção do banco de dados para adicionar uma coluna description à tabela images.

Corrigir o banco de dados para adicionar description às imagens

  1. Abra o Cloud SQL Studio:

b92b07c4cba658ef.png

  1. Coloque seu usuário e senha para o banco de dados de imagens
  2. Injete este SQL, que adiciona uma coluna para uma descrição de imagem:

ALTER TABLE images ADD COLUMN description TEXT;

3691aced78a6389.png

E bingo! Tente agora para conferir se funcionou:

SELECT * FROM images;

A nova coluna de descrição vai aparecer:

bed69d6ad0263114.png

Escreva a função f(x) do Gemini

Observação: Essa função foi criada com a ajuda do Gemini Code Assist.

Observação: Ao criar essa função, você pode ter erros de permissão do IAM. Alguns estão documentados abaixo no parágrafo "Possíveis erros".

  1. Ative as APIs
  2. Acesse https://console.cloud.google.com/functions/list.
  3. Clique em "Criar função".
  4. Ative as APIs no assistente de APIs:

d22b82658cfd4c48.png

É possível criar o GCF na interface ou na linha de comando. Aqui vamos usar a linha de comando.

Um possível código pode ser encontrado em .solutions/

  1. Crie uma pasta para hospedar seu código, por exemplo, "gcf/". Entre na pasta.
  2. Crie um arquivo requirements.txt:
google-cloud-storage
google-cloud-aiplatform
pymysql
  1. Crie uma função Python. Exemplo de código aqui: gcf/main.py.
#!/usr/bin/env python

"""Complete this"""

from google.cloud import storage
from google.cloud import aiplatform
import vertexai
from vertexai.generative_models import GenerativeModel, Part
import os
import pymysql
import pymysql.cursors

# Replace with your project ID
PROJECT_ID = "your-project-id"
GEMINI_MODEL = "gemini-1.5-pro-002"
DEFAULT_PROMPT = "Generate a caption for this image: "

def gemini_describe_image_from_gcs(gcs_url, image_prompt=DEFAULT_PROMPT):
    pass

def update_db_with_description(image_filename, caption, db_user, db_pass, db_host, db_name):
    pass

def generate_caption(event, context):
    """
    Cloud Function triggered by a GCS event.
    Args:
        event (dict): The dictionary with data specific to this type of event.
        context (google.cloud.functions.Context): The context parameter contains
                                                event metadata such as event ID
                                                and timestamp.
    """
    pass
  1. Envie a função. Você pode usar um script semelhante a este: gcf/push-to-gcf.sh.

Observação 1. Forneça os ambientes com os valores corretos ou adicione-os na parte de cima (GS_BUCKET=blah, ..):

Observação 2. Isso vai enviar todo o código local (.). Portanto, inclua seu código em uma pasta específica e use .gcloudignore como um profissional para evitar enviar bibliotecas enormes. ( exemplo).

#!/bin/bash

set -euo pipefail

# add your logic here, for instance:
source .env || exit 2 

echo "Pushing ☁️ f(x)☁ to 🪣 $GS_BUCKET, along with DB config.. (DB_PASS=$DB_PASS)"

gcloud --project "$PROJECT_ID" functions deploy php_amarcord_generate_caption \
    --runtime python310 \
    --region "$GCP_REGION" \
    --trigger-event google.cloud.storage.object.v1.finalized \
    --trigger-resource "$BUCKET" \
    --set-env-vars "DB_HOST=$DB_HOST,DB_NAME=$DB_NAME,DB_PASS=$DB_PASS,DB_USER=$DB_USER" \
    --source . \
    --entry-point generate_caption \
    --gen2

Observação: neste exemplo, generate_caption será o método invocado, e a Função do Cloud vai transmitir o evento do GCS a ele com todas as informações relevantes (nome do bucket, nome do objeto etc.). Dedique algum tempo para depurar o dicionário Python do evento.

Como testar a função

Testes de unidade

A função tem muitas partes móveis. Talvez você queira testar todos os elementos individuais.

Um exemplo está em gcf/test.py.

Interface do Cloud Functions

Também reserve um tempo para explorar sua função na interface. Vale a pena conferir todas as guias, principalmente Source (minha favorita), Variables, Trigger e Logs. Você vai passar muito tempo na Logs para resolver problemas (confira também os possíveis erros na parte de baixo desta página). Verifique também a Permissions.

cf3ded30d532a2c7.png

Teste E2E

É hora de testar a função manualmente.

  1. Acesse o app e faça login
  2. Faça o upload de uma imagem (não muito grande, já tivemos problemas com imagens grandes)
  3. verifique na interface se a imagem foi enviada.
  4. Verifique no Cloud SQL Studio se a descrição foi atualizada. Faça login e execute esta consulta: SELECT * FROM images.

43a680b12dbbdda0.png

E funciona. Também podemos atualizar o front-end para mostrar essa descrição.

Atualizar o PHP para mostrar [opcional]

Provamos que o app funciona. No entanto, seria bom que os usuários também pudessem ver essa descrição.

Não precisamos ser especialistas em PHP para adicionar a descrição ao index.php. Este código vai fazer (sim, o Gemini também escreveu isso para mim):

<?php if (!empty($image['description'])): ?>
    <p class="font-bold">Gemini Caption:</p>
    <p class="italic"><?php echo $image['description']; ?></p>
<?php endif; ?>

Posicione esse código dentro de foreach como preferir.

Nas próximas etapas, também vamos conferir uma versão mais bonita da interface, graças ao Gemini Code Assist. Uma versão bonita pode ser assim:

fdc12de0c88c4464.png

Conclusões

Você tem uma função do Cloud acionada em novos objetos que chegam ao GCS e que pode anotar o conteúdo da imagem como um humano faria e atualizar automaticamente o banco de dados. Uau!

A seguir Você pode seguir o mesmo raciocínio para alcançar duas grandes funcionalidades.

[Opcional] Adicionar mais funções do Cloud [sem fim definido]

Alguns recursos adicionais vêm à mente.

📩 Acionar e-mail

Um gatilho de e-mail que envia um e-mail para você sempre que alguém envia uma foto.

  • Com muita frequência? Adicione outra restrição: uma imagem GRANDE ou uma imagem com conteúdo do Gemini que contenha as palavras "nude/nudity/violent".
  • Verifique EventArc para isso.

🚫 Moderação automática de fotos inadequadas

No momento, um administrador humano está sinalizando imagens como "inadequadas". Que tal deixar o Gemini fazer o trabalho pesado e moderar o espaço? Adicione um teste para sinalizar conteúdo de gatilho inadequado e atualizar o banco de dados, conforme aprendemos na função anterior. Isso significa basicamente pegar a função anterior, mudar a solicitação e atualizar o banco de dados com base na resposta.

Observação. A IA generativa tem saídas imprevisíveis. Verifique se a "saída do criativo" do Gemini está "em trilhos". Você pode pedir uma resposta determinística, como uma pontuação de confiança de 0 a 1, um JSON etc. Isso pode ser feito de várias maneiras, por exemplo: * Usando bibliotecas Python pydantic, langchain, etc. * Usando a saída estruturada do Gemini.

Dica. Você pode ter VÁRIAS funções ou um único comando que exija uma resposta JSON (funciona muito bem com a "Saída estruturada do Gemini", conforme destacado acima), como:

Qual seria a instrução para gerar isso?

{
    "description": "This is the picture of an arrosticino",
    "suitable": TRUE
}

Você pode adicionar outros campos ao comando para receber insights como: "Há algo bom nisso?". Você se sente mal por isso? Você reconhece o lugar? Há algum texto (o OCR nunca foi tão fácil):

  • goods: "It looks like yummie food"
  • bads: "Parece comida não saudável"
  • OCR: "Da consumare preferibilmente prima del 10 Novembre 2024"
  • location: "Pescara, Lungomare"

Embora geralmente seja melhor ter uma função N para resultados N, é muito gratificante fazer uma que faça 10 coisas. Confira este artigo de Riccardo para saber como.

Possíveis erros (principalmente IAM / permissões)

Quando desenvolvi essa solução pela primeira vez, encontrei alguns problemas de permissão do IAM. Vou adicionar essas informações aqui para mostrar empatia e dar algumas ideias sobre como corrigir os problemas.

Erro: permissões insuficientes para a conta de serviço

  1. Para implantar uma função do GCF que escuta um bucket do GCS, é necessário configurar as permissões adequadas na conta de serviço que você está usando para o job, como na figura:

22f51012fa6b4a24.png

Talvez você também precise ativar as APIs do Eventarc. Isso pode levar alguns minutos até que elas fiquem totalmente disponíveis.

Erro: invocador do Cloud Run ausente

  1. Outro comentário da interface para a permissão do GCF é este ( papel de Invocador do Cloud Run):

be72e17294f2d3f3.png

Esse erro pode ser corrigido executando o comando na imagem, que é semelhante a fix-permissions.sh.

Esse problema é descrito aqui: https://cloud.google.com/functions/docs/securing/authenticating

Erro: limite de memória excedido

Na primeira vez que executei, os registros disseram: "O limite de memória de 244 MiB foi excedido com 270 MiB usados. Aumente o limite de memória. Consulte https://cloud.google.com/functions/docs/configuring/memory. Novamente, adicione RAM ao GCF. Isso é muito fácil de fazer na interface. Confira uma possível solução:

bed69d6ad0263114.png

Como alternativa, você também pode corrigir o script de implantação do Cloud Run para aumentar a MEM/CPU. Isso demora um pouco mais.

Erro: PubSub publicado

A criação de um acionador com a GCF v1 gerou este erro:

e5c338ee35ad4c24.png

Novamente, é fácil corrigir isso acessando o IAM e atribuindo à sua conta de serviço o papel de "Editor do Pub/Sub".

Erro: a Vertex AI não foi usada

Se você receber este erro:

Permissão negada: 403 a API Vertex AI não foi usada no projeto YOUR_PROJECT antes ou está desativada. Ative-a acessando https://console.developers.google.com/apis/api/aiplatform.googleapis.com/overview?project=YOR_PROJECT

Basta ativar as APIs Vertex AI. A maneira mais fácil de ativar TODAS as APIs necessárias é esta:

  1. https://console.cloud.google.com/vertex-ai
  2. Clique em "Ativar todas as APIs recomendadas".

492f05ac377f3630.png

Erro: o acionador do EventArc não foi encontrado.

Se isso acontecer, reimplante a função.

8ec4fc11833d7420.png

Erro: 400 Agentes de serviço estão sendo provisionados

400 Os agentes de serviço estão sendo provisionados ( https://cloud.google.com/vertex-ai/docs/general/access-control#service-agents ). Os agentes de serviço são necessários para ler o arquivo do Cloud Storage fornecido. Tente novamente em alguns minutos.

Se isso acontecer, aguarde um pouco ou pergunte a um Googler.

10. Módulo 8: Criar SLOs de disponibilidade

Neste capítulo, tentamos alcançar o seguinte:

  1. Como criar SLIs
  2. Como criar SLOs com base nos SLIs
  3. Como criar alertas com base em SLOs

f63426182c052123.png

Esse é um tema muito importante para o autor, já que Riccardo trabalha na área de SRE / DevOps do Google Cloud.

(sem resposta) Criar SLIs e SLOs para este app

Um app é bom se você não consegue saber quando ele está inativo?

O que é um SLO?

Ah! O Google inventou os SLOs! Para saber mais, sugiro:

Etapa 1: criar um SLI/SLO de disponibilidade

Vamos começar com o SLO de disponibilidade, porque é a métrica mais fácil e possivelmente a mais importante que você quer medir.

Felizmente, o Cloud Run tem suporte pré-criado para SLO, graças ao Istio.

Depois que o app está no Cloud Run, isso é muito simples de fazer. Leva 30 segundos.

  • Acesse a página do Cloud Run.
  • Clique/selecione o app.
  • Selecione a guia SLOs.
  • Clique em "+ Criar SLO".
  • Disponibilidade, com base na solicitação
  • Continuar
  • Mês no calendário / 99%.
  • Clique em "Criar SLO".

e471c7ebdc56cdf6.png

Etapa 2: configurar o alerta para este SLO

Sugiro criar dois alertas:

  1. Um com uma taxa de queima baixa ("Queima lenta") para alertar você por e-mail (simula um bilhete de prioridade baixa).
  2. Um com uma taxa de queima alta ("queima rápida") para alertar você por SMS (simula um pager / ticket de alta prioridade)

Acesse sua SLO tab anterior.

Faça isso duas vezes:

314bfd6b9ef0a260.png

  • Clique em "Criar alerta de SLO" (o botão 🔔 com um sinal de adição à direita).
  • Duração do lookback e limite do índice de desempenho de custo:
  • [RÁPIDO]. Primeiro: 60 min / 10 x
  • [LENTO]. Segundo: 720 min / 2 x
  • Canal de notificação: clique em "Gerenciar canais de notificação"
  • Primeiro, "E-mail" -> Adicionar novo -> ..
  • Em segundo lugar, "SMS" -> Adicionar novo -> Verificar no telefone.
  • Dica: eu gosto de usar emojis nos nomes. É divertido para demonstrações.
  • Quando terminar, clique no X grande no canto superior direito.
  • Selecione o telefone primeiro (rápido) e depois o e-mail (lento).
  • Adicione alguns exemplos de documentação, como:
  • [PHP Amarcord] Riccardo told me to type sudo reboot or to check documentation in http://example.com/playbooks/1.php but I guess he was joking.

Bingo!

Resultado final

Consideraremos este exercício concluído quando você tiver um SLO em funcionamento e dois alertas para sua disponibilidade, além de alertas no seu e-mail e no seu smartphone.

Se quiser, adicione uma latência (recomendo que você faça isso) ou até mesmo uma mais complexa. Para a latência, escolha uma latência que você considere razoável. Em caso de dúvida, escolha 200ms.

11. Próximas etapas

Você concluiu TUDO, o que está faltando?

Algumas ideias para você pensar:

Jogar com o Gemini

Você pode usar o Gemini de duas maneiras:

  1. Vertex AI. O "caminho empresarial", entrelaçado com o GCP, que abordamos no capítulo 7 (GCF+Gemini). Toda a autenticação funciona magicamente, e os serviços se interconectam perfeitamente.
  2. IA do Google. A "maneira do consumidor". Você recebe uma chave de API do Gemini aqui e começa a criar pequenos scripts que podem ser vinculados a qualquer carga de trabalho que você já tenha (trabalho reservado, outras nuvens, localhost etc.). Basta substituir a chave de API, e o código começa a funcionar magicamente.

Recomendamos que você tente explorar o (2) com seus próprios projetos pessoais.

Levantamento de interface

Não sou bom com interfaces. Mas o Gemini é! Você pode usar uma única página PHP e dizer algo como:

I have a VERY old PHP application. I want to touch it as little as possible. Can you help me:

1. add some nice CSS to it, a single static include for tailwind or similar, whatever you prefer
2. Transform the image print with description into cards, which fit 4 per line in the canvas?

Here's the code:

-----------------------------------
[Paste your PHP page, for instance index.php - mind the token limit!]

Você pode fazer isso facilmente em menos de cinco minutos com o Cloud Build. :)

A resposta do Gemini foi perfeita, ou seja, não precisei mudar nada:

8a3d5fe37ec40bf8.png

Confira o novo layout no app pessoal do autor:

81620eb90ae3229a.png

Observação: o código é colado como imagem porque não queremos que você o use, mas sim que o Gemini o escreva para você, com suas próprias restrições criativas de IU/front-end. Confie em mim, você vai ter mudanças muito pequenas depois.

Segurança

Proteger adequadamente esse app não é o objetivo deste workshop de quatro horas, porque isso aumentaria o tempo de conclusão em uma ou duas ordens de magnitude.

No entanto, esse tópico é superimportante. Reunimos algumas ideias em SECURITY.

12. Parabéns!

Parabéns 🎉🎉🎉 , você modernizou seu aplicativo PHP legado com o Google Cloud.

24cb9a39b1841fbd.png

Resumindo, você aprendeu neste codelab:

  • Como implantar um banco de dados no Google Cloud SQL e como migrar seu banco de dados atual para ele.
  • Como contêinerizar seu aplicativo PHP com o Docker e os Buildpacks e armazenar a imagem no Google Cloud Artifact Registry
  • Como implantar seu app conteinerizado no Cloud Run e fazer com que ele seja executado com o Cloud SQL
  • Como armazenar/usar secretamente parâmetros de configuração sensíveis (como a senha do banco de dados) usando o Google Secret Manager
  • Como configurar o pipeline de CI/CD com o Google Cloud Build para criar e implantar automaticamente seu app PHP em qualquer envio de código para o repositório do GitHub.
  • Como usar o Cloud Storage para "migrar para a nuvem" os recursos do app
  • Como aproveitar as tecnologias sem servidor para criar fluxos de trabalho incríveis no Google Cloud sem tocar no código do app.
  • Use os recursos multimodais do Gemini para um caso de uso adequado.
  • Implementar os princípios de SRE no Google Cloud

Esse é um ótimo começo para sua jornada de modernização de aplicativos com o Google Cloud.

🔁 Feedback

Se quiser nos contar sobre sua experiência com este workshop, preencha este formulário de feedback.

Agradecemos seu feedback e PRs para partes do código das quais você tem orgulho.

🙏 Agradecemos

O autor gostaria de agradecer a Mirko Gilioli e Maurizio Ipsale da Datatonic pela ajuda na redação e no teste da solução.