Esegui la migrazione da Go 1.11 all'ultima versione del runtime Go

Questa pagina fornisce istruzioni per la migrazione dai runtime Go di prima alla seconda generazione. Per eseguire l'upgrade dell'app di seconda generazione in modo che utilizzi l'ultima versione supportata di Go, vedi Eseguire l'upgrade di un'applicazione esistente.

Go 1.11 ha raggiunto la fine del supporto il 30 gennaio 2024. Le applicazioni Go 1.11 esistenti continueranno a essere eseguite e a ricevere traffico. Tuttavia, App Engine potrebbe bloccare il redeployment delle applicazioni che utilizzano runtime dopo la data di fine del supporto. Ti consigliamo di eseguire la migrazione all'ultimo runtime supportato di Go seguendo le linee guida riportate in questa pagina.

La migrazione a un runtime Go di seconda generazione supportato ti consente di utilizzare funzionalità del linguaggio aggiornate e creare app più portatili, con codice idiomatico.

Modifiche ai runtime di seconda generazione

Quando esegui l'upgrade a un runtime Go di seconda generazione supportato, tieni presente le seguenti differenze:

  • Per ridurre lo sforzo e la complessità della migrazione del runtime, l'ambiente standard App Engine ti consente di accedere a molti dei servizi e delle API in bundle legacy nei runtime di seconda generazione, come Memcache. L'app Go di seconda generazione può chiamare le API dei servizi in bundle tramite l'SDK App Engine per Go e accedere alla maggior parte delle stesse funzionalità dell'ambiente di runtime Go 1.11.

    Hai anche la possibilità di utilizzare i prodotti Google Cloud che offrono funzionalità simili a quelle dei servizi in bundle legacy. Questi Google Cloud prodotti forniscono librerie client Cloud per Go idiomatiche. Per i servizi in bundle non disponibili come prodotti separati in Google Cloud, come l'elaborazione delle immagini, la ricerca e la messaggistica, puoi utilizzare provider di terze parti o altre soluzioni alternative.

    Per saperne di più sulla migrazione ai servizi separati, consulta la pagina Eseguire la migrazione dai servizi in bundle.

  • Il comportamento di alcuni elementi nel file di configurazione app.yaml è stato modificato. Per ulteriori informazioni, vedi Modifiche al file app.yaml.

  • La registrazione nel runtime di seconda generazione segue lo standard di logging in Cloud Logging. Nei runtime di seconda generazione, i log delle app non sono più raggruppati con i log delle richieste, ma sono separati in record diversi. Per scoprire di più sulla lettura e la scrittura dei log nei runtime di seconda generazione, consulta la guida alla registrazione.

Differenze nell'utilizzo della memoria

I runtime di seconda generazione hanno una base di utilizzo della memoria più elevata rispetto ai runtime di prima generazione. Ciò è dovuto a diversi fattori, ad esempio versioni diverse dell'immagine di base e differenze nel modo in cui le due generazioni calcolano l'utilizzo della memoria.

I runtime di seconda generazione calcolano l'utilizzo della memoria dell'istanza come somma di ciò che utilizza un processo dell'applicazione e del numero di file dell'applicazione memorizzati dinamicamente nella cache in memoria. Per evitare che le applicazioni che utilizzano molta memoria subiscano arresti anomali delle istanze a causa del superamento dei limiti di memoria, esegui l'upgrade a una classe di istanze più grande con più memoria.

Differenze di utilizzo della CPU

I runtime di seconda generazione possono registrare una baseline più elevata di utilizzo della CPU all'avvio a freddo dell'istanza. A seconda della configurazione di scalabilità di un'applicazione, ciò potrebbe avere effetti collaterali indesiderati, ad esempio un numero di istanze superiore al previsto se un'applicazione è configurata per la scalabilità in base all'utilizzo della CPU. Per evitare questo problema, rivedi e testa le configurazioni di scalabilità dell'applicazione per assicurarti che il numero di istanze sia accettabile.

Differenze tra le intestazioni delle richieste

