Questo tutorial mostra come risolvere un guasto Servizio Knative serving che utilizza gli strumenti di Stackdriver per il rilevamento e e un flusso di lavoro di sviluppo.
Questo "case study" dettagliato associato al guida alla risoluzione dei problemi utilizza un progetto di esempio che provoca errori di runtime al momento del deployment, che dovrai individuare e correggere risolvere il problema.
Obiettivi
- Scrivi, crea ed esegui il deployment di un servizio su Knative serving
- Utilizzare Cloud Logging per identificare un errore
- Recupera l'immagine container da Container Registry per un'analisi delle cause principali
- Correggi il problema "production" e migliorare 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 basata sull'utilizzo previsto,
utilizza il Calcolatore prezzi.
Prima di iniziare
- Questo tutorial presuppone che tu abbia Knative serving installati e configurati sul tuo cluster.
- Assicurati che l'ambiente a riga di comando sia configurato e che gli strumenti siano up-to-date:
- Installa curl per provare il servizio.
- Installa Docker in locale.
Assemblaggio del codice
Crea passo dopo passo un nuovo servizio di chat Knative serving. Ti ricordiamo che questo servizio crea un errore di runtime per risoluzione dei problemi dell'allenamento.
Crea un nuovo progetto:
Node.js
Creare 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 unstart
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, valuta inserendo la descrizione, l'autore e valutando 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 le tue 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 aggiornare il nome se 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 nell'elenco delle dipendenze
pom.xml
(tra gli elementi<dependencies>
):Copia l'impostazione della build 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 container utilizzata per il deployment del servizio:Node.js
Python
Vai
Java
Questo esempio utilizza Jib per creare utilizzando strumenti Java comuni. Jib ottimizza le build di container senza la necessità di un Dockerfile o di avere Docker installato. Scopri di più sulla creazione di container Java con Jib.
Spedizione del codice
Il codice di spedizione prevede tre passaggi: la creazione di un'immagine container con Cloud Build, caricando l'immagine container in Container Registry il deployment dell'immagine container in Knative serving.
Per spedire il 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 è l'ID progetto Google Cloud. Puoi controllare ID progetto attuale con
gcloud config get-value project
.Se l'operazione riesce, dovresti vedere il messaggio SUCCESS contenente l'ID, la creazione ora e nome dell'immagine. L'immagine è archiviata in Container Registry e può essere se lo desideri,
Python
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
Dove PROJECT_ID è l'ID progetto Google Cloud. Puoi controllare ID progetto attuale con
gcloud config get-value project
.Se l'operazione riesce, dovresti vedere il messaggio SUCCESS contenente l'ID, la creazione ora e nome dell'immagine. L'immagine è archiviata in Container Registry e può essere se lo desideri,
Vai
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
Dove PROJECT_ID è l'ID progetto Google Cloud. Puoi controllare ID progetto attuale con
gcloud config get-value project
.Se l'operazione riesce, dovresti vedere il messaggio SUCCESS contenente l'ID, la creazione ora e nome dell'immagine. L'immagine è archiviata in Container Registry e può essere se lo desideri,
Java
mvn compile jib:build -Dimage=gcr.io/PROJECT_ID/hello-service
Dove PROJECT_ID è l'ID progetto Google Cloud. Puoi controllare ID progetto attuale con
gcloud config get-value project
.Se l'operazione riesce, dovresti visualizzare il messaggio BUILD SUCCESS. L'immagine è archiviata in in Container Registry e può essere riutilizzato, se necessario.
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 sia il nome del servizio Knative serving. Tieni presente che viene eseguito il deployment dell'immagine container nel servizio e nel cluster che hai configurato in precedenza in Impostazione di gcloudAttendi il completamento del deployment: l'operazione può 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 eseguito correttamente. Richieste dovrebbe restituire un errore HTTP 500 o 503 (i 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 routing dominio predefinito, ignora i passaggi precedenti e copia l'URL nel tuo browser web.
Se non utilizzi i certificati TLS automatici e la mappatura dei domini. Non ti viene fornito URL raggiungibile per il tuo servizio.
Utilizza invece l'URL fornito e l'indirizzo IP del traffico in entrata del servizio
gateway per creare un comando curl
che può effettuare richieste al tuo servizio:
-
Per ottenere l'IP esterno per il 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 Cloud Service Mesh. Specifica
istio-system
se ha 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 è il tuo indirizzo IP esterno del modulo di Google Cloud.
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 tuo completamente gestito di Google Cloud. Puoi ottenerlo prendendo l'URL predefinito e rimuovendo il protocollo
http://
.Visualizza il messaggio di errore HTTP 500 o HTTP 503.
Analisi del problema
Verifica che l'errore HTTP 5xx riscontrato in Prova è stato riscontrato come un errore di runtime di produzione. Questo tutorial illustra una processo formale per gestirlo. Sebbene i processi di risoluzione degli errori di produzione variano notevolmente, questo tutorial presenta una sequenza particolare di passaggi per mostrare l'applicazione di strumenti e tecniche utili.
Per esaminare questo problema dovrai seguire queste fasi:
- Raccogliere maggiori dettagli sull’errore segnalato per supportare ulteriori indagini e impostare una strategia di mitigazione.
- Allevia l'impatto degli utenti decidendo se eseguire una correzione o eseguire il rollback a una versione integro nota.
- Riproduci l'errore per confermare che sono stati raccolti i dettagli corretti e che l'errore non è un glitch una tantum
- Esegui un'analisi della causa principale del bug per trovare il codice, la configurazione processo che ha creato l'errore
All'inizio dell'indagine hai 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 determinare i passaggi successivi.
Utilizza gli strumenti disponibili per raccogliere ulteriori dettagli:
Visualizza i log per ulteriori dettagli.
Usa Cloud Logging per rivedere la sequenza di operazioni che portano problema, inclusi i messaggi di errore.
Esegui il rollback a una versione integro
Se hai una revisione che è stata
funziona, puoi eseguire il rollback del servizio per utilizzare la revisione. Ad esempio:
non potrai eseguire un rollback sul nuovo
Servizio hello-service
di cui hai eseguito il deployment in questo
perché contiene una sola revisione.
Per individuare una revisione ed eseguire il rollback del tuo servizio:
Riproduzione dell'errore in corso...
Utilizzando i dettagli ottenuti in precedenza, conferma si verifica sempre in condizioni di test.
Invia la stessa richiesta HTTP riprovando e controlla se vengono segnalati lo stesso errore con i relativi dettagli. I dettagli dell'errore possono richiedere del tempo che vengano mostrati.
Poiché il servizio di esempio in questo tutorial è di sola lettura e non attiva alcuno complicando gli effetti collaterali, la riproduzione degli errori in produzione è sicura. Tuttavia, per molti servizi reali, non sarà così: potresti dover riprodurre gli errori in un ambiente di test o limitare questo passaggio alle indagini locali.
La riproduzione dell'errore stabilisce il contesto per ulteriori lavori. Ad esempio: Se gli sviluppatori non riescono a riprodurre l'errore, potrebbero essere necessarie ulteriori indagini strumentazione aggiuntiva del servizio.
Esecuzione dell'analisi delle cause principali
L'analisi delle cause principali è un passaggio importante risoluzione dei problemi efficace per assicurarti di risolvere il problema anziché un sintomo.
In precedenza, in questo tutorial hai riprodotto il problema su Knative serving che conferma che il problema è attivo quando il servizio è ospitato su Knative serving. Ora riproduci il problema in locale per determinare se è isolato al codice o se emerge solo nell'hosting di produzione.
Se non hai utilizzato l'interfaccia a riga di comando Docker in locale con Container Registry, esegui l'autenticazione con gcloud:
gcloud auth configure-docker
Per gli approcci alternativi, vedi Metodi di autenticazione di Container Registry.
Se il nome dell'immagine container utilizzato più di recente non è disponibile, il servizio contiene le informazioni sull'immagine container di cui è stato eseguito il deployment più recente:
gcloud run services describe hello-service
Trova il nome dell'immagine container all'interno dell'oggetto
spec
. Un tipo di campagna kubectl 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, potrebbe richiedere diversi minuti per scaricare l'immagine container:
docker pull gcr.io/PROJECT_ID/hello-service
È possibile recuperare gli aggiornamenti successivi all'immagine container che riutilizzano questo nome con lo stesso comando. Se salti questo passaggio, utilizza il comando
docker run
riportato di seguito esegue il pull di un'immagine container se non è presente sulla macchina locale.Eseguilo localmente per verificare che il problema non sia univoco di Knative serving:
PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \ gcr.io/PROJECT_ID/hello-service
Analizziamo gli elementi del comando precedente,
- La variabile di ambiente
PORT
viene utilizzata dal servizio per determinare la per rimanere in ascolto all'interno del container. - Il comando
run
avvia il container, utilizzando come impostazione predefinita il punto di ingresso definito nel Dockerfile o in un'immagine container padre. - Il flag
--rm
elimina l'istanza di 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 sulla porta 9000. Le richieste a localhost:9000 verranno indirizzate al sulla porta 8080. Ciò significa che l'output del servizio relativo alla porta numero in uso non corrisponderà alla modalità di accesso al servizio. - L'argomento finale
gcr.io/PROJECT_ID/hello-service
è un percorso del repository che punta alla versione più recente del container dell'immagine. Se non è disponibile localmente, Docker cerca di recuperare l'immagine da da un registry remoto.
Nel browser, apri http://localhost:9000. Controlla l'output del terminale per che corrispondono a quelli di Google Cloud Observability.
Se il problema non è riproducibile localmente, potrebbe essere univoco Ambiente Knative serving. Esamina il Guida alla risoluzione dei problemi di Knative serving per aree specifiche da esaminare.
In questo caso l'errore viene riprodotto localmente.
- La variabile di ambiente
Ora che l'errore è confermato doppiamente come permanente e causato dal servizio anziché sulla piattaforma di hosting, è il momento di esaminare il codice in modo più approfondito.
Ai fini di questo tutorial, è consigliabile presupporre il codice all'interno del container e il codice nel sistema locale è identico.
Node.js
Individua l'origine del messaggio di errore nel fileindex.js
intorno alla riga
numero chiamato nell'analisi dello stack mostrata nei log:
Python
Individua l'origine del messaggio di errore nel filemain.py
intorno alla riga
numero chiamato nell'analisi dello stack mostrata nei log:
Vai
Individua l'origine del messaggio di errore nel file main.go
intorno alla riga
numero chiamato nell'analisi dello stack mostrata nei log:
Java
Individua l'origine del messaggio di errore nel file App.java
, intorno al numero di riga indicato nell'analisi dello stack mostrata nei log:
Durante l'esame di questo codice, vengono eseguite le seguenti azioni quando l'ambiente NAME
non è impostata:
- 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 al codice che aggiungeva la dipendenza rigida su una variabile di ambiente che includa le modifiche correlate agli script di deployment e alla documentazione sui requisiti di runtime.
Risoluzione della causa principale
Ora che abbiamo raccolto il codice e identificato la potenziale causa principale, possiamo adottare alcune misure per risolverlo.
Controlla se il servizio funziona localmente con l'ambiente
NAME
disponibile in uso:Esegui il container in locale 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
Vai all'indirizzo http://localhost:9000 nel browser.
Vedi "Hello Local World!" appaiono sulla pagina
Modifica l'ambiente di servizio Knative serving in esecuzione per includere questo elemento variabile:
Esegui il comando di aggiornamento dei servizi con il parametro
--update-env-vars
per aggiungi 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 basata su la revisione precedente con l'aggiunta della nuova variabile di ambiente.
Verifica che il servizio sia stato risolto:
- Vai nel browser all'URL del servizio Knative serving.
- Vedi "Hello Override!" vengono visualizzate nella pagina.
- Verifica che non vengano visualizzati messaggi o errori imprevisti in Cloud Logging.
Migliorare la velocità futura di risoluzione dei problemi
In questo problema di produzione di esempio, l'errore era correlato alle operazioni configurazione. Alcune modifiche al codice ridurranno al minimo l'impatto di questa problema in futuro.
- Migliora il log degli errori in modo da includere dettagli più specifici.
- Invece di restituire un errore, fai in modo che il servizio utilizzi un valore predefinito sicuro. Se l'utilizzo di un valore predefinito rappresenta un cambiamento alla funzionalità normale, utilizza un avviso a fini di monitoraggio.
Vediamo come rimuovere la variabile di ambiente NAME
come dipendenza rigida.
Rimuovi il codice di gestione
NAME
esistente:Node.js
Python
Vai
Java
Aggiungi un nuovo codice che imposti un valore di riserva:
Node.js
Python
Vai
Java
Esegui test in locale ricreando ed eseguendo il container tramite di configurazione:
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
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 alcun risultato, conferma la rimozione del codice nel nel primo passaggio non ha rimosso le righe aggiuntive, come quelle utilizzate per scrivere la risposta.
Per il deployment, consulta la sezione Deployment del codice.
Ogni deployment in un servizio crea una nuova revisione e avvia automaticamente per 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.
Individuazione di altri problemi nei log
Potresti visualizzare altri problemi nel visualizzatore log per questo servizio. Ad esempio, un la chiamata di sistema non supportata verrà visualizzata nei log come "Limitazione di Container Sandbox".
Ad esempio, i servizi Node.js a volte 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 costi.
Eliminazione delle risorse del tutorial in corso...
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 che hai 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 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, elimina il cluster.
- Elimina l'immagine container denominata
Passaggi successivi
- Scopri di più su come utilizzare Cloud Logging per ottenere insight sul comportamento di produzione.
- Per saperne di più sulla risoluzione dei problemi di Knative serving.
- Esplora le architetture di riferimento, i diagrammi e le best practice su Google Cloud. Dai un'occhiata al nostro Centro architetture cloud.