Esegui il deployment di un'app in un'immagine container su un cluster GKE


Questa pagina mostra come:

  1. Crea un'app Hello World.
  2. Creare un pacchetto con l'app in un'immagine container utilizzando Cloud Build.
  3. Crea un cluster in Google Kubernetes Engine (GKE).
  4. Eseguire il deployment dell'immagine container nel cluster.

L'esempio è disponibile in diverse lingue, ma puoi utilizzare altre lingue oltre a quelle mostrate.


Per seguire le indicazioni dettagliate per questa attività direttamente nell'editor di Cloud Shell, fai clic su Aiuto:

Guidami


Prima di iniziare

  1. Accedi al tuo account Google Cloud. Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti gratuiti per l'esecuzione, il test e il deployment dei carichi di lavoro.
  2. Nella pagina del selettore di progetti della console Google Cloud, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  3. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.

  4. Abilita le API Artifact Registry, Cloud Build, and Google Kubernetes Engine.

    Abilita le API

  5. Installa Google Cloud CLI.
  6. Per initialize gcloud CLI, esegui questo comando:

    gcloud init
  7. Nella pagina del selettore di progetti della console Google Cloud, seleziona o crea un progetto Google Cloud.

    Vai al selettore progetti

  8. Assicurati che la fatturazione sia attivata per il tuo progetto Google Cloud.

  9. Abilita le API Artifact Registry, Cloud Build, and Google Kubernetes Engine.

    Abilita le API

  10. Installa Google Cloud CLI.
  11. Per initialize gcloud CLI, esegui questo comando:

    gcloud init
  12. kubectl viene utilizzato per gestire Kubernetes, il sistema di orchestrazione dei cluster utilizzato da GKE. Puoi installare kubectl utilizzando gcloud:
    gcloud components install kubectl

Scrittura dell'app di esempio

Per istruzioni sulla creazione di un'app Hello World eseguita su GKE, fai clic sulla tua lingua:

Go

  1. Crea una nuova directory denominata helloworld-gke e modifica la directory al suo interno:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crea un nuovo modulo denominato example.com/helloworld:

    go mod init example.com/helloworld
    
  3. Crea un nuovo file denominato helloworld.go e incolla il seguente codice al suo interno:

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"os"
    )
    
    func main() {
    	http.HandleFunc("/", handler)
    
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    	}
    
    	log.Printf("Listening on localhost:%s", port)
    	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
    }
    
    func handler(w http.ResponseWriter, r *http.Request) {
    	log.Print("Hello world received a request.")
    	target := os.Getenv("TARGET")
    	if target == "" {
    		target = "World"
    	}
    	fmt.Fprintf(w, "Hello %s!\n", target)
    }
    

    Questo codice crea un server web in ascolto sulla porta definita dalla variabile di ambiente PORT.

La tua app è completa e pronta per essere pacchettizzata in un container Docker, poi caricata su Artifact Registry.

Node.js

  1. Crea una nuova directory denominata helloworld-gke e passa a questa directory:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crea un file package.json con il seguente contenuto:

    {
      "name": "gke-helloworld",
      "version": "1.0.0",
      "description": "GKE hello world sample in Node",
      "main": "index.js",
      "scripts": {
        "start": "node index.js"
      },
      "author": "",
      "license": "Apache-2.0",
      "dependencies": {
        "express": "^4.16.4"
      }
    }
    
  3. Nella stessa directory, crea un file index.js e copia le seguenti righe in questo file:

    const express = require('express');
    const app = express();
    
    app.get('/', (req, res) => {
      console.log('Hello world received a request.');
    
      const target = process.env.TARGET || 'World';
      res.send(`Hello ${target}!`);
    });
    
    const port = process.env.PORT || 8080;
    app.listen(port, () => {
      console.log('Hello world listening on port', port);
    });

    Questo codice crea un server web in ascolto sulla porta definita dalla variabile di ambiente PORT.

La tua app è completa e pronta per essere pacchettizzata in un container Docker e caricata su Artifact Registry.

