Znajdowanie i rozwiązywanie problemów z aplikacjami za pomocą Gemini Cloud Assist

1. Wprowadzenie

Gemini Cloud Assist to w pełni funkcjonalny agent, który obsługuje Twoje zbiory zadań Google Cloud. Agent pomoże Ci w projektowaniu nowych aplikacji lub aktualizowaniu istniejących, wdrażaniu i uruchamianiu zadań w Google Cloud, rozwiązywaniu problemów z zadaniami oraz optymalizowaniu ich pod kątem kosztów i wydajności.

Gemini Cloud Assist ułatwia reagowanie na nieoczekiwane błędy i przestoje.

Czego się nauczysz

  1. Wdrażanie: jak wdrożyć podstawowy backend i bazę danych w Google Cloud.
  2. Debugowanie: jak Gemini Cloud Assist automatyzuje analizę i analizę głównych przyczyn problemów z chmurą i kodem.
  3. Działanie naprawcze: jak Gemini Cloud Assist pomaga w określaniu poprawek na podstawie głównej przyczyny.

2. Konfigurowanie projektu

Konto Google

Jeśli nie masz jeszcze osobistego konta Google, musisz je utworzyć.

Używaj konta osobistego zamiast konta służbowego lub szkolnego.

Logowanie się w konsoli Google Cloud

Zaloguj się w konsoli Google Cloud, korzystając z osobistego konta Google.

Włącz płatności

Konfigurowanie osobistego konta rozliczeniowego

Jeśli skonfigurujesz płatności za pomocą środków w Google Cloud, możesz pominąć ten krok.

Aby skonfigurować osobiste konto rozliczeniowe, włącz płatności w konsoli Google Cloud.

Uwagi:

Tworzenie projektu (opcjonalnie)

Jeśli nie masz bieżącego projektu, którego chcesz użyć w tym ćwiczeniu, utwórz nowy projekt.

3. Otwórz edytor Cloud Shell

  1. Kliknij ten link, aby przejść bezpośrednio do edytora Cloud Shell
  2. Jeśli w dowolnym momencie pojawi się prośba o autoryzację, kliknij Autoryzuj, aby kontynuować.Kliknij, aby uwierzytelnić się w Cloud Shell
  3. Jeśli terminal nie pojawi się u dołu ekranu, otwórz go:
    • Kliknij Wyświetl.
    • Kliknij TerminalOtwieranie nowego terminala w edytorze Cloud Shell.
  4. W terminalu ustaw projekt za pomocą tego polecenia:
    gcloud config set project [PROJECT_ID]
    
    • Przykład:
      gcloud config set project lab-project-id-example
      
    • Jeśli nie pamiętasz identyfikatora projektu, możesz wyświetlić listę wszystkich identyfikatorów projektów za pomocą tego polecenia:
      gcloud projects list
      
      Ustawianie identyfikatora projektu w terminalu edytora Cloud Shell
  5. Powinien wyświetlić się ten komunikat:
    Updated property [core/project].
    

4. Włącz interfejsy API

Aby wdrożyć komponenty aplikacji i korzystać z Google Cloud Assist, włącz te interfejsy API:

W terminalu włącz interfejsy API:

```bash
gcloud services enable \
  container.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  alloydb.googleapis.com \
  run.googleapis.com
```
<br>
When the command finishes, you should see an output like the following: 
<br>

```console
Operation "operations/acf.p2-176675280136-b03ab5e4-3483-4ebf-9655-43dc3b345c63" finished successfully.
```

5. Przygotowywanie projektu

Utworzysz podstawową aplikację i wdrożenie, aby przetestować Cloud Assist.

Tworzenie katalogu

  1. Otwórz edytor Cloud Shell lub wybrane środowisko deweloperskie.
  2. Tworzenie nowego folderu:
    mkdir -p ~/gemini-cloud-assist-debug
    mkdir -p ~/gemini-cloud-assist-debug/auth_issue_demo
    mkdir -p ~/gemini-cloud-assist-debug/terraform
    cd ~/gemini-cloud-assist-debug
    
  3. W terminalu uruchom to polecenie, aby otworzyć obszar roboczy edytora Cloud Shell:
cloudshell open-workspace ~/gemini-cloud-assist-debug

Tworzenie plików

Teraz utworzysz niezbędne pliki początkowe aplikacji.

  1. Utwórz plik Dockerfile, uruchamiając w terminalu to polecenie: Ten plik odpowiada za utworzenie kontenera aplikacji.
