Tutorial: Pemecahan masalah lokal untuk layanan Cloud Run


Tutorial ini menunjukkan cara developer layanan dapat memecahkan masalah layanan Cloud Run yang rusak menggunakan alat Google Cloud Observability untuk penemuan dan alur kerja pengembangan lokal untuk penyidikan.

Pendamping "studi kasus" langkah demi langkah untuk panduan pemecahan masalah ini menggunakan project contoh yang menghasilkan error runtime saat di-deploy, yang Anda pecahkan masalahnya untuk ditemukan dan diperbaiki masalahnya.

Tujuan

  • Menulis, membangun, dan men-deploy layanan ke Cloud Run
  • Menggunakan Error Reporting dan Cloud Logging untuk mengidentifikasi sebuah error
  • Mengambil image container dari Container Registry untuk analisis akar masalah
  • Perbaiki layanan "produksi", lalu tingkatkan kualitas layanan untuk mengurangi masalah di masa mendatang

Biaya

Dalam dokumen ini, Anda menggunakan komponen Google Cloud yang dapat ditagih berikut:

Untuk membuat perkiraan biaya berdasarkan proyeksi penggunaan Anda, gunakan kalkulator harga. Pengguna baru Google Cloud mungkin memenuhi syarat untuk mendapatkan uji coba gratis.

Sebelum memulai

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Di konsol Google Cloud, pada halaman pemilih project, pilih atau buat project Google Cloud.

    Buka pemilih project

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

  4. Di konsol Google Cloud, pada halaman pemilih project, pilih atau buat project Google Cloud.

    Buka pemilih project

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

  6. Aktifkan Cloud Run Admin API
  7. Instal dan lakukan inisialisasi gcloud CLI.
  8. Perbarui komponen:
    gcloud components update
  9. Ikuti petunjuk untuk menginstal Docker secara lokal

Peran yang diperlukan

Untuk mendapatkan izin yang Anda perlukan untuk menyelesaikan tutorial, minta administrator Anda untuk memberi Anda peran IAM berikut di project Anda:

Untuk mengetahui informasi selengkapnya tentang cara memberikan peran, lihat Mengelola akses ke project, folder, dan organisasi.

Anda mungkin juga bisa mendapatkan izin yang diperlukan melalui peran khusus atau peran bawaan lainnya.

Menyiapkan default gcloud

Untuk mengonfigurasi gcloud dengan setelan default untuk layanan Cloud Run Anda:

  1. Setel project default Anda:

    gcloud config set project PROJECT_ID

    Ganti PROJECT_ID dengan nama project yang Anda buat untuk tutorial ini.

  2. Konfigurasi gcloud untuk region yang Anda pilih:

    gcloud config set run/region REGION

    Ganti REGION dengan region Cloud Run pilihan Anda yang didukung.

Lokasi Cloud Run

Cloud Run bersifat regional, berarti infrastruktur yang menjalankan layanan Cloud Run Anda terletak di region tertentu dan dikelola oleh Google agar tersedia secara redundan di semua zona dalam region tersebut.

Memenuhi persyaratan latensi, ketersediaan, atau ketahanan adalah faktor utama untuk memilih region tempat layanan Cloud Run dijalankan. Pada umumnya, Anda dapat memilih region yang paling dekat dengan pengguna Anda, tetapi Anda harus mempertimbangkan lokasi dari produk Google Cloud lain yang digunakan oleh layanan Cloud Run Anda. Menggunakan produk Google Cloud secara bersamaan di beberapa lokasi dapat memengaruhi latensi serta biaya layanan Anda.

Cloud Run tersedia di region berikut:

Tergantung harga Tingkat 1

  • asia-east1 (Taiwan)
  • asia-northeast1 (Tokyo)
  • asia-northeast2 (Osaka)
  • asia-south1 (Mumbai, India)
  • europe-north1 (Finlandia) ikon daun CO2 Rendah
  • europe-southwest1 (Madrid) ikon daun CO2 Rendah
  • europe-west1 (Belgia) ikon daun CO2 Rendah
  • europe-west4 (Belanda) ikon daun CO2 Rendah
  • europe-west8 (Milan)
  • europe-west9 (Paris) ikon daun CO2 Rendah
  • me-west1 (Tel Aviv)
  • us-central1 (Iowa) ikon daun CO2 Rendah
  • us-east1 (South Carolina)
  • us-east4 (North Virginia)
  • us-east5 (Columbus)
  • us-south1 (Dallas) ikon daun CO2 Rendah
  • us-west1 (Oregon) ikon daun CO2 Rendah