Python

  1. Crea una nuova directory denominata helloworld-gke e passa a questa directory:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crea un file denominato app.py e incolla il codice seguente in questo file:

    import os
    
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        target = os.environ.get('TARGET', 'World')
        return 'Hello {}!\n'.format(target)
    
    if __name__ == "__main__":
        app.run(debug=True,host='0.0.0.0',port=int(os.environ.get('PORT', 8080)))

Java

Creare un'app Spring Boot.

  1. Installa Java SE 8 o versione successiva JDK e cURL. Java SE e cURL sono necessari solo per creare il nuovo progetto web nel passaggio successivo. Il Dockerfile, descritto in seguito, carica tutte le dipendenze nel container.

  2. Dal terminale, crea un nuovo progetto web vuoto:

    curl https://start.spring.io/starter.zip \
        -d dependencies=web \
        -d javaVersion=1.8 \
        -d type=maven-project \
        -d bootVersion=2.6.6 \
        -d name=helloworld \
        -d artifactId=helloworld \
        -d baseDir=helloworld-gke \
        -o helloworld-gke.zip
    unzip helloworld-gke.zip
    cd helloworld-gke
    

    Ora hai un nuovo progetto Spring Boot in helloworld-gke.

  3. Nel file src/main/java/com/example/helloworld/HelloworldApplication.java, aggiorna la classe HelloworldApplication aggiungendo @RestController per gestire il mapping /.

    package com.example.helloworld;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    public class HelloworldApplication {
    
    	@Value("${TARGET:World}")
    	String target;
    
    	@RestController
    	class HelloworldController {
    		@GetMapping("/")
    		String hello() {
    			return "Hello " + target + "!";
    		}
    	}
    
    	public static void main(String[] args) {
    		SpringApplication.run(HelloworldApplication.class, args);
    	}
    }

    Questo codice crea un server web in ascolto sulla porta definita dalla variabile di ambiente PORT.

La tua app è completa e pronta per essere pacchettizzata in un container Docker, poi caricata su Artifact Registry.

C#

  1. Installa l'SDK.NET. L'SDK .NET è necessario solo per creare il nuovo progetto web nel passaggio successivo. L'elemento Dockerfile, descritto in seguito, carica tutte le dipendenze nel container.

  2. Dal terminale, crea un nuovo progetto web vuoto:

    dotnet new web -o helloworld-gke
    
  3. Cambia la directory in helloworld-gke.

    cd helloworld-gke
    
  4. Aggiorna Program.cs per l'ascolto sulla porta 8080:

    var builder = WebApplication.CreateBuilder(args);
    
    // Google Cloud Run sets the PORT environment variable to tell this
    // process which port to listen to.
    var port = Environment.GetEnvironmentVariable("PORT") ?? "8080";
    var url = $"http://0.0.0.0:{port}";
    var target = Environment.GetEnvironmentVariable("TARGET") ?? "World";
    
    var app = builder.Build();
    
    app.MapGet("/", () => $"Hello {target}!");
    
    app.Run(url);

La tua app è completa e pronta per essere pacchettizzata in un container Docker, poi caricata su Artifact Registry.

PHP

  1. Crea una nuova directory denominata helloworld-gke e passa a questa directory:

    mkdir helloworld-gke
    cd helloworld-gke
    
  2. Crea un file denominato index.php e incolla il codice seguente in questo file:

    <?php
    $target = getenv('TARGET', true) ?: 'World';
    echo sprintf("Hello %s!", $target);
    ?>

La tua app è completa e pronta per essere pacchettizzata in un container Docker, poi caricata su Artifact Registry.