cat <<EOF > ~/gemini-cloud-assist-debug/auth_issue_demo/Dockerfile
FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY main.py .

CMD ["gunicorn", "--bind", "0.0.0.0:8080", "main:app"]
EOF
  1. Utwórz plik main.py, uruchamiając w terminalu to polecenie: Ten plik zawiera aplikację napisaną w języku Python.
cat <<EOF > ~/gemini-cloud-assist-debug/auth_issue_demo/main.py
import os
import logging
from flask import Flask
from google.cloud.alloydb.connector import Connector
import sqlalchemy

app = Flask(__name__)

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Configuration from Environment Variables
# The fully qualified instance URI: projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>
ALLOYDB_URI = os.environ.get("ALLOYDB_URI") 
DB_USER = os.environ.get("DB_USER", "auth-debug")
DB_PASS = os.environ.get("DB_PASS", "debug-auth")
DB_NAME = os.environ.get("DB_NAME", "postgres")
USE_PUBLIC_IP = os.environ.get("USE_PUBLIC_IP", "false").lower() == "true"

# Initialize Connector lazily
_connector = None

def get_connector():
    global _connector
    if _connector is None:
        _connector = Connector()
    return _connector

def getconn():
    connector = get_connector()
    ip_type = "PUBLIC" if USE_PUBLIC_IP else "PRIVATE"
    
    conn = connector.connect(
        ALLOYDB_URI,
        "pg8000",
        user=DB_USER,
        password=DB_PASS,
        db=DB_NAME,
        ip_type=ip_type
    )
    return conn

@app.route("/")
def index():
    return "AlloyDB Auth Demo. /connect to test.", 200

@app.route("/connect")
def connect_db():
    if not ALLOYDB_URI:
        return "FAILURE: ALLOYDB_URI env var is not set.", 500

    try:
        logger.info(f"Attempting connection to {ALLOYDB_URI} with user {DB_USER}...")
        
        # Create connection pool
        pool = sqlalchemy.create_engine(
            "postgresql+pg8000://",
            creator=getconn,
        )
        
        with pool.connect() as db_conn:
            # Simple query to validate connection
            result = db_conn.execute(sqlalchemy.text("SELECT NOW()")).fetchone()
            timestamp = result[0]
            
        msg = f"SUCCESS: Connected to AlloyDB! DB Time: {timestamp}"
        logger.info(msg)
        return msg, 200

    except Exception as e:
        logger.exception("Connection failed")
        # Return the error to the caller to visualize the auth failure
        return f"FAILURE: Connection Error.\nDetails: {str(e)}", 500

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
EOF
  1. Utwórz plik requirements.txt, uruchamiając w terminalu to polecenie: Ten plik obsługuje wymagania dotyczące pakietu Pythona.
cat <<EOF > ~/gemini-cloud-assist-debug/auth_issue_demo/requirements.txt
flask==3.1.3
gunicorn==25.3.0
google-cloud-alloydb-connector[pg8000]==1.12.1
sqlalchemy==2.0.49
EOF
  1. Utwórz plik main.tf, uruchamiając w terminalu to polecenie: Ten plik zawiera informacje o zasobach Google Cloud, które mają zostać utworzone.
cat <<EOF > ~/gemini-cloud-assist-debug/terraform/main.tf
provider "google" {
  project = var.project_id
  region  = var.region
}

# Enable APIs
locals {
  apis = [
    "alloydb.googleapis.com",
    "run.googleapis.com",
    "artifactregistry.googleapis.com",
    "compute.googleapis.com",
    "geminicloudassist.googleapis.com",
    "monitoring.googleapis.com",
    "cloudasset.googleapis.com",
    "cloudbuild.googleapis.com",
    "recommender.googleapis.com",
    "appoptimize.googleapis.com"
  ]
}

resource "random_password" "db_pass" {
  count            = var.db_password == null ? 1 : 0
  length           = 16
  special          = true
  override_special = "!#$%&*()-_=+[]{}<>:?"
}

locals {
  db_password = var.db_password != null ? var.db_password : random_password.db_pass[0].result
}

resource "google_project_service" "apis" {
  for_each           = toset(local.apis)
  service            = each.value
  disable_on_destroy = false
}

# Service Account
resource "google_service_account" "auth_demo_sa" {
  account_id   = var.service_account_name
  display_name = "Auth Demo SA"
}

