Questo tutorial mostra come risolvere i problemi di un servizio di pubblicazione Knative non funzionante utilizzando gli strumenti di Stackdriver per il rilevamento e un flusso di lavoro di sviluppo locale per le indagini.
Questo "case study" passo passo complementare alla guida alla risoluzione dei problemi utilizza un progetto di esempio che genera errori di runtime durante il deployment, che puoi risolvere per trovare e correggere il problema.
Obiettivi
- Scrivere, compilare ed eseguire il deployment di un servizio in Knative serving
- Utilizzare Cloud Logging per identificare un errore
- Recupera l'immagine del contenitore da Container Registry per un'analisi della causa principale
- Correggi il servizio "produzione", quindi miglioralo per ridurre i problemi futuri
Costi
In questo documento utilizzi 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 tu abbia installato e configurato Knative serving sul tuo 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 di saluto Knative serving passo passo. Ti ricordiamo che questo servizio crea intenzionalmente 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 del 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 avrà il seguente aspetto:{ "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, consulta la documentazione di package.json.
Python
Crea una nuova directory
hello-service
:mkdir hello-service cd hello-service
Crea un file requirements.txt e copia le dipendenze al suo interno:
Vai
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 accessibile tramite il web.
Java
Crea un progetto Maven:
mvn archetype:generate \ -DgroupId=com.example \ -DartifactId=hello-service \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false
Copia le dipendenze nell'elenco delle dipendenze
pom.xml
(tra gli elementi<dependencies>
):Copia l'impostazione di compilazione in
pom.xml
(sotto gli elementi<dependencies>
):
Crea un servizio HTTP per gestire le richieste in entrata:
Node.js
Python
Vai
Java
Crea un
Dockerfile
per definire l'immagine del container utilizzata per eseguire il deployment del servizio:Node.js
Python
Vai
Java
Questo esempio utilizza Jib per creare immagini Docker utilizzando strumenti Java comuni. Jib ottimizza le build dei container senza dover disporre di un Dockerfile o di Docker. Scopri di più sulla creazione di container Java con Jib.
Invio del codice
La spedizione del codice è composta da tre passaggi: creazione di un'immagine container con Cloud Build, caricamento dell'immagine container in Container Registry ed esecuzione del deployment dell'immagine container in Knative serving.
Per spedire il codice:
Crea il contenitore e pubblicalo su Container Registry:
Node.js
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
dove PROJECT_ID è l'ID progetto Google Cloud. Puoi controllare il tuo ID progetto corrente con
gcloud config get-value project
.In caso di esito positivo, dovresti visualizzare un messaggio di successo 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 è l'ID progetto Google Cloud. Puoi controllare il tuo ID progetto corrente con
gcloud config get-value project
.In caso di esito positivo, dovresti visualizzare un messaggio di successo 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.
Vai
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
dove PROJECT_ID è l'ID progetto Google Cloud. Puoi controllare il tuo ID progetto corrente con
gcloud config get-value project
.In caso di esito positivo, dovresti visualizzare un messaggio di successo 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 è l'ID progetto Google Cloud. Puoi controllare il tuo ID progetto corrente con
gcloud config get-value project
.In caso di esito positivo, dovresti visualizzare il messaggio BUILD SUCCESS. L'immagine è archiviata in Container Registry e, se lo desideri, può essere riutilizzata.
Esegui questo comando per eseguire il deployment dell'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 sia il nome del servizio Knative serving. Tieni presente che l'immagine del contenitore viene dispiattata nel servizio e nel cluster che hai configurato in precedenza in Configurazione di gcloudAttendi il completamento del deployment, che potrebbe richiedere circa mezzo minuto. Se l'operazione riesce, la riga di comando visualizza l'URL del servizio.
Prova
Prova il servizio per verificare di averlo implementato correttamente. Le richieste dovrebbero non riuscire con un errore HTTP 500 o 503 (membri della classe Errori del server 5xx). Il tutorial illustra la procedura di risoluzione dei problemi relativi a questa risposta di errore.
Se il cluster è configurato con un dominio predefinito instradabile, salta i passaggi precedenti e copia l'URL nel browser web.
Se non utilizzi i certificati TLS automatici e la mappatura dei domini, non ti viene fornito un URL navigabile per il tuo servizio.
Utilizza invece l'URL fornito e l'indirizzo IP del gateway di ingresso del servizio per creare un comando curl
che possa inviare richieste al servizio:
-
Per ottenere l'IP esterno per il bilanciatore del carico, esegui il seguente comando:
kubectl get svc istio-ingressgateway -n ASM-INGRESS-NAMESPACE
Sostituisci ASM-INGRESS-NAMESPACE con lo spazio dei nomi in cui si trova l'ingresso di Cloud Service Mesh. Specifica
istio-system
se hai installato Cloud Service Mesh utilizzando la 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 assegnato predefinito del servizio. Puoi ottenerlo prendendo l'URL predefinito e rimuovendo il protocollo
http://
.Visualizza il messaggio di errore HTTP 500 o HTTP 503.
Indagine sul problema
Visualizza che l'errore HTTP 5xx riscontrato sopra in Provare è stato rilevato come errore di runtime in produzione. Questo tutorial illustra una procedura formale per la gestione. Sebbene le procedure di risoluzione degli errori di produzione varieggino notevolmente, questo tutorial presenta una sequenza particolare di passaggi per mostrare l'applicazione di strumenti e tecniche utili.
Per esaminare questo problema, dovrai svolgere le seguenti fasi:
- Raccogli ulteriori dettagli sull'errore segnalato per supportare ulteriori indagini e impostare una strategia di mitigazione.
- Riduci l'impatto sugli utenti decidendo di applicare una correzione o di eseguire il rollback a una versione nota come sana.
- Riproduci l'errore per verificare che siano stati raccolti i dettagli corretti e che non si tratti di un problema temporaneo
- Esegui un'analisi delle cause principali del bug per trovare il codice, la configurazione o il processo che ha creato questo errore
All'inizio dell'indagine sono disponibili un URL, un timestamp e il messaggio "Internal Server Error".
Raccolta di ulteriori dettagli
Raccogliere ulteriori informazioni sul problema per capire cosa è successo e determinare i passaggi successivi.
Utilizza gli strumenti disponibili per raccogliere ulteriori dettagli:
Visualizza i log per ulteriori dettagli.
Utilizza Cloud Logging per esaminare la sequenza di operazioni che ha causato il problema, inclusi i messaggi di errore.
Esegui il rollback a una versione sana
Se hai una revisione che sai che funzionava, puoi eseguire il rollback del servizio per utilizzarla. 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:
Riprodurre l'errore
Utilizzando i dettagli ottenuti in precedenza, verifica che il problema si verifichi in modo coerente nelle condizioni di test.
Invia la stessa richiesta HTTP provando di nuovo e controlla se vengono segnalati gli stessi errori e dettagli. Potrebbe essere necessario del 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 non è così: potrebbe essere necessario riprodurre gli errori in un ambiente di test o limitare questo passaggio all'indagine locale.
La riproduzione dell'errore stabilisce il contesto per ulteriori operazioni. Ad esempio, se gli sviluppatori non riescono a riprodurre l'errore, ulteriori accertamenti potrebbero richiedere un'ulteriore strumentazione del servizio.
Eseguire un'analisi delle cause principali
L'analisi della causa principale è un passaggio importante per la risoluzione dei problemi in modo da risolvere il problema anziché un sintomo.
In precedenza in questo tutorial, hai riprodotto il problema su Knative serving, il che conferma che il problema è attivo quando il servizio è ospitato su Knative serving. Ora riproduci il problema localmente per determinare se è isolato nel codice o se si verifica solo nell'hosting di produzione.
Se non hai utilizzato Docker CLI localmente con Container Registry, autenticalo con gcloud:
gcloud auth configure-docker
Per approcci alternativi, consulta Metodi di autenticazione di Container Registry.
Se il nome dell'immagine container utilizzata più di recente non è disponibile, la descrizione del servizio contiene le informazioni sull'immagine container di cui è stato eseguito il deployment più di recente:
gcloud run services describe hello-service
Trova il nome dell'immagine del contenitore 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 mostra il nome di un'immagine container, ad esempio
gcr.io/PROJECT_ID/hello-service
.Estrai l'immagine container da Container Registry nel tuo ambiente. Questo passaggio potrebbe richiedere diversi minuti durante il download dell'immagine container:
docker pull gcr.io/PROJECT_ID/hello-service
Gli aggiornamenti successivi all'immagine del contenitore 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 del contenitore se non è presente sulla macchina locale.Esegui l'app in locale per verificare che il problema non sia specifico di Knative serving:
PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \ gcr.io/PROJECT_ID/hello-service
Se analizziamo gli elementi del comando riportato sopra,
- La variabile di ambiente
PORT
viene utilizzata dal servizio per determinare la porta su cui eseguire l'ascolto all'interno del contenitore. - Il comando
run
avvia il contenitore, utilizzando per impostazione predefinita il comando entrypoint definito nel Dockerfile o un'immagine container principale. - Il flag
--rm
elimina l'istanza del contenitore all'uscita. - Il flag
-e
assegna un valore a una variabile di ambiente.-e PORT=$PORT
propaga la variabilePORT
dal sistema locale al contenitore con lo stesso nome. - Il flag
-p
pubblica il contenitore come servizio disponibile su localhost sulla 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à al modo in cui si accede al servizio. - L'ultimo argomento
gcr.io/PROJECT_ID/hello-service
è un percorso del repository che rimanda alla versione più recente dell'immagine del contenitore. Se non è disponibile localmente, Docker tenta di recuperare l'immagine da un registro remoto.
Nel browser, apri http://localhost:9000. Controlla l'output del terminale per verificare se sono presenti messaggi di errore corrispondenti a quelli di Google Cloud Observability.
Se il problema non è riproducibile localmente, potrebbe essere specifico per l'ambiente di pubblicazione Knative. Consulta la guida alla risoluzione dei problemi di Knative serving per individuare le aree specifiche da esaminare.
In questo caso, l'errore viene riprodotto localmente.
- La variabile di ambiente
Ora che l'errore è stato confermato come persistente e causato dal codice del servizio anziché dalla piattaforma di hosting, è il momento di esaminare più da vicino il codice.
Ai fini di questo tutorial, è possibile assumere che il codice all'interno del contenitore e il codice nel sistema locale siano identici.
Node.js
Individua l'origine del messaggio di errore nel fileindex.js
intorno al numero di riga indicato nella analisi dello stack mostrata nei log:
Python
Individua l'origine del messaggio di errore nel filemain.py
intorno al numero di riga indicato nella analisi dello stack mostrata nei log:
Vai
Individua l'origine del messaggio di errore nel file main.go
intorno al numero di riga indicato nella analisi dello stack mostrata nei log:
Java
Individua la fonte del messaggio di errore nel file App.java
intorno al numero di riga indicato nella analisi dello stack mostrata nei log:
Esaminando questo codice, quando la variabile di ambiente NAME
non è impostata vengono eseguite le seguenti azioni:
- Viene registrato un errore in Google Cloud Observability
- Viene inviata una risposta di errore HTTP
Il problema è causato da una variabile mancante, ma la causa principale è più specifica: la modifica del codice che aggiunge la dipendenza obbligatoria da una variabile di ambiente non includeva modifiche correlate agli script di deployment e alla documentazione dei requisiti di runtime.
Risolvere la causa principale
Ora che abbiamo raccolto il codice e identificato la potenziale causa principale, possiamo adottare le misure del caso per risolvere il problema.
Verifica se il servizio funziona localmente con l'ambiente
NAME
disponibile:Esegui il contenitore localmente con la variabile di ambiente aggiunta:
PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \ -e NAME="Local World!" \ gcr.io/PROJECT_ID/hello-service
Apri il browser e vai all'indirizzo http://localhost:9000
Visualizza "Hello Local World!" nella pagina
Modifica l'ambiente del servizio Knative serving in esecuzione in modo da 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 Knative serving crea una nuova revisione in base alla revisione precedente con la nuova variabile di ambiente aggiunta.
Verifica che il servizio sia stato risolto:
- Apri l'URL del servizio Knative serving nel browser.
- Nella pagina viene visualizzato il messaggio "Hello Override!".
- Verifica che in Cloud Logging non vengano visualizzati messaggi o errori imprevisti.
Migliorare la velocità di risoluzione dei problemi futuri
In questo problema di produzione di esempio, l'errore era correlato alla configurazione operativa. Esistono modifiche al codice che ridurranno al minimo l'impatto di questo problema in futuro.
- Migliora il log degli errori in modo da includere dettagli più specifici.
- Anziché restituire un errore, il servizio deve eseguire il fallback a un valore predefinito sicuro. Se l'utilizzo di un valore predefinito rappresenta una modifica alla funzionalità normale, utilizza un messaggio di avviso per il monitoraggio.
Vediamo come rimuovere la variabile di ambiente NAME
come dipendenza obbligatoria.
Rimuovi il codice di gestione
NAME
esistente:Node.js
Python
Vai
Java
Aggiungi nuovo codice che imposta un valore alternativo:
Node.js
Python
Vai
Java
Esegui il test a livello locale ricostruendo ed eseguendo il container nei 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 .
Vai
docker build --tag gcr.io/PROJECT_ID/hello-service .
Java
mvn compile jib:build
Verifica che la variabile di ambiente
NAME
funzioni ancora: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 righe aggiuntive, ad esempio quelle utilizzate per scrivere la risposta.
Esegui il deployment consultando la sezione Eseguire il deployment del codice.
Ogni deployment in un servizio crea una nuova revisione e avvia automaticamente il servizio 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.
Trovare altri problemi nei log
Potresti notare altri problemi nel visualizzatore log per questo servizio. Ad esempio, una chiamata di sistema non supportata viene visualizzata nei log come "Limitazione della sandbox del contenitore".
Ad esempio, a volte i servizi Node.js generano questo 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 di sostenere costi.
Eliminazione delle risorse dei tutorial
Elimina il servizio Knative serving di cui hai eseguito il deployment in questo tutorial:
gcloud run services delete SERVICE-NAME
dove SERVICE-NAME è il nome del servizio scelto.
Puoi anche eliminare i servizi Knative serving 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 l'immagine container denominata
gcr.io/<var>PROJECT_ID</var>/hello-service
da Container Registry. - Se hai creato un cluster per questo tutorial, eliminalo.
- Elimina l'immagine container denominata
Passaggi successivi
- Scopri di più su come utilizzare Cloud Logging per ottenere informazioni sul comportamento in produzione.
- Scopri di più sulla risoluzione dei problemi di Knative serving.
- Esplora architetture di riferimento, diagrammi e best practice su Google Cloud. Consulta il nostro Cloud Architecture Center.