Containerizzazione di un'app con Cloud Build

  1. Per containerizzare l'app di esempio, crea un nuovo file denominato Dockerfile nella stessa directory dei file di origine e copia il contenuto seguente:

    Go

    # Use the offical Go image to create a build artifact.
    # This is based on Debian and sets the GOPATH to /go.
    # https://hub.docker.com/_/golang
    FROM golang:1.22.0 as builder
    WORKDIR /app
    
    # Initialize a new Go module.
    RUN go mod init quickstart-go
    
    # Copy local code to the container image.
    COPY *.go ./
    
    # Build the command inside the container.
    RUN CGO_ENABLED=0 GOOS=linux go build -o /quickstart-go
    
    # Use a Docker multi-stage build to create a lean production image.
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM gcr.io/distroless/base-debian11
    
    # Change the working directory.
    WORKDIR /
    
    # Copy the binary to the production image from the builder stage.
    COPY --from=builder /quickstart-go /quickstart-go
    
    # Run the web service on container startup.
    USER nonroot:nonroot
    ENTRYPOINT ["/quickstart-go"]

    Node.js

    # Use the official lightweight Node.js 16 image.
    # https://hub.docker.com/_/node
    FROM node:21-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 both package.json AND package-lock.json are copied.
    # Copying this separately prevents re-running npm install on every code change.
    COPY package*.json ./
    
    # Install production dependencies.
    RUN npm install --omit=dev
    
    # Copy local code to the container image.
    COPY . ./
    
    # Run the web service on container startup.
    CMD [ "npm", "start" ]

    Aggiungi un altro file .dockerignore per assicurarti che i file locali non influiscano sul processo di compilazione del container:

    Dockerfile
    README.md
    node_modules
    npm-debug.log
    

    Python

    # Use the official lightweight Python image.
    # https://hub.docker.com/_/python
    FROM python:3.12-slim
    
    # Copy local code to the container image.
    ENV APP_HOME /app
    WORKDIR $APP_HOME
    COPY . ./
    
    # Install production dependencies.
    RUN pip install Flask gunicorn
    
    # Run the web service on container startup. Here we use the 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.
    CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app

    Aggiungi un file .dockerignore per assicurarti che i file locali non influiscano sul processo di compilazione del container:

    Dockerfile
    README.md
    *.pyc
    *.pyo
    *.pyd
    __pycache__
    

    Java

    # Use the official maven/Java 8 image to create a build artifact.
    # https://hub.docker.com/_/maven
    FROM maven:3.5-jdk-8-alpine as builder
    
    # Copy local code to the container image.
    WORKDIR /app
    COPY pom.xml ./
    COPY src ./src/
    
    # Build a release artifact.
    RUN mvn package -DskipTests
    
    # Use AdoptOpenJDK for base image.
    # It's important to use OpenJDK 8u191 or above that has container support enabled.
    # https://hub.docker.com/r/adoptopenjdk/openjdk8
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM adoptopenjdk/openjdk8:jdk8u202-b08-alpine-slim
    
    # Copy the jar to the production image from the builder stage.
    COPY --from=builder /app/target/helloworld-*.jar /helloworld.jar
    
    # Run the web service on container startup.
    CMD ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/helloworld.jar"]

    C#

    # Use Microsoft's official lightweight .NET images.
    FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
    WORKDIR /app
    
    # Install production dependencies.
    # Copy csproj and restore as distinct layers.
    COPY *.csproj ./
    RUN dotnet restore
    
    # Copy local code to the container image.
    COPY . ./
    
    # Build a release artifact.
    RUN dotnet publish -c Release -o out
    
    # Run the web service on container startup in a lean production image.
    FROM mcr.microsoft.com/dotnet/aspnet:6.0
    WORKDIR /app
    COPY --from=build /app/out .
    
    # Start the .dll (will have the same name as your .csproj file)
    ENTRYPOINT ["dotnet", "helloworld-gke.dll"]

    Aggiungi un file .dockerignore per assicurarti che i file locali non influiscano sul processo di compilazione del container:

    Dockerfile
    README.md
    **/obj/
    **/bin/
    

    PHP

    # Use the official PHP 7.4 image.
    # https://hub.docker.com/_/php
    FROM php:8.2-apache
    
    # Copy local code to the container image.
    COPY index.php /var/www/html/
    
    # Use port 8080 in Apache configuration files.
    RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
    
    # Configure PHP for development.
    # Switch to the production php.ini for production operations.
    # RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
    # https://hub.docker.com/_/php#configuration
    RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

    Aggiungi un file .dockerignore per assicurarti che i file locali non influiscano sul processo di compilazione del container:

    Dockerfile
    README.md
    vendor
    
  2. Recupera il tuo ID progetto Google Cloud:

    gcloud config get-value project
    
  3. In questa guida rapida, archivierai il container in Artifact Registry e ne eseguirai il deployment nel tuo cluster dal registry. Esegui questo comando per creare un repository denominato hello-repo nella stessa località del cluster:

    gcloud artifacts repositories create hello-repo \
        --project=PROJECT_ID \
        --repository-format=docker \
        --location=us-central1 \
        --description="Docker repository"
    

    Sostituisci i seguenti valori:

    • PROJECT_ID è l'ID del tuo progetto Google Cloud
  4. Crea la tua immagine container utilizzando Cloud Build, che è simile all'esecuzione di docker build e docker push, ma la build avviene su Google Cloud:

    gcloud builds submit \
      --tag us-central1-docker.pkg.dev/PROJECT_ID/hello-repo/helloworld-gke .
    

    L'immagine è archiviata in Artifact Registry.