# AlloyDB Cluster
resource "google_alloydb_cluster" "rma_cluster" {
  cluster_id = var.cluster_id
  location   = var.region

  # Initial password, managed via variable or generated randomly
  initial_user {
    password = local.db_password
  }

  # Use default network as in the manual setup
  network_config {
    network = "projects/${var.project_id}/global/networks/default"
  }

  depends_on = [google_project_service.apis["alloydb.googleapis.com"]]
}

# AlloyDB Instance
resource "google_alloydb_instance" "rma_instance_1" {
  cluster       = google_alloydb_cluster.rma_cluster.name
  instance_id   = var.instance_id
  instance_type = "PRIMARY"

  machine_config {
    cpu_count = 2
  }

  network_config {
    enable_public_ip = true
  }

  depends_on = [google_alloydb_cluster.rma_cluster]
}

# Cloud Run Service
resource "google_cloud_run_service" "auth_issue_demo" {
  name     = var.cloud_run_service_name
  location = var.region

  template {
    spec {
      containers {
        image = var.cloud_run_image
        env {
          name  = "ALLOYDB_URI"
          value = "projects/${var.project_id}/locations/${var.region}/clusters/${var.cluster_id}/instances/${var.instance_id}"
        }
        env {
          name  = "DB_USER"
          value = "postgres"
        }
        env {
          name  = "DB_PASS"
          value = local.db_password
        }
        env {
          name  = "USE_PUBLIC_IP"
          value = "true"
        }
      }
      service_account_name = google_service_account.auth_demo_sa.email
    }
  }

  traffic {
    percent         = 100
    latest_revision = true
  }

  depends_on = [google_project_service.apis["run.googleapis.com"], google_alloydb_instance.rma_instance_1]
}

# Allow unauthenticated access to Cloud Run service (matching --allow-unauthenticated)
resource "google_cloud_run_service_iam_member" "public_access" {
  location = google_cloud_run_service.auth_issue_demo.location
  project  = google_cloud_run_service.auth_issue_demo.project
  service  = google_cloud_run_service.auth_issue_demo.name
  role     = "roles/run.invoker"
  member   = "allUsers"
}
EOF
  1. Utwórz plik variables.tf, uruchamiając w terminalu to polecenie: Ten plik zawiera zmienne Terraform dla zasobów Google Cloud.
cat <<EOF > ~/gemini-cloud-assist-debug/terraform/variables.tf
variable "project_id" {
  description = "The ID of the Google Cloud project."
  type        = string
}

variable "region" {
  description = "The region to deploy resources in."
  type        = string
  default     = "us-central1"
}

variable "cluster_id" {
  description = "The ID of the AlloyDB cluster."
  type        = string
  default     = "rma-cluster"
}

variable "instance_id" {
  description = "The ID of the AlloyDB instance."
  type        = string
  default     = "rma-instance-1"
}

variable "service_account_name" {
  description = "The name of the service account."
  type        = string
  default     = "auth-demo-sa"
}

variable "cloud_run_service_name" {
  description = "The name of the Cloud Run service."
  type        = string
  default     = "auth-issue-demo"
}

variable "cloud_run_image" {
  description = "The container image for the Cloud Run service."
  type        = string
}

variable "db_password" {
  description = "The database password. If not provided, a random one will be generated."
  type        = string
  sensitive   = true
  default     = null
}
EOF
  1. Utwórz plik setup_via_tf.sh, uruchamiając w terminalu to polecenie: Ten plik obsługuje wymagania dotyczące pakietu Pythona.
cat <<EOF > ~/gemini-cloud-assist-debug/setup_via_tf.sh
#!/bin/bash
set -e

# Get script directory and change to project root
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"

# Load configuration from .env
if [ -f .env ]; then
    set -a
    source .env
    set +a
else
    echo "ERROR: .env file not found. Please create one with PROJECT_ID."
    exit 1
fi

if [ -z "$PROJECT_ID" ]; then
    echo "ERROR: PROJECT_ID is not set in .env file."
    exit 1
fi

REGION="us-central1"
CLUSTER_ID="rma-cluster"
INSTANCE_ID="rma-instance-1"
SA_NAME="auth-demo-sa"
SERVICE_NAME="auth-issue-demo"

echo "--- Terraform Setup for Auth Demo ---"
echo "Using Project: $PROJECT_ID"

# Get current Cloud Run image
echo "Fetching current Cloud Run image..."
IMAGE=$(gcloud run services describe $SERVICE_NAME --region=$REGION --project=$PROJECT_ID --format="value(spec.template.spec.containers[0].image)" 2>/dev/null || true)