Tergantung harga Tingkat 2

  • africa-south1 (Johannesburg)
  • asia-east2 (Hong Kong)
  • asia-northeast3 (Seoul, Korea Selatan)
  • asia-southeast1 (Singapura)
  • asia-southeast2 (Jakarta)
  • asia-south2 (Delhi, India)
  • australia-southeast1 (Sydney)
  • australia-southeast2 (Melbourne)
  • europe-central2 (Warsawa, Polandia)
  • europe-west10 (Berlin) ikon daun CO2 Rendah
  • europe-west12 (Turin)
  • europe-west2 (London, Inggris Raya) ikon daun CO2 Rendah
  • europe-west3 (Frankfurt, Jerman) ikon daun CO2 Rendah
  • europe-west6 (Zurich, Swiss) ikon daun CO2 Rendah
  • me-central1 (Doha)
  • me-central2 (Dammam)
  • northamerica-northeast1 (Montreal) ikon daun CO2 Rendah
  • northamerica-northeast2 (Toronto) ikon daun CO2 Rendah
  • southamerica-east1 (São Paulo, Brasil) ikon daun CO2 Rendah
  • southamerica-west1 (Santiago, Cile) ikon daun CO2 Rendah
  • us-west2 (Los Angeles)
  • us-west3 (Salt Lake City)
  • us-west4 (Las Vegas)

Jika sudah membuat layanan Cloud Run, Anda dapat melihat region di dasbor Cloud Run di Konsol Google Cloud.

Susun kode