Crea un cluster GKE

Un cluster GKE è un insieme gestito di macchine virtuali di Compute Engine che operano come un singolo cluster GKE.

  1. Crea il cluster.

    gcloud container clusters create-auto helloworld-gke \
      --location us-central1
    
  2. Verifica di avere accesso al cluster. Il seguente comando elenca i nodi nel tuo cluster di container che sono in esecuzione e indica che hai accesso al cluster.

    kubectl get nodes
    

    Se riscontri errori, consulta la guida alla risoluzione dei problemi di Kubernetes.

Deployment in GKE

Per eseguire il deployment dell'app nel cluster GKE che hai creato, devi avere due oggetti Kubernetes.

  1. Un Deployment per definire l'app.
  2. Un Servizio per definire la modalità di accesso all'app.

Eseguire il deployment di un'app

L'app ha un server frontend che gestisce le richieste web. Puoi definire le risorse cluster necessarie per eseguire il frontend in un nuovo file denominato deployment.yaml. Queste risorse sono descritte come un deployment. Puoi utilizzare i deployment per creare e aggiornare una ReplicaSet e i pod associati.

  1. Crea il file deployment.yaml nella stessa directory degli altri file e copia i seguenti contenuti. Sostituisci i seguenti valori nel file:

    • $GCLOUD_PROJECT è l'ID progetto Google Cloud:
    • $LOCATION è la località del repository, ad esempio us-central1.
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: helloworld-gke
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: hello
      template:
        metadata:
          labels:
            app: hello
        spec:
          containers:
          - name: hello-app
            # Replace $LOCATION with your Artifact Registry location (e.g., us-west1).
            # Replace $GCLOUD_PROJECT with your project ID.
            image: $LOCATION-docker.pkg.dev/$GCLOUD_PROJECT/hello-repo/helloworld-gke:latest
            # This app listens on port 8080 for web traffic by default.
            ports:
            - containerPort: 8080
            env:
              - name: PORT
                value: "8080"
            resources:
              requests:
                memory: "1Gi"
                cpu: "500m"
                ephemeral-storage: "1Gi"
              limits:
                memory: "1Gi"
                cpu: "500m"
                ephemeral-storage: "1Gi"
  2. Esegui il deployment della risorsa nel cluster:

    kubectl apply -f deployment.yaml
    
  3. Monitora lo stato delldeployment:

    kubectl get deployments
    

    Il deployment è completo quando tutti i deployment AVAILABLE sono READY.

    NAME              READY   UP-TO-DATE   AVAILABLE   AGE
    helloworld-gke    1/1     1            1           20s
    

    Se il deployment presenta un errore, esegui di nuovo kubectl apply -f deployment.yaml per aggiornarlo con eventuali modifiche.

  4. Una volta completato il deployment, puoi vedere i pod creati dal deployment:

    kubectl get pods
    