if [ -z "$IMAGE" ]; then
    echo "WARNING: Could not find existing Cloud Run service image."
    echo "Using a placeholder image (gcr.io/cloudrun/hello) for initial Terraform apply."
    IMAGE="gcr.io/cloudrun/hello"
fi

echo "Found Image: $IMAGE"

cd terraform

# Initialize Terraform
echo "Initializing Terraform..."
terraform init

echo "Formatting Terraform files..."
terraform fmt

echo "Validating Terraform configuration..."
terraform validate

echo "------------------------------------------------"
echo "Applying changes..."
echo "------------------------------------------------"

terraform apply -var="project_id=$PROJECT_ID" -var="cloud_run_image=$IMAGE" -auto-approve

echo "------------------------------------------------"
echo "Building and deploying updated Cloud Run service..."
echo "------------------------------------------------"

gcloud run deploy $SERVICE_NAME \
  --source ../auth_issue_demo \
  --region $REGION \
  --project $PROJECT_ID \
  --service-account $SA_NAME@$PROJECT_ID.iam.gserviceaccount.com \
  --quiet
EOF
  1. Aby zmienić skrypt powłoki na wykonywalny, uruchom to polecenie:
chmod +x ~/gemini-cloud-assist-debug/setup_via_tf.sh
  1. Utwórz plik .env zawierający identyfikator projektu Google Cloud na potrzeby wdrożenia. Zaktualizuj pole YOUR_PROJECT_ID:
cat <<EOF > ~/gemini-cloud-assist-debug/.env
PROJECT_ID=YOUR_PROJECT_ID
USE_PUBLIC_IP=true
EOF

6. Wdrażanie aplikacji

Kod aplikacji i zasoby Google Cloud są gotowe do wdrożenia. Może to potrwać do 15 minut.

Uruchom w terminalu to polecenie:

cd ~/gemini-cloud-assist-debug
./setup_via_tf.sh

Podczas wdrażania komponentów przeglądaj pliki w edytorze Cloud Shell, aby dowiedzieć się więcej.

7. Tworzenie i debugowanie błędu

Teraz wywołamy błąd w aplikacji. W panelu po lewej stronie otwórz Cloud Run. Następnie kliknij usługę auth-issue-demo.

  1. U góry strony Szczegóły usługi znajduje się adres URL. Skopiuj adres URL i otwórz nową kartę przeglądarki. Wklej adres URL i dodaj do niego znak /connect. Adres URL będzie wyglądać mniej więcej tak:

https://auth-issue-demo-.us-central1.run.app/connect

  1. Otwórz adres URL. Uruchomienie instancji Cloud Run może potrwać kilka sekund. Pojawi się błąd.
  2. Wróć na stronę Cloud Run Szczegóły usługi. Kliknij kolejno DostrzegalnośćLogi. Zobaczysz logi kontenera, w tym błąd. Jeśli dziennik błędów nie jest jeszcze dostępny, poczekaj kilka sekund i odśwież stronę, korzystając z ikony w prawym górnym rogu.
  3. Kliknij dziennik błędów, aby dowiedzieć się więcej. Kliknij ikonę zbadania w wierszu głównego logu. Następnie kliknij Sprawdź log.

Otworzy się panel czatu Cloud Assist. Analiza trwa 2–3 minuty.

Po zakończeniu analizy zagrożeń możesz zapoznać się z wynikami i rekomendacjami. Pojawiła się rekomendacja, aby dodać odpowiednie uprawnienia do konta usługi, aby Cloud Run mogło uzyskać dostęp do instancji AlloyDB.

8. Napraw błąd

Napraw błąd uprawnień konta usługi.

  1. Otwórz Cloud IAM.
  2. Kliknij przycisk Przyznaj dostęp. W panelu podmiotu zabezpieczeń zacznij wpisywać auth-demo i poczekaj, aż pojawi się konto usługi.
  3. Następnie przypisz do konta usługi rolę AlloyDB Client i kliknij Zapisz.

Może to potrwać do minuty.

Po odczekaniu wróć i odśwież aplikację. Zobaczysz teraz komunikat o powodzeniu z bazy danych AlloyDB.

9. Gratulacje

Gratulacje! To już koniec tego wprowadzenia do Cloud Investigations i procesu debugowania uprawnień aplikacji w Google Cloud.

Co dalej?