Bangun layanan penyambut Cloud Run baru langkah demi langkah. Sebagai sebuah pengingat, layanan ini sengaja membuat error runtime untuk latihan pemecahan masalah.

  1. Membuat sebuah project baru.

    Node.js

    Membuat sebuah project Node.js dengan menentukan paket layanan, dependensi awal, dan beberapa operasi umum.

    1. Membuat direktori hello-service baru:

      mkdir hello-service
      cd hello-service
      
    2. Membuat project Node.js baru dengan membuat package.jsonfile:

      npm init --yes
      npm install --save express@4
      
    3. Buka file package.json baru di editor Anda dan konfigurasikan skrip start untuk menjalankan node index.js Setelah selesai, filenya akan terlihat seperti ini:

      {
        "name": "hello-broken",
        "description": "Broken Cloud Run service for troubleshooting practice",
        "version": "1.0.0",
        "private": true,
        "main": "index.js",
        "scripts": {
          "start": "node index.js",
          "test": "echo \"Error: no test specified\" && exit 0",
          "system-test": "NAME=Cloud c8 mocha -p -j 2 test/system.test.js --timeout=360000 --exit"
        },
        "engines": {
          "node": ">=16.0.0"
        },
        "author": "Google LLC",
        "license": "Apache-2.0",
        "dependencies": {
          "express": "^4.17.1"
        },
        "devDependencies": {
          "c8": "^10.0.0",
          "google-auth-library": "^9.0.0",
          "got": "^11.5.0",
          "mocha": "^10.0.0"
        }
      }
      

    Jika Anda terus mengembangkan layanan ini hingga lebih dari sekadar tutorial langsung, pertimbangkan untuk mengisi deskripsi, penulis, dan mengevaluasi lisensinya. Untuk mengetahui detail lengkapnya, baca dokumentasi package.json.

    Python

    1. Membuat direktori hello-service baru:

      mkdir hello-service
      cd hello-service
      
    2. Membuat file requirements.txt dan salin dependensi Anda ke dalamnya:

      Flask==3.0.3
      pytest==8.2.0; python_version > "3.0"
      # pin pytest to 4.6.11 for Python2.
      pytest==4.6.11; python_version < "3.0"
      gunicorn==22.0.0
      Werkzeug==3.0.3
      

    Go

    1. Membuat direktori hello-service baru:

      mkdir hello-service
      cd hello-service
      
    2. Membuat project Go dengan melakukan inisialisasi modul go baru:

      go mod init example.com/hello-service
      

    Anda dapat memperbarui nama spesifiknya sesuai keinginan: Anda harus memperbarui nama tersebut jika kode dipublikasikan ke repositori kode yang dapat diakses melalui web.

    Java

    1. Membuat project Maven baru:

      mvn archetype:generate \
        -DgroupId=com.example.cloudrun \
        -DartifactId=hello-service \
        -DarchetypeArtifactId=maven-archetype-quickstart \
        -DinteractiveMode=false
      
    2. Salin dependensi ke daftar dependensi pom.xml Anda (di antara elemen <dependencies>):

      <dependency>
        <groupId>com.sparkjava</groupId>
        <artifactId>spark-core</artifactId>
        <version>2.9.4</version>
      </dependency>
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.12</version>
      </dependency>
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>2.0.12</version>
      </dependency>
      
    3. Salin setelan build ke dalam pom.xml Anda (di bawah elemen <dependencies>):

      <build>
        <plugins>
          <plugin>
            <groupId>com.google.cloud.tools</groupId>
            <artifactId>jib-maven-plugin</artifactId>
            <version>3.4.0</version>
            <configuration>
              <to>
                <image>gcr.io/PROJECT_ID/hello-service</image>
              </to>
            </configuration>
          </plugin>
        </plugins>
      </build>
      

  2. Membuat layanan HTTP untuk menangani permintaan masuk:

    Node.js

    const express = require('express');
    const app = express();
    
    app.get('/', (req, res) => {
      console.log('hello: received request.');
    
      const {NAME} = process.env;
      if (!NAME) {
        // Plain error logs do not appear in Stackdriver Error Reporting.
        console.error('Environment validation failed.');
        console.error(new Error('Missing required server parameter'));
        return res.status(500).send('Internal Server Error');
      }
      res.send(`Hello ${NAME}!`);
    });
    const port = parseInt(process.env.PORT) || 8080;
    app.listen(port, () => {
      console.log(`hello: listening on port ${port}`);
    });

    Python

    import json
    import os
    
    from flask import Flask
    
    
    app = Flask(__name__)
    
    
    @app.route("/", methods=["GET"])
    def index():
        """Example route for testing local troubleshooting.
    
        This route may raise an HTTP 5XX error due to missing environment variable.
        """
        print("hello: received request.")
    
        NAME = os.getenv("NAME")
    
        if not NAME:
            print("Environment validation failed.")
            raise Exception("Missing required service parameter.")
    
        return f"Hello {NAME}"
    
    
    if __name__ == "__main__":
        PORT = int(os.getenv("PORT")) if os.getenv("PORT") else 8080
    
        # This is used when running locally. Gunicorn is used to run the
        # application on Cloud Run. See entrypoint in Dockerfile.
        app.run(host="127.0.0.1", port=PORT, debug=True)

    Go

    
    // Sample hello demonstrates a difficult to troubleshoot service.
    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    func main() {
    	log.Print("hello: service started")
    
    	http.HandleFunc("/", helloHandler)
    
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    		log.Printf("Defaulting to port %s", port)
    	}
    
    	log.Printf("Listening on port %s", port)
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    
    func helloHandler(w http.ResponseWriter, r *http.Request) {
    	log.Print("hello: received request")
    
    	name := os.Getenv("NAME")
    	if name == "" {
    		log.Printf("Missing required server parameter")
    		// The panic stack trace appears in Cloud Error Reporting.
    		panic("Missing required server parameter")
    	}
    
    	fmt.Fprintf(w, "Hello %s!\n", name)
    }
    

    Java

    import static spark.Spark.get;
    import static spark.Spark.port;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class App {
    
      private static final Logger logger = LoggerFactory.getLogger(App.class);
    
      public static void main(String[] args) {
        int port = Integer.parseInt(System.getenv().getOrDefault("PORT", "8080"));
        port(port);
    
        get(
            "/",
            (req, res) -> {
              logger.info("Hello: received request.");
              String name = System.getenv("NAME");
              if (name == null) {
                // Standard error logs do not appear in Stackdriver Error Reporting.
                System.err.println("Environment validation failed.");
                String msg = "Missing required server parameter";
                logger.error(msg, new Exception(msg));
                res.status(500);
                return "Internal Server Error";
              }
              res.status(200);
              return String.format("Hello %s!", name);
            });
      }
    }

  3. Membuat Dockerfile untuk menentukan image container yang digunakan untuk men-deploy layanan:

    Node.js

    
    # Use the official lightweight Node.js image.
    # https://hub.docker.com/_/node
    FROM node:20-slim
    # Create and change to the app directory.
    WORKDIR /usr/src/app
    
    # Copy application dependency manifests to the container image.
    # A wildcard is used to ensure copying both package.json AND package-lock.json (when available).
    # Copying this first prevents re-running npm install on every code change.
    COPY package*.json ./
    
    # Install dependencies.
    # if you need a deterministic and repeatable build create a
    # package-lock.json file and use npm ci:
    # RUN npm ci --omit=dev
    # if you need to include development dependencies during development
    # of your application, use:
    # RUN npm install --dev
    
    RUN npm install --omit=dev
    
    # Copy local code to the container image.
    COPY . ./
    
    # Run the web service on container startup.
    CMD [ "npm", "start" ]
    

    Python

    
    # Use the official Python image.
    # https://hub.docker.com/_/python
    FROM python:3.11
    
    # Allow statements and log messages to immediately appear in the Cloud Run logs
    ENV PYTHONUNBUFFERED True
    
    # Copy application dependency manifests to the container image.
    # Copying this separately prevents re-running pip install on every code change.
    COPY requirements.txt ./
    
    # Install production dependencies.
    RUN pip install -r requirements.txt
    
    # Copy local code to the container image.
    ENV APP_HOME /app
    WORKDIR $APP_HOME
    COPY . ./
    
    # Run the web service on container startup.
    # Use 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.
    CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
    

    Go

    
    # Use the offical golang image to create a binary.
    # This is based on Debian and sets the GOPATH to /go.
    # https://hub.docker.com/_/golang
    FROM golang:1.21-bookworm as builder
    
    # Create and change to the app directory.
    WORKDIR /app
    
    # Retrieve application dependencies.
    # This allows the container build to reuse cached dependencies.
    # Expecting to copy go.mod and if present go.sum.
    COPY go.* ./
    RUN go mod download
    
    # Copy local code to the container image.
    COPY . ./
    
    # Build the binary.
    RUN go build -v -o server
    
    # Use the official Debian slim image for a lean production container.
    # https://hub.docker.com/_/debian
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM debian:bookworm-slim
    RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
        ca-certificates && \
        rm -rf /var/lib/apt/lists/*
    
    # Copy the binary to the production image from the builder stage.
    COPY --from=builder /app/server /server
    
    # Run the web service on container startup.
    CMD ["/server"]
    

    Java

    Contoh ini menggunakan Jib untuk mem-build image Docker menggunakan alat Java umum. Jib mengoptimalkan build container tanpa memerlukan Dockerfile atau menginstal Docker. Pelajari lebih lanjut cara mem-build container Java dengan Jib.

    <plugin>
      <groupId>com.google.cloud.tools</groupId>
      <artifactId>jib-maven-plugin</artifactId>
      <version>3.4.0</version>
      <configuration>
        <to>
          <image>gcr.io/PROJECT_ID/hello-service</image>
        </to>
      </configuration>
    </plugin>
    

Mengirimkan kode

Kode pengiriman terdiri dari tiga langkah: mem-build image container dengan Cloud Build, mengupload image container ke Container Registry, dan men-deploy image container ke Cloud Run.

Untuk kode pengiriman Anda:

  1. Build container Anda dan publikasikan di Container Registry:

    Node.js

    gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service

    Dengan PROJECT_ID sebagai project ID Google Cloud Anda. Anda dapat memeriksa project ID Anda saat ini dengan gcloud config get-value project.

    Setelah berhasil, Anda akan melihat pesan SUCCESS yang berisi ID, waktu pembuatan, dan nama image. Image tersebut disimpan di Container Registry dan dapat digunakan kembali bila diinginkan.

    Python

    gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service

    Dengan PROJECT_ID sebagai project ID Google Cloud Anda. Anda dapat memeriksa project ID Anda saat ini dengan gcloud config get-value project.

    Setelah berhasil, Anda akan melihat pesan SUCCESS yang berisi ID, waktu pembuatan, dan nama image. Image tersebut disimpan di Container Registry dan dapat digunakan kembali bila diinginkan.

    Go

    gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service

    Dengan PROJECT_ID sebagai project ID Google Cloud Anda. Anda dapat memeriksa project ID Anda saat ini dengan gcloud config get-value project.

    Setelah berhasil, Anda akan melihat pesan SUCCESS yang berisi ID, waktu pembuatan, dan nama image. Image tersebut disimpan di Container Registry dan dapat digunakan kembali bila diinginkan.

    Java

    1. Gunakan gcloud kredensial helper untuk memberi otorisasi Docker agar dikirim ke Container Registry Anda.
      gcloud auth configure-docker
    2. Gunakan Plugin Maven Jib untuk mem-build dan mengirim container ke Container Registry.
      mvn compile jib:build -Dimage=gcr.io/PROJECT_ID/hello-service

    Dengan PROJECT_ID sebagai project ID Google Cloud Anda. Anda dapat memeriksa project ID Anda saat ini dengan gcloud config get-value project.

    Setelah berhasil, Anda akan melihat pesan BUILD SUCCESS. Image tersebut disimpan di Container Registry dan dapat digunakan kembali bila diinginkan.

  2. Jalankan perintah berikut ini untuk menggunakan aplikasi anda:

    gcloud run deploy hello-service --image gcr.io/PROJECT_ID/hello-service

    Ganti PROJECT_ID dengan ID project Google Cloud anda. hello-service adalah nama gambar penampung dan nama dari layanan Cloud Run. Perhatikan bahwa gambar penampung digunakan untuk layanan dan region yang anda konfigurasikan sebelumnya pada bagian Menyiapkan gcloud

    Berikan tanggapan y, "Yes", pada perintah allow unauthenticated. Kunjungi Managing Access untuk detail lebih lanjut pada autentikasi berdasarkan IAM.

    Tunggu hingga deployment selesai: proses ini memerlukan waktu sekitar setengah menit. Apabila berhasil, command line akan menampilkan URL layanan:

Melakukan Percobaan

Cobalah layanan untuk mengonfirmasi bahwa anda telah berhasil men-deploy-nya. Berbagai permintaan akan gagal apabila menggunakan HTTP 500 atau 503 error (anggota-anggota dari kelas 5xx Server errors). Tutorial ini berisi penjelasan mengenai pemecahan masalah pada tanggapan yang error.

Layanan ini ditetapkan secara otomatis oleh URL yang dapat dinavigasi.

  1. Buka URL ini pada browser web anda:

    1. Buka sebuah browser web.

    2. Temukan layanan URL output pada perintah deploy sebelumnya.

      Jika perintah deploy tidak memberikan URL, maka terjadi error. Evaluasi pesan dan tindakan yang error dengan sesuai: jika tidak ada panduan yang dapat ditindaklanjuti, tinjau troubleshooting guide dan coba lagi menu perintah deployment.

    3. Buka URL ini dengan menyalinnya ke kolom URL pada browser anda dan tekan ENTER.

  2. Lihat error pada HTTP 500 atau HTTP 503.

    Jika menerima error pada HTTP 403, anda mungkin telah menolak allow unauthenticated invocations pada perintah deployment. Berikan akses yang tidak diautentikasi ke layanan untuk memperbaiki masalah ini:

    gcloud run services add-iam-policy-binding hello-service \
      --member="allUsers" \
      --role="roles/run.invoker"
    

Untuk informasi selengkapnya, baca Allowing public (unauthenticated) access.

Menyelidiki masalah

Visualisasikan bahwa HTTP 5xx error yang ditemukan di atas dalam Trying it out ditemukan sebagai sebuah error runtime production. Tutorial ini berisi penjelasan mengenai proses formal untuk menangani itu. Meskipun proses resolusi error produksi sangat bervariasi, tutorial ini menyajikan langkah-langkah tertentu untuk menunjukkan pengaplikasian dari fitur-fitur dan teknik-teknik yang berguna.

Untuk menyelidiki masalah ini kamu akan menggunakan fase ini:

  • Kumpulkan detail selengkapnya tentang error yang dilaporkan untuk mendukung penyelidikan lebih lanjut dan menetapkan strategi mitigasi.
  • Kurangi dampak pengguna dengan memutuskan untuk meneruskan perbaikan atau rollback ke versi yang sehat.
  • Reproduksi error untuk konfirmasi bahwa detail yang benar telah dikumpulkan dan error bukanlah glitch satu kali
  • Lakukan analisis akar masalah pada bug untuk menemukan kode konfigurasi, atau proses yang membuat error ini

Pada saat memulai investigasi anda memiliki URL, stempel waktu, dan pesan. "Error Server Internal"

Mengumpulkan detail selengkapnya

Kumpulkan informasi selengkapnya tentang masalah untuk memahami yang terjadi dan menentukan langkah selanjutnya.

Gunakan alat Google Cloud Observability yang tersedia untuk mengumpulkan detail selengkapnya:

  1. Gunakan console Error Reporting, yang menyediakan dasbor dengan detail dan pelacakan pengulangan untuk error dengan kenali stack trace.

    Buka console Error Reporting

    Screenshot daftar error termasuk kolom &#39;Resolution Status&#39;, Occurrences, Error, dan &#39;Seen in&#39;.
    daftar error yang tercatat. Error dikelompokan menurut pesan di seluruh revisi layanan dan platform.
  2. Klik pada error untuk melihat detail pelacakan tumpukan, perhatikan panggilan fungsi yang dibuat sebelum terjadinya error.

    Screenshot dari sebuah pelacakan tumpukan yang terurai sekali, menunjukkan profil umum pada error ini.
    "Sampel pelacakan tumpukan" di dalam halaman detail error menunjukkan satu instance dari error itu. Anda dapat meninjau untuk setiap instance.
  3. Gunakan Cloud Logging untuk meninjau urutan dari operasi yang membuka masalah, termasuk pesan error yang tidak dimasukkan di konsol Error Reporting karena kurangnya pengenalan pelacakan tumpukan error:

    Buka konsol Cloud Logging

    Pilihlah Revisi Cloud Run > hello-service dari kotak drop-down pertama. Ini akan memfilter entri log pada entri log yang dihasilkan oleh layanan anda.

Baca selengkapnya tentang melihat log pada Cloud Run

Rollback ke versi stabil

jika ini adalah layanan yang sudah ada, dapat digunakan, maka akan ada revisi sebelumnya dari layanan pada Cloud Run. Tutorial ini menggunakan sebuah layanan baru tanpa versi sebelumnya, jadi anda tidak dapat melakukan rollback.

Namun, jika anda memiliki sebuah layanan dengan versi sebelumnya anda dapat rollback, ikuti Melihat detail revisi untuk mengekstrak nama container dan detail konfigurasi penting untuk membuat deployment pengerjaan baru dari layanan anda.

Mengulangi error

Gunakan detail anda dapat sebelumnya, konfirmasi masalah yang terjadi secara konsisten pada kondisi tes.

kirim permintaan HTTP yang sama dengan melakukan percobaan lagi, dan lihat jika detail dan error yang sama di laporkan. Itu mungkin membutuhkan beberapa waktu untuk detail error muncul.

Karena layanan sampel pada tutorial ini adalah hanya baca dan tidak dapat memicu berbagai efek samping yang rumit, reproduksi error pada produksi adalah aman. Namun, untuk layanan nyata kebanyakan, ini tidak akan menjadi kasus: anda mungkin butuh untuk mereproduksi error dalam lingkungan pengujian atau batas langkah ini pada penyelidikan lokal.

mereproduksi error akan membangun konteks untuk pekerjaan lebih lanjut. misalnya, jika developer tidak dapat mereproduksi error, penyelidikan selanjutnya mungkin diperlukan instrumentasi tambahan dari layanan.

Melakukan analisis akar masalah

Analisis akar masalah adalah langkah penting dalam pemecahan masalah yang efektif untuk memastikan bahwa anda menyelesaikan masalah, bukan menemukan gejala.

Sebelumnya dalam tutorial ini, anda mereproduksi masalah di Cloud Run yang mengonfirmasi bahwa masalah aktif saat layanan dihosting pada Cloud Run. Sekarang, reproduksi masalah secara lokal untuk menentukan apakah masalah tersebut terisolasi pada kode atau itu hanya muncul di hosting produksi.

  1. Jika Anda belum menggunakan Docker CLI secara lokal dengan mengautentikasi Container Registry, itu dengan gcloud:

    gcloud auth configure-docker

    Untuk pendekatan alternatif lihat metode autentifikasi Container Registry.

  2. Jika nama image container yang paling baru digunakan tidak tersedia, deskripsi layanan tersebut memiliki informasi mengenai image container yang di-deploy paling baru:

    gcloud run services describe hello-service

    Temukan nama image container di dalam objek spec. Perintah yang lebih ditargetkan dapat secara langsung mengambilnya:

    gcloud run services describe hello-service \
       --format="value(spec.template.spec.containers.image)"

    Perintah ini menampilkan nama image container seperti gcr.io/PROJECT_ID/hello-service.

  3. Tarik image container dari Container Registry ke lingkungan anda. langkah ini mungkin memerlukan waktu beberapa menit saat mendownload image container:

    docker pull gcr.io/PROJECT_ID/hello-service

    pembaruan selanjutnya pada image container yang menggunakan kembali nama ini dapat diambil dengan perintah yang sama. Jika anda melewati langkah ini, perintah docker run di bawah akan menarik image container jika tidak ada di komputer lokal.

  4. Jalankan secara lokal untuk mengonfirmasi bahwa masalah tidak hanya terjadi di Cloud Run:

    PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \
       gcr.io/PROJECT_ID/hello-service

    lihat rincian elemen dari perintah di atas,

    • Variabel lingkungan PORT digunakan oleh layanan untuk menentukan port yang akan memproses di dalam container.
    • Perintah run memulai container, secara default ke perintah entrypoint yang ditentukan di Dockerfile atau image container induk.
    • Flag --rm menghapus instance penampung saat keluar.
    • Flag -e menetapkan nilai ke variabel lingkungan. -e PORT=$PORT menerapkan variabel PORT dari sistem lokal ke dalam container dengan nama variabel yang sama.
    • Flag -p memublikasikan container sebagai layanan yang tersedia di host lokal pada port 9000. Permintaan ke host lokal:9000 akan diarahkan kepada penampung pada port 8080. Artinya, output dari layanan tentang nomor port yang digunakan tidak akan cocok dengan cara layanan yang diakses.
    • Argumen terakhir gcr.io/PROJECT_ID/hello-service adalah image container tag, label yang dapat dibaca manusia untuk sebuah pengidentifikasi hash sha256 milik image container Jika tidak tersedia secara lokal, Docker akan mencoba untuk mengambil image dari registry jarak jauh.

    Pada browser anda, buka http://localhost:9000. Periksa output terminal untuk menemukan pesan error yang cocok dengan pesan di {ops_name}}.

    Jika masalah tidak dapat direproduksi secara lokal, masalah mungkin hanya terjadi di lingkungan Cloud Run. Tinjau panduan pemecahan masalah Cloud Run untuk area tertentu yang perlu diselidiki.

    Dalam hal ini, error akan direproduksi secara lokal.

Setelah error dikonfirmasi dua kali sebagai persisten dan disebabkan oleh kode layanan bukan platform hosting, saatnya untuk menyelidiki kode tersebut lebih mendalam.

Untuk tujuan tutorial ini, anda dapat mengasumsikan bahwa kode di dalam penampung dan kode di sistem lokal adalah identik.

Tinjau kembali pelacakan tumpukan laporan error dan referensi silang dengan kode untuk menemukan baris spesifik yang bermasalah.

Node.js

Temukan sumber pesan error di dalam file index.js di sekitar nomor baris yang dipanggil dalam pelacakan tumpukan yang ditampilkan dalam log:
const {NAME} = process.env;
if (!NAME) {
  // Plain error logs do not appear in Stackdriver Error Reporting.
  console.error('Environment validation failed.');
  console.error(new Error('Missing required server parameter'));
  return res.status(500).send('Internal Server Error');
}

Python

Temukan sumber pesan error di dalam file main.py di sekitar nomor baris yang dipanggil dalam pelacakan tumpukan yang ditampilkan dalam log:
NAME = os.getenv("NAME")

if not NAME:
    print("Environment validation failed.")
    raise Exception("Missing required service parameter.")

Go

Temukan sumber pesan error di dalam file main.go di sekitar nomor baris yang dipanggil dalam pelacakan tumpukan yang ditampilkan dalam log:

name := os.Getenv("NAME")
if name == "" {
	log.Printf("Missing required server parameter")
	// The panic stack trace appears in Cloud Error Reporting.
	panic("Missing required server parameter")
}

Java

Temukan sumber dari pesan error dalam file App.java di sekitar nomor baris yang dipanggil dalam pelacakan tumpukan yang ditampilkan dalam log:

String name = System.getenv("NAME");
if (name == null) {
  // Standard error logs do not appear in Stackdriver Error Reporting.
  System.err.println("Environment validation failed.");
  String msg = "Missing required server parameter";
  logger.error(msg, new Exception(msg));
  res.status(500);
  return "Internal Server Error";
}

Memeriksa kode ini, tindakan berikut akan dilakukan saat variabel lingkungan NAME tidak ditetapkan:

  • Error dicatat ke dalam log Google Cloud Observability
  • Respon error HTTP dikirim

Masalah ini disebabkan oleh tidak adanya variabel, tetapi akar masalahnya lebih spesifik: perubahan kode yang menambahkan dependensi keras pada variabel lingkungan tidak menyertakan perubahan terkait pada skrip deployment dan dokumentasi persyaratan runtime.

Memperbaiki akar masalah

Setelah mengumpulkan kode dan mengidentifikasi potensi penyebab utamanya, kita dapat mengambil langkah-langkah untuk memperbaikinya.

  • Periksa apakah layanan berfungsi secara lokal dengan lingkungan NAME yang tersedia di tempat:

    1. Jalankan container secara lokal dengan variabel lingkungan yang telah ditambahkan:

      PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \
       -e NAME="Local World!" \
       gcr.io/PROJECT_ID/hello-service
    2. Buka http://localhost:9000 pada browser anda

    3. Lihat "Hello Local World!" muncul pada halaman tersebut

  • Ubah lingkungan layanan Cloud Run yang sedang berjalan untuk menyertakan variabel ini:

    1. Jalankan perintah update layanan untuk menambahkan variabel lingkungan:

      gcloud run services update hello-service \
        --set-env-vars NAME=Override
      
    2. Tunggu beberapa detik ketika Cloud Run membuat revisi baru berdasarkan revisi sebelumnya dengan menambahkan variabel lingkungan baru.

  • Pastikan layanan kini telah diperbaiki:

    1. Arahkan browser anda menuju URL layanan Cloud Run.
    2. Lihat "Halo Penggantian!" akan muncul pada halaman tersebut.
    3. Pastikan tidak ada pesan atau error yang tidak terduga yang muncul di Cloud Logging atau Error Reporting.

Meningkatkan kecepatan pemecahan masalah di masa mendatang

Dalam contoh masalah produksi ini, error terkait dengan konfigurasi operasional. Ada perubahan kode yang akan meminimalkan dampak masalah ini di masa mendatang.

  • Memperbaiki log error untuk menyertakan detail yang lebih spesifik.
  • Daripada menampilkan error, buat layanan kembali ke default yang aman. Jika penggunaan default mewakili perubahan pada fungsi normal, gunakan pesan peringatan untuk tujuan pemantauan.

Mari kita lanjutkan dengan menghapus variabel lingkungan NAME sebagai dependensi kuat.

  1. Hapus kode penanganan NAME yang sudah ada:

    Node.js

    const {NAME} = process.env;
    if (!NAME) {
      // Plain error logs do not appear in Stackdriver Error Reporting.
      console.error('Environment validation failed.');
      console.error(new Error('Missing required server parameter'));
      return res.status(500).send('Internal Server Error');
    }

    Python

    NAME = os.getenv("NAME")
    
    if not NAME:
        print("Environment validation failed.")
        raise Exception("Missing required service parameter.")

    Go

    name := os.Getenv("NAME")
    if name == "" {
    	log.Printf("Missing required server parameter")
    	// The panic stack trace appears in Cloud Error Reporting.
    	panic("Missing required server parameter")
    }

    Java

    String name = System.getenv("NAME");
    if (name == null) {
      // Standard error logs do not appear in Stackdriver Error Reporting.
      System.err.println("Environment validation failed.");
      String msg = "Missing required server parameter";
      logger.error(msg, new Exception(msg));
      res.status(500);
      return "Internal Server Error";
    }

  2. Tambahkan kode baru yang menetapkan nilai penggantian:

    Node.js

    const NAME = process.env.NAME || 'World';
    if (!process.env.NAME) {
      console.log(
        JSON.stringify({
          severity: 'WARNING',
          message: `NAME not set, default to '${NAME}'`,
        })
      );
    }

    Python

    NAME = os.getenv("NAME")
    
    if not NAME:
        NAME = "World"
        error_message = {
            "severity": "WARNING",
            "message": f"NAME not set, default to {NAME}",
        }
        print(json.dumps(error_message))

    Go

    name := os.Getenv("NAME")
    if name == "" {
    	name = "World"
    	log.Printf("warning: NAME not set, default to %s", name)
    }

    Java

    String name = System.getenv().getOrDefault("NAME", "World");
    if (System.getenv("NAME") == null) {
      logger.warn(String.format("NAME not set, default to %s", name));
    }

  3. Uji secara lokal dengan mem-build ulang dan menjalankan container melalui kasus konfigurasi yang terpengaruh:

    Node.js

    docker build --tag gcr.io/PROJECT_ID/hello-service .

    Python

    docker build --tag gcr.io/PROJECT_ID/hello-service .

    Go

    docker build --tag gcr.io/PROJECT_ID/hello-service .

    Java

    mvn compile jib:build

    Pastikan variabel lingkungan NAME masih berfungsi:

    PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \
     -e NAME="Robust World" \
     gcr.io/PROJECT_ID/hello-service

    Pastikan layanan berfungsi tanpa variabel NAME:

    PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \
     gcr.io/PROJECT_ID/hello-service

    Jika layanan tidak menampilkan hasil, pastikan penghapusan kode pada langkah pertama tidak menghapus baris tambahan, seperti yang digunakan untuk menulis respons.

  4. Deploy ini dengan membuka kembali bagian Men-deploy kode Anda.

    Setiap deployment ke layanan membuat revisi baru dan otomatis mulai menyalurkan traffic jika sudah siap.

    Untuk menghapus variabel lingkungan yang telah disetel sebelumnya:

    gcloud run services update hello-service --clear-env-vars

Tambahkan fungsi baru untuk nilai default ke cakupan pengujian otomatis untuk layanan.

Menemukan masalah lain di log

Anda mungkin melihat masalah lain di Log Viewer untuk layanan ini. Misalnya, panggilan sistem yang tidak didukung akan muncul di log sebagai "Container Sandbox Limitation".

Misalnya, layanan Node.js terkadang menghasilkan pesan log ini:

Container Sandbox Limitation: Unsupported syscall statx(0xffffff9c,0x3e1ba8e86d88,0x0,0xfff,0x3e1ba8e86970,0x3e1ba8e86a90). Please, refer to https://gvisor.dev/c/linux/amd64/statx for more information.

Dalam hal ini, kurangnya dukungan tidak mempengaruhi layanan sampel hello-service.

Pemecahan masalah Terraform

Untuk pertanyaan atau pemecahan masalah terkait Terraform, baca Pemecahan masalah validasi kebijakan Terraform atau hubungi dukungan Terraform.

Pembersihan

Jika Anda membuat project baru untuk tutorial ini, hapus project tersebut. Jika Anda menggunakan project yang ada dan ingin mempertahankannya tanpa ada perubahan yang ditambahkan dalam tutorial ini, hapus resource yang dibuat untuk tutorial.

Menghapus project

Cara termudah untuk menghilangkan penagihan adalah dengan menghapus project yang Anda buat untuk tutorial.

Untuk menghapus project:

  1. Di konsol Google Cloud, buka halaman Manage resource.

    Buka Manage resource

  2. Pada daftar project, pilih project yang ingin Anda hapus, lalu klik Delete.
  3. Pada dialog, ketik project ID, lalu klik Shut down untuk menghapus project.

Menghapus resource tutorial

  1. Hapus layanan Cloud Run yang Anda deploy dalam tutorial ini:

    gcloud run services delete SERVICE-NAME

    Dengan SERVICE-NAME adalah nama layanan pilihan Anda.

    Anda juga dapat menghapus layanan Cloud Run dari Konsol Google Cloud.

  2. Hapus konfigurasi region default gcloud yang Anda tambahkan selama penyiapan tutorial:

     gcloud config unset run/region
    
  3. Hapus konfigurasi project:

     gcloud config unset project
    
  4. Hapus resource Google Cloud lain yang dibuat dalam tutorial ini:

Langkah berikutnya