Questo tutorial mostra come risolvere i problemi relativi a un servizio di gestione di Knative non funzionante utilizzando gli strumenti di Stackdriver per il rilevamento e un flusso di lavoro di sviluppo locale per l'analisi.
Questa procedura complementare dettagliata del "case study" della guida alla risoluzione dei problemi utilizza un progetto di esempio che, al momento del deployment, genera errori di runtime, che potrai risolvere per individuare e risolvere il problema.
Obiettivi
- Scrivi, crea ed esegui il deployment di un servizio nella gestione di Knative
- Utilizzare Cloud Logging per identificare un errore
- Recupera l'immagine container da Container Registry per un'analisi delle cause principali
- Correggi il servizio di "produzione", quindi migliora il servizio per mitigare i problemi futuri
Costi
In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:
Per generare una stima dei costi in base all'utilizzo previsto,
utilizza il Calcolatore prezzi.
Prima di iniziare
- Questo tutorial presuppone che la pubblicazione di Knative sia installata e configurata sul cluster.
- Assicurati che l'ambiente a riga di comando sia configurato e che gli strumenti siano aggiornati:
- Installa curl per provare il servizio.
- Installa Docker localmente.
Assemblaggio del codice
Crea un nuovo servizio greeter di Knative passo passo. Ti ricordiamo che questo servizio crea appositamente un errore di runtime per l'esercizio di risoluzione dei problemi.
Crea un nuovo progetto:
Node.js
Crea un progetto Node.js definendo il pacchetto di servizio, le dipendenze iniziali e alcune operazioni comuni.Crea una directory
hello-service
:mkdir hello-service cd hello-service
Genera un file
package.json
:npm init --yes npm install --save express@4
Apri il nuovo file
package.json
nell'editor e configura uno scriptstart
per eseguirenode index.js
. Al termine, il file sarà simile a questo:{ "name": "hello-service", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1" } }
Se continui a sviluppare questo servizio oltre il tutorial immediato, ti consigliamo di compilare la descrizione, l'autore e valutare la licenza. Per ulteriori dettagli, leggi la documentazione dipackage.json.
Python
Crea una nuova directory
hello-service
:mkdir hello-service cd hello-service
Crea un file requirements.txt e copia al suo interno le dipendenze:
Go
Crea una directory
hello-service
:mkdir hello-service cd hello-service
Crea un progetto Go inizializzando un nuovo modulo Go:
go mod init <var>my-domain</var>.com/hello-service
Puoi aggiornare il nome specifico come preferisci: devi aggiornarlo se il codice viene pubblicato in un repository di codice raggiungibile dal web.
Java
Crea un progetto Maven:
mvn archetype:generate \ -DgroupId=com.example \ -DartifactId=hello-service \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false
Copia le dipendenze nel tuo elenco di dipendenze
pom.xml
(tra gli elementi<dependencies>
):Copia l'impostazione di build in
pom.xml
(sotto gli elementi<dependencies>
):
Crea un servizio HTTP per gestire le richieste in entrata:
Node.js
Python
Go
Java
Crea un oggetto
Dockerfile
per definire l'immagine container utilizzata per il deployment del servizio:Node.js
Python
Go
Java
Questo esempio utilizza Jib per creare immagini Docker con gli strumenti Java comuni. Jib ottimizza le build di container senza bisogno di un Dockerfile o di dover installare Docker. Scopri di più sulla creazione di container Java con Jib.
Spedisci il codice
Il codice di spedizione prevede tre passaggi: creazione di un'immagine container con Cloud Build, caricamento dell'immagine container su Container Registry e deployment dell'immagine container nella pubblicazione con Knative.
Per spedire il tuo codice:
Crea il tuo container e pubblicalo su Container Registry:
Node.js
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
Dove PROJECT_ID è il tuo ID progetto Google Cloud. Puoi controllare il tuo ID progetto attuale con
gcloud config get-value project
.Se l'operazione va a buon fine, dovresti visualizzare un messaggio SUCCESSIVO contenente l'ID, l'ora di creazione e il nome dell'immagine. L'immagine è archiviata in Container Registry e, se lo desideri, può essere riutilizzata.
Python
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
Dove PROJECT_ID è il tuo ID progetto Google Cloud. Puoi controllare il tuo ID progetto attuale con
gcloud config get-value project
.Se l'operazione va a buon fine, dovresti visualizzare un messaggio SUCCESSIVO contenente l'ID, l'ora di creazione e il nome dell'immagine. L'immagine è archiviata in Container Registry e, se lo desideri, può essere riutilizzata.
Go
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
Dove PROJECT_ID è il tuo ID progetto Google Cloud. Puoi controllare il tuo ID progetto attuale con
gcloud config get-value project
.Se l'operazione va a buon fine, dovresti visualizzare un messaggio SUCCESSIVO contenente l'ID, l'ora di creazione e il nome dell'immagine. L'immagine è archiviata in Container Registry e, se lo desideri, può essere riutilizzata.
Java
mvn compile jib:build -Dimage=gcr.io/PROJECT_ID/hello-service
Dove PROJECT_ID è il tuo ID progetto Google Cloud. Puoi controllare il tuo ID progetto attuale con
gcloud config get-value project
.Se l'operazione ha esito positivo, dovresti visualizzare il messaggio COSTRUIRE RIUSCITA. L'immagine è archiviata in Container Registry e, se lo desideri, può essere riutilizzata.
Esegui questo comando per eseguire il deployment della tua app:
gcloud run deploy hello-service --image gcr.io/PROJECT_ID/hello-service
Sostituisci PROJECT_ID con l'ID del tuo progetto Google Cloud.
hello-service
è sia il nome dell'immagine container del servizio di pubblicazione Knative. Nota che il deployment dell'immagine container è stato eseguito nel servizio e nel cluster che hai configurato in precedenza in Configurazione di gcloud.Attendi il completamento del deployment: questa operazione può richiedere circa mezzo minuto. Se l'operazione riesce, la riga di comando visualizza l'URL del servizio.
Provalo
Prova il servizio per verificare di aver eseguito il deployment correttamente. Le richieste non dovrebbero andare a buon fine con un errore HTTP 500 o 503 (membri della classe Errori del server 5xx). Il tutorial illustra la risoluzione dei problemi relativi a questa risposta di errore.
Se il cluster è configurato con un dominio predefinito instradabile, salta i passaggi precedenti e copia invece l'URL nel tuo browser web.
Se non utilizzi i certificati TLS automatici e il mappatura dei domini, non ti viene fornito un URL di navigazione per il tuo servizio.
Utilizza invece l'URL fornito e l'indirizzo IP del gateway in entrata del servizio per creare un comando curl
che possa effettuare richieste al tuo servizio:
-
Per ottenere l'indirizzo IP esterno del bilanciatore del carico, esegui questo comando:
kubectl get svc istio-ingressgateway -n ASM-INGRESS-NAMESPACE
Sostituisci ASM-INGRESS-NAMESPACE con lo spazio dei nomi in cui si trova il traffico in entrata di Anthos Service Mesh. Specifica
istio-system
se hai installato Anthos Service Mesh utilizzando la sua configurazione predefinita.L'output risultante è simile al seguente:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) istio-ingressgateway LoadBalancer XX.XX.XXX.XX pending 80:32380/TCP,443:32390/TCP,32400:32400/TCP
dove il valore EXTERNAL-IP è l'indirizzo IP esterno del bilanciatore del carico.
Esegui un comando
curl
utilizzando questo indirizzoGATEWAY_IP
nell'URL.curl -G -H "Host: SERVICE-DOMAIN" https://EXTERNAL-IP/
Sostituisci SERVICE-DOMAIN con il dominio predefinito assegnato al tuo servizio. Puoi ottenerlo prendendo l'URL predefinito e rimuovendo il protocollo
http://
.Visualizza il messaggio di errore HTTP 500 o HTTP 503.
Analisi del problema
Visualizza che l'errore HTTP 5xx riscontrato in precedenza nella sezione Prova è stato riscontrato come errore di runtime in produzione. Questo tutorial illustra un processo formale di gestione. Sebbene i processi di risoluzione degli errori di produzione siano ampiamente diversi, questo tutorial presenta una specifica sequenza di passaggi per mostrare l'applicazione di strumenti e tecniche utili.
Per analizzare questo problema, dovrai seguire queste fasi:
- Raccogliere ulteriori dettagli sull'errore segnalato per supportare ulteriori indagini e impostare una strategia di mitigazione.
- Allevia l’impatto sugli utenti decidendo di eseguire il push di una correzione o il rollback a una versione integro noto.
- Riproduci l'errore per confermare che siano stati raccolti i dettagli corretti e che l'errore non si tratti di un problema
- Esegui un'analisi delle cause principali del bug per trovare il codice, la configurazione o il processo che ha creato l'errore
All'inizio dell'indagine sono presenti un URL, un timestamp e il messaggio "Errore interno del server".
Raccolta di ulteriori dettagli
Raccogliere ulteriori informazioni sul problema per capire cosa è successo e stabilire i passaggi successivi.
Usa gli strumenti disponibili per raccogliere ulteriori dettagli:
Visualizza i log per maggiori dettagli.
Utilizza Cloud Logging per esaminare la sequenza delle operazioni che hanno portato al problema, inclusi i messaggi di errore.
Esegui il rollback a una versione integra
Se disponi di una revisione che funzionava, puoi eseguire il rollback del servizio per utilizzare quella revisione. Ad esempio,
non potrai eseguire un rollback sul nuovo servizio
hello-service
di cui hai eseguito il deployment in questo
tutorial perché contiene una sola revisione.
Per individuare una revisione e eseguire il rollback del servizio:
Riproduzione dell'errore
Utilizzando i dettagli ottenuti in precedenza, verifica che il problema si verifichi costantemente in condizioni di test.
Invia la stessa richiesta HTTP riprovandola e controlla se vengono segnalati lo stesso errore e i relativi dettagli. Potrebbe essere necessario attendere un po' di tempo prima che vengano visualizzati i dettagli dell'errore.
Poiché il servizio di esempio in questo tutorial è di sola lettura e non attiva effetti collaterali complicati, la riproduzione di errori in produzione è sicura. Tuttavia, per molti servizi reali, questo non avviene: potresti dover riprodurre gli errori in un ambiente di test o limitare questo passaggio all'indagine locale.
La riproduzione dell'errore stabilisce il contesto da sottoporre a ulteriore lavoro. Ad esempio, se gli sviluppatori non riescono a riprodurre l'errore, ulteriori indagini potrebbero richiedere l'uso di strumenti aggiuntivi per il servizio.
Esecuzione dell'analisi delle cause principali
L'analisi delle cause principali è un passaggio importante per una risoluzione dei problemi efficace per assicurare la risoluzione del problema invece che di un sintomo.
In precedenza, in questo tutorial hai riprodotto il problema nella pubblicazione con Knative, a conferma che il problema è attivo quando il servizio è ospitato sulla pubblicazione con Knative. Ora riproduci il problema localmente per determinare se il problema è isolato dal codice o se emerge solo nell'hosting di produzione.
Se non hai utilizzato l'interfaccia a riga di comando di Docker localmente con Container Registry, autenticala con gcloud:
gcloud auth configure-docker
Per approcci alternativi, consulta Metodi di autenticazione di Container Registry.
Se il nome dell'immagine container utilizzato più di recente non è disponibile, la descrizione del servizio contiene le informazioni dell'immagine container di cui è stato eseguito il deployment più di recente:
gcloud run services describe hello-service
Trova il nome dell'immagine container all'interno dell'oggetto
spec
. Un comando più mirato può recuperarlo direttamente:gcloud run services describe hello-service \ --format="value(spec.template.spec.containers.image)"
Questo comando rivela il nome di un'immagine container, come
gcr.io/PROJECT_ID/hello-service
.Esegui il pull dell'immagine container da Container Registry al tuo ambiente. Questo passaggio potrebbe richiedere diversi minuti mentre scarica l'immagine container:
docker pull gcr.io/PROJECT_ID/hello-service
Gli aggiornamenti successivi all'immagine container che riutilizzano questo nome possono essere recuperati con lo stesso comando. Se salti questo passaggio, il comando
docker run
riportato di seguito estrae un'immagine container se non ne esiste una sulla macchina locale.Esegui localmente per verificare che il problema non riguardi esclusivamente la pubblicazione con Knative:
PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \ gcr.io/PROJECT_ID/hello-service
Analizzando gli elementi del comando precedente,
- La variabile di ambiente
PORT
viene utilizzata dal servizio per determinare la porta per l'ascolto all'interno del container. - Il comando
run
avvia il container, ripristinando per impostazione predefinita il comando del punto di ingresso definito nel Dockerfile o in un'immagine container padre. - Il flag
--rm
elimina l'istanza del container all'uscita. - Il flag
-e
assegna un valore a una variabile di ambiente.-e PORT=$PORT
sta propagando la variabilePORT
dal sistema locale al container con lo stesso nome di variabile. - Il flag
-p
pubblica il container come servizio disponibile su localhost alla porta 9000. Le richieste a localhost:9000 verranno instradate al container sulla porta 8080. Ciò significa che l'output del servizio relativo al numero di porta in uso non corrisponderà alla modalità di accesso al servizio. - L'argomento finale
gcr.io/PROJECT_ID/hello-service
è un percorso del repository che rimanda alla versione più recente dell'immagine container. Se non è disponibile localmente, docker tenta di recuperare l'immagine da un registro remoto.
Nel browser, apri http://localhost:9000. Controlla se nell'output del terminale sono presenti messaggi di errore corrispondenti a quelli di Google Cloud Observability.
Se il problema non è riproducibile localmente, potrebbe essere univoco per l'ambiente di pubblicazione Knative. Consulta la guida alla risoluzione dei problemi relativi alla pubblicazione con Knative per informazioni sulle aree specifiche da analizzare.
In questo caso, l'errore viene riprodotto localmente.
- La variabile di ambiente
Ora che l'errore viene doppiamente confermato come persistente e causato dal codice del servizio invece che dalla piattaforma di hosting, è il momento di esaminare il codice più da vicino.
Ai fini di questo tutorial, è sicuro presumere che il codice all'interno del container e il codice nel sistema locale siano identici.
Node.js
Trova l'origine del messaggio di errore nel fileindex.js
intorno al numero di riga richiamato nell'analisi dello stack mostrata nei log:
Python
Trova l'origine del messaggio di errore nel filemain.py
intorno al numero di riga richiamato nell'analisi dello stack mostrata nei log:
Go
Trova l'origine del messaggio di errore nel file main.go
intorno al numero di riga richiamato nell'analisi dello stack mostrata nei log:
Java
Trova l'origine del messaggio di errore nel file App.java
intorno al numero di riga richiamato nell'analisi dello stack mostrata nei log:
Esaminando questo codice, vengono intraprese le seguenti azioni quando la variabile di ambiente NAME
non è impostata:
- Viene registrato un errore nell'osservabilità di Google Cloud
- Viene inviata una risposta di errore HTTP
Il problema è causato da una variabile mancante, ma la causa principale è più specifica: la modifica del codice, aggiungendo la dipendenza rigida su una variabile di ambiente, non includeva le modifiche correlate agli script di deployment e alla documentazione sui requisiti di runtime.
Correzione della causa principale
Ora che abbiamo raccolto il codice e identificato la potenziale causa principale, possiamo adottare le misure necessarie per risolvere il problema.
Controlla se il servizio funziona localmente con l'ambiente
NAME
disponibile:Esegui il container in locale aggiungendo la variabile di ambiente:
PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \ -e NAME="Local World!" \ gcr.io/PROJECT_ID/hello-service
Nel browser vai all'indirizzo http://localhost:9000
Vedi "Hello Local World!" nella pagina
Modifica l'ambiente di servizio di pubblicazione Knative in esecuzione per includere questa variabile:
Esegui il comando di aggiornamento dei servizi con il parametro
--update-env-vars
per aggiungere una variabile di ambiente:gcloud run services update hello-service \ --update-env-vars NAME=Override
Attendi qualche secondo mentre la gestione di Knative crea una nuova revisione basata sulla revisione precedente con l'aggiunta della nuova variabile di ambiente.
Verifica che il servizio sia stato risolto:
- Vai all'URL del servizio di pubblicazione Knative nel browser.
- Vedi "Hello Override!" nella pagina.
- Verifica che in Cloud Logging non vengano visualizzati errori o messaggi imprevisti.
Miglioramento della velocità futura della risoluzione dei problemi
In questo problema di produzione di esempio, l'errore riguardava la configurazione operativa. Esistono modifiche al codice che ridurranno al minimo l'impatto di questo problema in futuro.
- Migliora il log degli errori per includere dettagli più specifici.
- Invece di restituire un errore, imposta il servizio su un valore predefinito sicuro. Se l'utilizzo di un valore predefinito rappresenta una modifica alla normale funzionalità, utilizza un messaggio di avviso a scopo di monitoraggio.
Vediamo come rimuovere la variabile di ambiente NAME
come dipendenza rigida.
Rimuovi il codice di gestione
NAME
esistente:Node.js
Python
Go
Java
Aggiungi nuovo codice che imposta un valore di riserva:
Node.js
Python
Go
Java
Esegui test in locale ricreando ed eseguendo il container tramite i casi di configurazione interessati:
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
Verifica che la variabile di ambiente
NAME
continui a funzionare:PORT=8080 && docker run --rm -e $PORT -p 9000:$PORT \ -e NAME="Robust World" \ gcr.io/PROJECT_ID/hello-service
Verifica che il servizio funzioni senza la variabile
NAME
:PORT=8080 && docker run --rm -e $PORT -p 9000:$PORT \ gcr.io/PROJECT_ID/hello-service
Se il servizio non restituisce un risultato, verifica che la rimozione del codice nel primo passaggio non abbia rimosso le righe aggiuntive, ad esempio quelle utilizzate per scrivere la risposta.
Per eseguire il deployment, rivedi la sezione Esegui il deployment del codice.
Ogni deployment in un servizio crea una nuova revisione e inizia automaticamente a gestire il traffico quando è pronto.
Per cancellare le variabili di ambiente impostate in precedenza:
gcloud run services update hello-service --clear-env-vars
Aggiungi la nuova funzionalità per il valore predefinito alla copertura dei test automatici per il servizio.
Ricerca di altri problemi nei log
Potresti notare altri problemi nel visualizzatore log di questo servizio. Ad esempio, una chiamata di sistema non supportata verrà visualizzata nei log come "Limitazione della sandbox del container".
Ad esempio, a volte i servizi Node.js restituiscono il seguente messaggio di log:
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.
In questo caso, la mancanza di assistenza non influisce sul servizio di esempio hello-service.
Esegui la pulizia
Puoi eliminare le risorse create per questo tutorial per evitare costi.
Eliminazione delle risorse del tutorial
Elimina il servizio di gestione Knative di cui hai eseguito il deployment in questo tutorial:
gcloud run services delete SERVICE-NAME
Dove SERVICE-NAME è il nome del servizio che hai scelto.
Puoi anche eliminare i servizi di gestione Knative dalla console Google Cloud:
Rimuovi le configurazioni predefinite di gcloud che hai aggiunto durante la configurazione del tutorial:
gcloud config unset run/platform gcloud config unset run/cluster gcloud config unset run/cluster_location
Rimuovi la configurazione del progetto:
gcloud config unset project
Elimina le altre risorse Google Cloud create in questo tutorial:
- Elimina da Container Registry l'immagine container denominata
gcr.io/<var>PROJECT_ID</var>/hello-service
. - Se hai creato un cluster per questo tutorial, elimina il cluster.
- Elimina da Container Registry l'immagine container denominata
Passaggi successivi
- Scopri di più su come utilizzare Cloud Logging per ottenere insight sul comportamento in produzione.
- Per ulteriori informazioni sulla risoluzione dei problemi relativi alla pubblicazione con Knative.
- Esplora le architetture di riferimento, i diagrammi e le best practice su Google Cloud. Visita il nostro Cloud Architecture Center.