I runtime di prima generazione consentono di inoltrare all'applicazione le intestazioni delle richieste con trattini bassi (ad es. X-Test-Foo_bar). I runtime di seconda generazione introducono Nginx nell'architettura host. A seguito di questa modifica, i runtime di seconda generazione sono configurati per rimuovere automaticamente le intestazioni con trattini bassi (_). Per evitare problemi con l'applicazione, evita di utilizzare trattini bassi nelle intestazioni delle richieste dell'applicazione.

Modifiche al file app.yaml

Il comportamento di alcuni elementi nel file di configurazione app.yaml è stato modificato:

Elemento Tipo di modifica Descrizione
app_engine_apis Obbligatorio per le app che utilizzano servizi in bundle legacy Deve essere impostato su true se vuoi accedere ai servizi in bundle legacy per i runtime di seconda generazione.
login Supportato se app_engine_apis è true Se non utilizzi i servizi in bundle legacy per i runtime di seconda generazione, utilizza questi metodi alternativi per autenticare gli utenti.
runtime Modificato Modifica l'elemento runtime per specificare un runtime di seconda generazione.

Per ulteriori informazioni, consulta il riferimento app.yaml.

Crea un pacchetto main

Il tuo servizio deve includere una dichiarazione package main in almeno un file di origine.

Servizi integrati legacy di App Engine

Se il tuo servizio utilizza i servizi in bundle legacy per i runtime di seconda generazione:

  • Il tuo servizio deve utilizzare solo pacchetti v2 (google.golang.org/appengine/v2). L'utilizzo dei pacchetti v1 (google.golang.org/appengine) precedenti causa errori.

  • Nella funzione main(), chiama appengine.Main() anziché http.ListenAndServe(). In questo modo, le API user e appengine hanno accesso al contesto della richiesta corrente.

Scrivere un pacchetto principale

Se il tuo servizio non contiene già un pacchetto main, aggiungi l'istruzione package main e scrivi una funzione main(). Come minimo, la funzione main() deve:

  • Leggi la variabile di ambiente PORT e chiama la funzione http.ListenAndServe():

    port := os.Getenv("PORT")
    if port == "" {
    	port = "8080"
    	log.Printf("Defaulting to port %s", port)
    }
    
    log.Printf("Listening on port %s", port)
    if err := http.ListenAndServe(":"+port, nil); err != nil {
    	log.Fatal(err)
    }

Registrazione dei gestori HTTP

Puoi registrare i gestori HTTP scegliendo una delle seguenti opzioni:

  • Il metodo preferito è spostare manualmente tutte le chiamate http.HandleFunc() dai pacchetti alla funzione main() nel pacchetto main.
  • In alternativa, importa i pacchetti dell'applicazione nel pacchetto main, assicurandoti che ogni funzione init() che contiene chiamate a http.HandleFunc() venga eseguita all'avvio.

    Puoi trovare tutti i pacchetti che utilizzano la chiamata http.HandleFunc() con il seguente script bash e copiare l'output nel blocco import del pacchetto main:

    gp=$(go env GOPATH) && p=$(pwd) && pkg=${p#"$gp/src/"} && find . -name "*.go" | xargs grep "http.HandleFunc" --files-with-matches | grep -v vendor/ | grep -v '/main.go' | sed "s#\./\(.*\)/[^/]\+\.go#\t_ \"$pkg/\1\"#" | sort | uniq
    

Strutturare i file

Go richiede che ogni pacchetto abbia la propria directory. Puoi indicare ad App Engine dove si trova il pacchetto main utilizzando main: nel file app.yaml del progetto. Ad esempio, se la struttura dei file della tua app è la seguente:

myapp/
├── app.yaml
├── foo.go
├── bar.go
└── web/
    └── main.go

Il tuo file app.yaml avrebbe:

main: ./web # Relative filepath to the directory containing your main package.

Per saperne di più sul flag main, consulta il app.yaml riferimento.

Spostamento dei file in GOPATH in corso…

Trova il tuo GOPATH utilizzando il seguente comando:

go env GOPATH

Sposta tutti i file e le importazioni pertinenti nel tuo GOPATH. Se utilizzi importazioni relative, ad esempio import ./guestbook, aggiorna le importazioni in modo che utilizzino il percorso completo: import github.com/example/myapp/guestbook.