Introduzione ai container


Se non hai familiarità con i carichi di lavoro containerizzati, questo tutorial fa per te. Ti introduce ai container e all'orchestrazione dei container illustrandoti la configurazione di una semplice applicazione dal codice sorgente a un container in esecuzione su GKE.

Questo tutorial non richiede alcuna esperienza precedente con i container o Kubernetes. Tuttavia, se vuoi leggere una panoramica della terminologia di base di Kubernetes prima di iniziare questo tutorial, consulta Inizia a scoprire Kubernetes (o se preferisci scoprire Kubernetes in forma di fumetto, consulta il nostro fumetto su Kubernetes). Puoi trovare risorse più dettagliate nella sezione Passaggi successivi alla fine del tutorial.

Se conosci già i container e Kubernetes, puoi saltare questo tutorial e iniziare a conoscere GKE in sé.

Obiettivi

  1. Esplora una semplice applicazione "Hello World" multiservizio.
  2. Esegui l'applicazione dall'origine.
  3. Containerizza l'applicazione.
  4. Crea un cluster Kubernetes.
  5. Esegui il deployment dei container nel cluster.

Prima di iniziare

Per abilitare l'API Kubernetes Engine, segui questi passaggi:
  1. Visita la pagina di Kubernetes Engine nella console Google Cloud.
  2. Crea o seleziona un progetto.
  3. Attendi che l'API e i relativi servizi siano abilitati. L'operazione può richiedere diversi minuti.
  4. Make sure that billing is enabled for your Google Cloud project.

Prepara Cloud Shell

Questo tutorial utilizza Cloud Shell, che esegue il provisioning di una macchina virtuale (VM) Compute Engine g1-small che esegue un sistema operativo Linux basato su Debian.

L'utilizzo di Cloud Shell presenta i seguenti vantaggi:

  • Un ambiente di sviluppo Python 3 (incluso virtualenv) è completamente configurato.
  • Gli strumenti a riga di comando gcloud, docker, git e kubectl utilizzati in questo tutorial sono già installati.
  • Puoi scegliere tra gli editor di testo integrati:

    • Cloud Shell Editor, a cui puoi accedere facendo clic su Apri editor nella parte superiore della finestra di Cloud Shell.

    • Emacs, Vim o Nano, a cui accedi dalla riga di comando in Cloud Shell.

In the Google Cloud console, activate Cloud Shell.

Activate Cloud Shell

At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

Scarica il codice campione

  1. Scarica il codice sorgente di helloserver:

    git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-samples
    
  2. Passa alla directory codice campione:

    cd anthos-service-mesh-samples/docs/helloserver
    

Esplora l'applicazione multiservizio

L'applicazione di esempio è scritta in Python. È composto dai seguenti componenti che comunicano utilizzando REST:

  • server: un server di base con un endpoint GET, / , che stampa "hello world" nella finestra del terminale.
  • loadgen: uno script che invia traffico a server con un numero configurabile di richieste al secondo (RPS).

Applicazione di esempio

Esegui l'applicazione dall'origine

Per familiarizzare con l'applicazione di esempio, eseguila in Cloud Shell:

  1. Dalla directory sample-apps/helloserver, esegui server:

    python3 server/server.py
    

    All'avvio, server mostra quanto segue:

    INFO:root:Starting server...
    
  2. Apri un'altra finestra del terminale per poter inviare richieste al server. Per farlo in Cloud Shell, fai clic su Apri una nuova scheda per aprire un'altra sessione.

  3. Nella nuova finestra del terminale, invia una richiesta a server:

    curl http://localhost:8080
    

    L'output di server è il seguente:

    Hello World!
    
  4. Nella stessa scheda, passa alla directory che contiene lo script loadgen:

    cd anthos-service-mesh-samples/docs/helloserver/loadgen
  5. Crea le seguenti variabili di ambiente:

    export SERVER_ADDR=http://localhost:8080
    export REQUESTS_PER_SECOND=5
    
  6. Avvio virtualenv:

    virtualenv --python python3 env
    
  7. Attiva l'ambiente virtuale:

    source env/bin/activate
    
  8. Installa i requisiti per loadgen:

    pip3 install -r requirements.txt
    
  9. Esegui l'applicazione loadgen per generare traffico per server:

    python3 loadgen.py
    

    All'avvio, l'output di loadgen è simile al seguente:

    Starting loadgen: 2024-10-11 09:49:51.798028
    5 request(s) complete to http://localhost:8080
    
  10. Ora apri la finestra del terminale in cui è in esecuzione server. Dovresti vedere messaggi simili a quanto segue:

    127.0.0.1 - - [11/Oct/2024 09:51:28] "GET / HTTP/1.1" 200 -
    INFO:root:GET request,
    Path: /
    Headers:
    Host: localhost:8080
    User-Agent: python-requests/2.32.3
    Accept-Encoding: gzip, deflate
    Accept: */*
    Connection: keep-alive
    

    Dal punto di vista della rete, l'intera applicazione ora viene eseguita sullo stesso host, il che ti consente di utilizzare localhost per inviare richieste a server.

  11. Per interrompere loadgen e server, premi Ctrl-c in ogni finestra del terminale.

  12. Nella finestra del terminale loadgen, disattiva l'ambiente virtuale:

    deactivate
    

Containerizza l'applicazione

Per eseguire l'applicazione su GKE, devi pacchettizzare entrambi i componenti dell'applicazione di esempio in container. Un container è un pacchetto che contiene tutti gli elementi necessari per l'esecuzione della tua applicazione in qualsiasi ambiente. Questo tutorial utilizza Docker per containerizzare l'applicazione.

Per containerizzare l'applicazione con Docker, hai bisogno di un Dockerfile. Un Dockerfile è un file di testo che definisce i comandi necessari per assemblare il codice sorgente dell'applicazione e le sue dipendenze in un'immagine container. Dopo aver creato l'immagine, la carichi in un registry dei container, ad esempio Artifact Registry.

Il codice sorgente di questo tutorial include un Dockerfile sia per server che per loadgen con tutti i comandi necessari per creare le immagini. Di seguito è riportato il Dockerfile per il server:

FROM python:3.13-slim as base
FROM base as builder
RUN apt-get -qq update \
    && apt-get install -y --no-install-recommends \
        g++ \
    && rm -rf /var/lib/apt/lists/*

# Enable unbuffered logging
FROM base as final
ENV PYTHONUNBUFFERED=1

RUN apt-get -qq update \
    && apt-get install -y --no-install-recommends \
        wget

WORKDIR /helloserver

# Grab packages from builder
COPY --from=builder /usr/local/lib/python3.* /usr/local/lib/

# Add the application
COPY . .

EXPOSE 8080
ENTRYPOINT [ "python", "server.py" ]

In questo file puoi vedere quanto segue:

  • L'istruzione FROM python:3-slim as base indica a Docker di utilizzare l'ultima immagine di Python 3 come immagine di base.
  • L'istruzione COPY . . copia i file di origine dalla directory di lavoro corrente (in questo caso server.py) al file system del contenitore.
  • ENTRYPOINT definisce l'istruzione utilizzata per eseguire il container. In questo esempio, l'istruzione è simile a quella utilizzata per eseguire server.py dal codice sorgente.
  • L'istruzione EXPOSE specifica che server ascolta sulla porta 8080. Questa istruzione non espone alcuna porta, ma serve come documentazione per indicare che devi aprire la porta 8080 quando esegui il container.

Prepararsi a containerizzare l'applicazione

Prima di eseguire il containerizzazione dell'applicazione, devi eseguire alcune configurazioni per gli strumenti e i servizi che utilizzerai:

  1. Imposta il progetto Google Cloud predefinito per Google Cloud CLI.

    gcloud config set project PROJECT_ID
  2. Imposta la regione predefinita per Google Cloud CLI.

    gcloud config set compute/region us-central1
    

Crea il repository

Per creare un nuovo repository per le immagini container Docker in Artifact Registry, segui questi passaggi:

  1. Assicurati che il servizio Artifact Registry sia abilitato nel tuo progetto Google Cloud.

    gcloud services enable artifactregistry.googleapis.com
    
    
  2. Crea il repository Artifact Registry:

    gcloud artifacts repositories create container-intro --repository-format=docker \
        --location=us-central1 \
        --description="My new Docker repository" 
    
  3. Configura l'autenticazione da Docker ad Artifact Registry utilizzando Google Cloud CLI:

    gcloud auth configure-docker us-central1-docker.pkg.dev
    

Containerizza server

Ora è il momento di eseguire il containerizzazione dell'applicazione. Innanzitutto, esegui il containerizzazione del comando "hello world" server ed esegui il push dell'immagine in Artifact Registry:

  1. Passa alla directory in cui si trova il campione server:

    cd ~/anthos-service-mesh-samples/docs/helloserver/server/
  2. Crea l'immagine utilizzando Dockerfile:

    docker build -t us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1 .
    
    • Sostituisci PROJECT_ID con l'ID del tuo progetto Google Cloud.

    Il flag -t rappresenta il tag Docker. Si tratta del nome dell'immagine che utilizzi per il deployment del container.

  3. Esegui il push dell'immagine ad Artifact Registry:

    docker push us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1
    

Containerizza loadgen

Poi, esegui la containerizzazione del servizio di generatore di carico nello stesso modo:

  1. Passa alla directory in cui si trova il campione loadgen:

    cd ../loadgen
    
  2. Crea l'immagine:

    docker build -t us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1 .
    
  3. Esegui il push dell'immagine ad Artifact Registry:

    docker push us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1
    

Elenca le immagini

Visualizza un elenco delle immagini nel repository per verificare che siano state pushate:

gcloud container images list --repository us-central1-docker.pkg.dev/PROJECT_ID/container-intro

L'output dovrebbe elencare i nomi delle immagini che hai eseguito push, in modo simile al seguente:

NAME
us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver
us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen

Crea un cluster GKE

A questo punto puoi semplicemente eseguire i container sulla VM Cloud Shell utilizzando il comando docker run. Tuttavia, per eseguire carichi di lavoro di produzione affidabili, è necessario gestire i container in modo più unificato. Ad esempio, devi assicurarti che i contenitori si riavviino in caso di errore e devi avere un modo per eseguire il ridimensionamento e avviare istanze aggiuntive di un contenitore per gestire gli aumenti del traffico.

GKE può aiutarti a soddisfare queste esigenze. GKE è una piattaforma di orchestrazione dei container che funziona collegando le VM in un cluster. Ogni VM è indicata come nodo. I cluster GKE sono basati sul sistema open source di gestione dei cluster Kubernetes. Kubernetes fornisce i meccanismi che consentono di interagire con il cluster.

Per eseguire i contenitori su GKE, devi prima creare un cluster e poi connetterti:

  1. Crea il cluster:

    gcloud container clusters create-auto container-intro
    

    Il comando gcloud crea un cluster nel progetto e nella regione Google Cloud predefiniti che hai impostato in precedenza.

    Il completamento del comando per la creazione del cluster richiede alcuni minuti. Quando il cluster è pronto, l'output è simile al seguente:

     NAME: container-intro
     LOCATION: us-central1
     MASTER_VERSION: 1.30.4-gke.1348000
     MASTER_IP: 34.44.14.166
     MACHINE_TYPE: e2-small
     NODE_VERSION: 1.30.4-gke.1348000
     NUM_NODES: 3
     STATUS: RUNNING
    
  2. Fornisci le credenziali allo strumento a riga di comando kubectl in modo da poterlo utilizzare per gestire il cluster:

    gcloud container clusters get-credentials container-intro
    

Esamina i manifest di Kubernetes

Quando hai eseguito l'applicazione dal codice sorgente, hai utilizzato un comando imperativo: python3 server.py

Il linguaggio imperativo è basato sui verbi: "fai questo".

Al contrario, Kubernetes si basa su un modello declarativo. Ciò significa che, anziché dire a Kubernetes esattamente cosa fare, fornisci a Kubernetes uno stato desiderato. Ad esempio, Kubernetes avvia e termina gli pod in base alle necessità in modo che lo stato effettivo del sistema corrisponda a quello desiderato.

Lo stato desiderato viene specificato in un file chiamato manifest. I manifest sono scritti in linguaggi come YAML o JSON e contengono la specifica di uno o più oggetti Kubernetes.

Il sample contiene un manifest per server e loadgen. Ogni manifesto specifica lo stato desiderato per l'oggetto Kubernetes Deployment (che gestisce l'esecuzione del container, pacchettizzato per la gestione come pod Kubernetes) e per il servizio (che fornisce un indirizzo IP per il pod). Un pod è l'unità di calcolo di cui è possibile eseguire il deployment più piccola che puoi creare e gestire in Kubernetes e contiene uno o più container.

Il seguente diagramma mostra l'applicazione in esecuzione su GKE:

Applicazione containerizzata in esecuzione su GKE

Per scoprire di più su pod, deployment e servizi, consulta Inizia a imparare su Kubernetes o consulta le risorse alla fine di questa pagina.

Server

Innanzitutto, esamina il manifest di "hello world" server:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloserver
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helloserver
  template:
    metadata:
      labels:
        app: helloserver
    spec:
      containers:
      - image: gcr.io/google-samples/istio/helloserver:v0.0.1
        imagePullPolicy: Always
        name: main
      restartPolicy: Always
      terminationGracePeriodSeconds: 5

Questo manifest contiene i seguenti campi:

  • kind indica il tipo di oggetto.
  • metadata.name specifica il nome del deployment.
  • Il primo campo spec contiene una descrizione dello stato desiderato.
  • spec.replicas specifica il numero di pod desiderati.
  • La sezione spec.template definisce un modello di pod. Nella specifica per i pod è incluso il campo image, che corrisponde al nome dell'immagine da estrarre da Artifact Registry. Nel passaggio successivo, aggiornerai questo valore con la nuova immagine che hai appena creato.

Il servizio hellosvc è definito come segue:

apiVersion: v1
kind: Service
metadata:
  name: hellosvc
spec:
  ports:
  - name: http
    port: 80
    targetPort: 8080
  selector:
    app: helloserver
  type: LoadBalancer
  • LoadBalancer: i client inviano richieste all'indirizzo IP di un bilanciatore del carico di rete, che ha un indirizzo IP stabile ed è raggiungibile dall'esterno del cluster.
  • targetPort: ricorda che il comando EXPOSE 8080 in Dockerfile non espone effettivamente alcuna porta. Esponi la porta 8080 in modo da poter raggiungere il contenitore server all'esterno del cluster. In questo caso, hellosvc.default.cluster.local:80 (nome breve: hellosvc) si mappa alla porta 8080 dell'IP del pod helloserver.
  • port: si tratta del numero di porta utilizzato dagli altri servizi del cluster per inviare richieste.

Generatore di carico

L'oggetto Deployment in loadgen.yaml è simile a server.yaml. Una differenza significativa è che la specifica del pod per il deployment loadgen ha un campo denominato env. Questa sezione definisce le variabili di ambiente richieste da loadgen, che hai impostato in precedenza quando hai eseguito l'applicazione dal codice sorgente.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: loadgenerator
spec:
  replicas: 1
  selector:
    matchLabels:
      app: loadgenerator
  template:
    metadata:
      labels:
        app: loadgenerator
    spec:
      containers:
      - env:
        - name: SERVER_ADDR
          value: http://hellosvc:80/
        - name: REQUESTS_PER_SECOND
          value: '10'
        image: gcr.io/google-samples/istio/loadgen:v0.0.1
        imagePullPolicy: Always
        name: main
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
          requests:
            cpu: 300m
            memory: 256Mi
      restartPolicy: Always
      terminationGracePeriodSeconds: 5

Poiché loadgen non accetta richieste in arrivo, il campo type è impostato su ClusterIP. Questo tipo di servizio fornisce un indirizzo IP stabile che può essere utilizzato dalle entità nel cluster, ma l'indirizzo IP non è esposto ai client esterni.

apiVersion: v1
kind: Service
metadata:
  name: loadgensvc
spec:
  ports:
  - name: http
    port: 80
    targetPort: 8080
  selector:
    app: loadgenerator
  type: ClusterIP

Esegui il deployment dei container in GKE

Per eseguire il deployment dei container, applica i manifest che specificano lo stato desiderato utilizzando kubectl.

Esegui il deployment di server

  1. Passa alla directory in cui si trova il campione server:

    cd ~/anthos-service-mesh-samples/docs/helloserver/server/
  2. Apri server.yaml nell'editor di Cloud Shell (o nell'editor di testo che preferisci).

  3. Sostituisci il nome nel campo image con il nome dell'immagine Docker.

    image: us-central1-docker.pkg.dev/PROJECT_ID/container-intro/helloserver:v0.0.1
    

    Sostituisci PROJECT_ID con l'ID del tuo progetto Google Cloud.

    • Se utilizzi Cloud Shell Editor, il file viene salvato automaticamente. Torna alla finestra del terminale facendo clic su Apri terminale.
    • Se utilizzi un editor di testo in Cloud Shell, salva e chiudi server.yaml.
  4. Esegui il deployment del manifest in Kubernetes:

    kubectl apply -f server.yaml
    

    L'output è simile al seguente:

    deployment.apps/helloserver created
    service/hellosvc created
    

Esegui il deployment di loadgen

  1. Passa alla directory in cui si trova loadgen.

    cd ../loadgen
    
  2. Apri loadgen.yaml in un editor di testo, come prima.

  3. Sostituisci di nuovo il nome nel campo image con il nome dell'immagine Docker.

    image: us-central1-docker.pkg.dev/PROJECT_ID/container-intro/loadgen:v0.0.1
    

    Sostituisci PROJECT_ID con l'ID del tuo progetto Google Cloud.

    • Se utilizzi Cloud Shell Editor, il file viene salvato automaticamente. Torna alla finestra del terminale facendo clic su Apri terminale.
    • Se utilizzi un editor di testo in Cloud Shell, salva e chiudi loadgen.yaml.
  4. Esegui il deployment del manifest nel cluster:

    kubectl apply -f loadgen.yaml
    

    In caso di esito positivo, il comando risponde con quanto segue:

    deployment.apps/loadgenerator created
    service/loadgensvc created
    

Verifica il deployment

Dopo aver eseguito il deployment dei manifest nel cluster, verifica che i container siano stati implementati correttamente:

  1. Controlla lo stato dei pod nel tuo cluster:

    kubectl get pods
    

    Il comando risponde con lo stato simile al seguente:

    NAME                             READY   STATUS    RESTARTS   AGE
    helloserver-69b9576d96-mwtcj     1/1     Running   0          58s
    loadgenerator-774dbc46fb-gpbrz   1/1     Running   0          57s
    
  2. Recupera i log dell'applicazione dal pod loadgen. Sostituisci POD_ID con l'identificatore del pod del generatore di carico dall'output precedente.

    kubectl logs POD_ID
    
  3. Ottieni gli indirizzi IP esterni di hellosvc:

    kubectl get service hellosvc
    

    L'output è simile al seguente:

    NAME         TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
    hellosvc     LoadBalancer   10.81.15.158   192.0.2.1       80:31127/TCP   33m
    
  4. Invia una richiesta al hellosvc. Sostituisci EXTERNAL_IP con l'indirizzo IP esterno del tuo hellosvc.

    curl http://EXTERNAL_IP
    

    Dovresti vedere il messaggio "Hello World!" dal server.

Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.

Se non vuoi eliminare l'intero progetto:

  • Elimina il cluster GKE. L'eliminazione del cluster comporta l'eliminazione di tutte le risorse che lo compongono, ad esempio le istanze, i dischi e le risorse di rete di Compute Engine.

     gcloud container clusters delete container-intro
    
  • Elimina il repository Artifact Registry:

     gcloud artifacts repositories delete container-intro --location=us-central1
    

Passaggi successivi