Esegui il deployment di un servizio

I servizi forniscono un singolo punto di accesso a un insieme di pod. Sebbene sia possibile accedere a un singolo pod, i pod sono temporanei e sono accessibili in modo affidabile solo tramite un indirizzo di servizio. Nell'app Hello World, il servizio "hello" definisce un bilanciatore del carico per accedere ai pod hello-app da un singolo indirizzo IP. Questo servizio è definito nel file service.yaml.

  1. Crea il file service.yaml nella stessa directory degli altri file di origine con i seguenti contenuti:

    # The hello service provides a load-balancing proxy over the hello-app
    # pods. By specifying the type as a 'LoadBalancer', Kubernetes Engine will
    # create an external HTTP load balancer.
    apiVersion: v1
    kind: Service
    metadata:
      name: hello
    spec:
      type: LoadBalancer
      selector:
        app: hello
      ports:
      - port: 80
        targetPort: 8080

    I pod vengono definiti separatamente dal servizio che li utilizza. Kubernetes utilizza le etichette per selezionare i pod che un servizio gestisce. Con le etichette puoi avere un servizio che si rivolge ai pod di diversi set di repliche e avere più servizi che puntano a un singolo pod.

  2. Crea il servizio Hello World:

    kubectl apply -f service.yaml
    
  3. Recupera l'indirizzo IP esterno del servizio:

    kubectl get services
    

    L'allocazione dell'indirizzo IP può richiedere fino a 60 secondi. L'indirizzo IP esterno è riportato nella colonna EXTERNAL-IP per il servizio hello.

    NAME         TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
    hello        LoadBalancer   10.22.222.222   35.111.111.11   80:32341/TCP   1m
    kubernetes   ClusterIP      10.22.222.1     <none>          443/TCP        20m
    

Visualizzare un'app di cui è stato eseguito il deployment

Hai eseguito il deployment di tutte le risorse necessarie per eseguire l'app Hello World su GKE.

Utilizza l'indirizzo IP esterno del passaggio precedente per caricare l'app nel browser web e vedere l'app in esecuzione:

 http://EXTERNAL_IP

In alternativa, puoi effettuare una chiamata curl all'indirizzo IP esterno del servizio:

curl EXTERNAL_IP

L'output mostra quanto segue:

Hello World!

Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questa pagina, segui questi passaggi:

Ti vengono addebitati i costi per le istanze di Compute Engine in esecuzione nel cluster, nonché per l'immagine container in Artifact Registry.

Elimina il progetto

L'eliminazione del tuo progetto Google Cloud interrompe la fatturazione per tutte le risorse utilizzate all'interno di quel progetto.

  1. Nella console Google Cloud, vai alla pagina Gestisci risorse.

    Vai a Gestisci risorse

  2. Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
  3. Nella finestra di dialogo, digita l'ID del progetto e fai clic su Chiudi per eliminare il progetto.

Elimina cluster e container

Se vuoi conservare il progetto, ma eliminare solo le risorse utilizzate in questo tutorial, elimina il cluster e l'immagine.

Per eliminare un cluster utilizzando Google Cloud CLI, esegui questo comando per la modalità utilizzata:

gcloud container clusters delete helloworld-gke \
    --location us-central1

Per eliminare un'immagine nel repository Artifact Registry, esegui questo comando:

gcloud artifacts docker images delete \
    us-central1-docker.pkg.dev/PROJECT_ID/hello-repo/helloworld-gke

Passaggi successivi

Per maggiori informazioni su Kubernetes, consulta:

Per maggiori informazioni sul deployment in GKE, consulta:

Per ulteriori informazioni sulla creazione, lo sviluppo e l'esecuzione di applicazioni su GKE direttamente dal tuo IDE con Cloud Code, consulta quanto segue: