prepara un'applicazione per Cloud Service Mesh


Cloud Service Mesh è un potente strumento per la gestione e il monitoraggio delle applicazioni distribuite. Per ottenere il massimo da Cloud Service Mesh, è utile comprendere le sue astrazioni sottostanti, inclusi i container e Kubernetes. Questo tutorial spiega come preparare un'applicazione per Cloud Service Mesh dal codice sorgente a un contenitore in esecuzione su GKE, fino al punto immediatamente precedente all'installazione di Cloud Service Mesh.

Se hai già familiarità con i concetti di Kubernetes e service mesh, puoi saltare questo tutorial e andare direttamente alla guida all'installazione di Cloud Service Mesh.

Obiettivi

  1. Esplora un semplice "Hello World" multi-servizio un'applicazione.
  2. Esegui l'applicazione dall'origine
  3. Containerizza l'applicazione.
  4. Creare un cluster Kubernetes.
  5. Eseguire il deployment dei container nel cluster.

Prima di iniziare

Segui questi passaggi per abilitare l'API Cloud Service Mesh:
  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.

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.

Prepara Cloud Shell

I vantaggi dell'utilizzo di Cloud Shell sono:

  • Gli ambienti di sviluppo Python 2 e Python 3 (tra cui virtualenv) sono tutti configurati.
  • Gli strumenti a riga di comando gcloud, docker, git e kubectl utilizzati in questo tutorial sono già installati.
  • Puoi scegliere tra editor di testo:

    • Editor di codice, a cui puoi accedere tramite facendo clic su nella parte superiore finestra di Cloud Shell.

    • Emacs, Vim o Nano, a cui si accede 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 del codice di esempio:

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

Esplora l'applicazione multiservizio

L'applicazione di esempio è scritta in Python e ha due componenti comunicare tramite REST:

  • server: un semplice server con un endpoint GET, /, che stampa "hello world" nella console.
  • loadgen: uno script che invia il traffico a server, con un parametro di richieste al secondo (RPS).

applicazione di esempio

Esegui l'applicazione dall'origine

Per acquisire familiarità 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. Fai clic su per aprire un'altra sessione.

  3. Invia una richiesta a server:

    curl http://localhost:8080
    

    server risponde:

    Hello World!
    
  4. Dalla directory in cui hai scaricato il codice di esempio, vai alla directory che contiene il file loadgen:

    cd YOUR_WORKING_DIRECTORY/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. Avvia 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 loadgen:

    python3 loadgen.py
    

    All'avvio, loadgen restituisce un messaggio simile al seguente:

    Starting loadgen: 2019-05-20 10:44:12.448415
    5 request(s) complete to http://localhost:8080
    

    Nell'altra finestra del terminale, server scrive messaggi nella console simili ai seguenti:

    127.0.0.1 - - [21/Jun/2019 14:22:01] "GET / HTTP/1.1" 200 -
    INFO:root:GET request,
    Path: /
    Headers:
    Host: localhost:8080
    User-Agent: python-requests/2.22.0
    Accept-Encoding: gzip, deflate
    Accept: */*
    

    Dal punto di vista della rete, l'intera applicazione ora è in esecuzione sullo stesso host. Per questo motivo, puoi utilizzare localhost per inviare richieste al server.

  10. Per arrestare loadgen e server, inserisci Ctrl-c in ciascun terminale finestra.

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

    deactivate
    

Containerizza l'applicazione

Per eseguire l'applicazione su GKE, devi pacchettizzare l'esempio server e loadgen in container. Un container è un modo per pacchettizzare un'applicazione in modo che sia isolata dall'ambiente di base.

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

Il sample è dotato di un Dockerfile sia per server che per loadgen con tutti i comandi necessari per creare le immagini. Di seguito sono riportate le Dockerfile per server:

FROM python:3.12-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" ]
  • Il comando FROM python:3-slim as base indica a Docker di utilizzare l'ultima immagine Python 3 come l'immagine di base.
  • Il comando COPY . . copia i file di origine nella directory di lavoro corrente (in questo caso solo server.py) nel file system del contenitore.
  • ENTRYPOINT definisce il comando utilizzato per eseguire il container. Nella in questo caso il comando è quasi uguale a quello usato per eseguire server.py dal codice sorgente.
  • Il comando EXPOSE specifica che server è in ascolto sulla porta 8080. Questo comando esporre eventuali porte, ma serve da documentazione che ti serve per aprire la porta 8080 quando esegui containerizzato.

Prepararsi a containerizzare l'applicazione

  1. Imposta le seguenti variabili di ambiente. Sostituisci PROJECT_ID con l'ID del tuo progetto Google Cloud.

    export PROJECT_ID="PROJECT_ID"
    export GCR_REPO="asm-ready"

    Utilizza il valore di PROJECT_ID e GCR_REPO per taggare l'immagine Docker durante la compilazione ed eseguine il push nel tuo Container Registry privato.

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

    gcloud config set project $PROJECT_ID
  3. Imposta la zona predefinita per Google Cloud CLI.

    gcloud config set compute/zone us-central1-b
    
  4. Assicurati che il servizio Container Registry sia abilitato nel progetto Google Cloud.

    gcloud services enable containerregistry.googleapis.com
    

Containerizza server

  1. Passa alla directory in cui si trova l'esempio server:

    cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
  2. Crea l'immagine utilizzando Dockerfile e le variabili di ambiente che hai definito in precedenza:

    docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1 .
    

    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 a Container Registry:

    docker push gcr.io/$PROJECT_ID/$GCR_REPO/helloserver:v0.0.1
    

Containerizza loadgen

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

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

    docker build -t gcr.io/$PROJECT_ID/$GCR_REPO/loadgen:v0.0.1 .
    
  3. Esegui il push dell'immagine a Container Registry:

    docker push gcr.io/$PROJECT_ID/$GCR_REPO/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 gcr.io/$PROJECT_ID/asm-ready

Il comando risponde con i nomi delle immagini che hai appena eseguito il push:

NAME
gcr.io/PROJECT_ID/asm-ready/helloserver
gcr.io/PROJECT_ID/asm-ready/loadgen

Crea un cluster GKE

Puoi eseguire questi container sulla VM Cloud Shell utilizzando Comando docker run. In fase di produzione, però, devi orchestrare i container in modo più unificato. Ad esempio, hai bisogno di un sistema che garantisca che i contenitori siano sempre in esecuzione e di un modo per eseguire l'upgrade e avviare istanze aggiuntive di un contenitore per gestire gli aumenti del traffico.

Puoi utilizzare la modalità GKE per eseguire applicazioni containerizzate. GKE è una piattaforma di orchestrazione dei container che funziona collegando le VM in un cluster. Ogni VM è indicata come nodo. I cluster GKE si basano Sistema open source di gestione dei cluster Kubernetes. Kubernetes fornisce meccanismi attraverso i quali interagisci con il cluster.

Per creare un cluster GKE:

  1. Crea il cluster:

    gcloud container clusters create asm-ready \
      --cluster-version latest \
      --machine-type=n1-standard-4 \
      --num-nodes 4
    

    Il comando gcloud crea un cluster in la zona e il progetto Google Cloud che hai impostato in precedenza. Per eseguire Cloud Service Mesh, consigliamo almeno 4 nodi e n1-standard-4 tipo di macchina.

    Il completamento del comando per la creazione del cluster richiede alcuni minuti. Quando cluster è pronto, il comando restituisce un messaggio simile al seguente:

    NAME        LOCATION       MASTER_VERSION  MASTER_IP      MACHINE_TYPE   NODE_VERSION   NUM_NODES  STATUS
    asm-ready  us-central1-b  1.13.5-gke.10   203.0.113.1    n1-standard-2  1.13.5-gke.10  4          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 asm-ready
    
  3. Ora puoi utilizzare kubectl per comunicare con Kubernetes. Ad esempio, puoi eseguire questo comando per ottenere lo stato dei nodi:

    kubectl get nodes
    

    Il comando risponde con un elenco di nodi, simile al seguente:

    NAME                                       STATUS   ROLES    AGE    VERSION
    gke-asm-ready-default-pool-dbeb23dc-1vg0   Ready    <none>   99s    v1.13.6-gke.13
    gke-asm-ready-default-pool-dbeb23dc-36z5   Ready    <none>   100s   v1.13.6-gke.13
    gke-asm-ready-default-pool-dbeb23dc-fj7s   Ready    <none>   99s    v1.13.6-gke.13
    gke-asm-ready-default-pool-dbeb23dc-wbjw   Ready    <none>   99s    v1.13.6-gke.13
    

Comprendere i concetti chiave di Kubernetes

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

applicazione containerizzata

Prima di eseguire il deployment dei container in GKE, ti consigliamo di ripassa alcuni concetti chiave di Kubernetes. Alla fine di questo tutorial sono disponibili link per approfondire ciascun concetto.

  • Nodi e cluster: in GKE, un nodo è una VM. Su altro su piattaforme Kubernetes, un nodo può essere sia una macchina fisica che una macchina virtuale. Un cluster è un insieme di nodi che possono essere trattati insieme come una singola macchina su cui esegui il deployment di un'applicazione containerizzata.

  • Pod: in Kubernetes, i container vengono eseguiti all'interno di un pod. Un pod è dell'unità atomica in Kubernetes. Un pod contiene uno o più container. Esegui il deployment server e loadgen container, ognuno nel proprio pod. Quando un pod esegue più container (ad esempio un server di applicazioni e un server proxy), i container vengono gestiti come un'unica entità e condividono le risorse del pod.

  • Deployment: un deployment è un oggetto Kubernetes che rappresenta un insieme di di pod identici. Un oggetto Deployment esegue più repliche dei pod distribuiti tra i nodi di un cluster. Un deployment sostituisce automaticamente qualsiasi pod che non rispondono o non rispondono del tutto.

  • Servizio Kubernetes: esecuzione del codice dell'applicazione nelle modifiche GKE il networking tra loadgen e server. Quando hai eseguito i servizi in una VM Cloud Shell, potevi inviare richieste a server utilizzando l'indirizzo localhost:8080. Dopo il deployment in GKE, i pod sono pianificati per essere eseguiti sui nodi disponibili. Per impostazione predefinita, non puoi controllare su quale nodo è in esecuzione il pod, pertanto i pod non hanno indirizzi IP stabili.

    Per ottenere un indirizzo IP per server, devi definire un'astrazione di rete sopra i pod chiamata servizio Kubernetes. Un servizio Kubernetes fornisce un endpoint di rete stabile per un insieme di pod. Esistono diversi tipi di servizi. server utilizza un LoadBalancer, che espone un indirizzo IP esterno che puoi raggiungere server dall'esterno del cluster.

    Kubernetes ha anche un sistema DNS integrato, che assegna i nomi DNS (ad esempio helloserver.default.cluster.local) ai servizi. In questo modo i pod all'interno del cluster possono raggiungere altri pod del cluster con un indirizzo stabile. Non puoi utilizzare questo nome DNS all'esterno del cluster, ad esempio da in Cloud Shell.

Manifest di Kubernetes

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

Imperativo significa basato sui verbi: "fai questo".

Al contrario, Kubernetes opera su una modello dichiarativo. Ciò significa che, invece di dire esattamente a Kubernetes cosa fare, Kubernetes con lo 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.

Devi specificare lo stato desiderato in un insieme di manifest o file YAML. Un file YAML contiene per uno o più oggetti Kubernetes.

Il sample contiene un file YAML per server e loadgen. Ogni codice YAML specifica lo stato desiderato per l'oggetto Kubernetes Deployment assistenza.

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
  • 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. Incluso nel specifica per i pod è il campo image, ovvero il nome l'immagine di cui eseguire il pull da Container Registry.

Il Servizio è 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 carico di rete di servizio, che ha un indirizzo IP stabile ed è raggiungibile all'esterno in un cluster Kubernetes.
  • targetPort: ricorda che il comando EXPOSE 8080 in Dockerfile non espone alcuna porta. Esponi la porta 8080 in modo da poter raggiungere il container server all'esterno del cluster. In questo caso, hellosvc.default.cluster.local:80 (nome breve: hellosvc) mappa al helloserver Porta dell'IP del pod 8080.
  • port: questo è il numero di porta utilizzato dagli altri servizi del cluster quando inviano richieste.

Generatore di carico

L'oggetto Deployment in loadgen.yaml è simile a server.yaml. Un elemento degno di nota è che l'oggetto Deployment contiene una sezione denominata env. Questo definisce le variabili di ambiente richieste da loadgen, che imposti in precedenza, quando eseguivi l'applicazione dall'origine.

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 fornisce un indirizzo IP stabile che fornisce utilizzabile dal 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

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

    cd YOUR_WORKING_DIRECTORY/anthos-service-mesh-samples/docs/helloserver/server/
  2. Apri server.yaml in un editor di testo.

  3. Sostituisci il nome nel campo image con il nome della tua immagine Docker.

    image: gcr.io/PROJECT_ID/asm-ready/helloserver:v0.0.1
    

    Sostituisci PROJECT_ID con il tuo progetto Google Cloud ID.

  4. Salva e chiudi server.yaml.

  5. Esegui il deployment del file YAML in Kubernetes:

    kubectl apply -f server.yaml
    

    Se l'operazione riesce, il comando risponde con quanto segue:

    deployment.apps/helloserver created
    service/hellosvc created
    

  6. Passa alla directory in cui si trova loadgen.

    cd ../loadgen
    
  7. Apri loadgen.yaml in un editor di testo.

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

    image: gcr.io/PROJECT_ID/asm-ready/loadgen:v0.0.1
    

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

  9. Salva e chiudi loadgen.yaml, quindi chiudi l'editor di testo.

  10. Esegui il deployment del file YAML in Kubernetes:

    kubectl apply -f loadgen.yaml
    

    Se l'operazione riesce, il comando risponde con quanto segue:

    deployment.apps/loadgenerator created
    service/loadgensvc created
    

  11. Controlla lo stato dei pod:

    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
    
  12. Recupera i log dell'applicazione dal pod loadgen. Sostituisci POD_ID con l'identificatore dell'output precedente.

    kubectl logs loadgenerator-POD_ID
    
  13. Ottieni gli indirizzi IP esterni di hellosvc:

    kubectl get service
    

    La risposta del comando è simile alla seguente:

    NAME         TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
    hellosvc     LoadBalancer   10.81.15.158   192.0.2.1       80:31127/TCP   33m
    kubernetes   ClusterIP      10.81.0.1      <none>          443/TCP        93m
    loadgensvc   ClusterIP      10.81.15.155   <none>          80/TCP         4m52s
    
  14. Invia una richiesta a hellosvc. Sostituisci EXTERNAL_IP con l'indirizzo IP esterno del tuo hellosvc.

    curl http://EXTERNAL_IP
    

Pronto per Cloud Service Mesh

Ora l'applicazione è stata dispiata in GKE. loadgen puoi utilizzare il DNS di Kubernetes (hellosvc:80) per inviare richieste a server e puoi inviare richieste a server con un indirizzo IP esterno. Sebbene Kubernetes offre molte funzionalità. Alcune informazioni sui servizi mancanti:

  • Come interagiscono i servizi? Qual è la relazione tra i servizi? Come scorre il traffico tra i servizi? Sai che loadgen invia richieste a server, ma immagina di non conoscere bene l'applicazione. Non puoi rispondere a queste domande guardando il dei pod in esecuzione su GKE.
  • Metriche: quanto tempo impiega server per rispondere alle richieste in arrivo? Quante richieste al secondo (RPS) vengono inviate a server? Ci sono risposte di errore?
  • Informazioni di sicurezza: traffico tra loadgen e server piano HTTP o mTLS?

Cloud Service Mesh può fornire risposte a queste domande. Cloud Service Mesh è una versione gestita da Google Cloud del progetto open source Istio. Cloud Service Mesh funziona posizionando Proxy sidecar Envoy in ogni pod. Il proxy Envoy intercetta tutto il traffico in entrata e in uscita verso i container delle applicazioni. Questo significa che server e loadgen ricevono ciascuno un proxy sidecar Envoy e tutti il traffico da loadgen a server è mediato dai proxy Envoy. Le connessioni tra questi proxy Envoy costituiscono il mesh di servizi. Questa architettura mesh dei servizi fornisce un livello di controllo su Kubernetes.

mesh di servizi

Poiché i proxy Envoy vengono eseguiti nei propri container, puoi installare Cloud Service Mesh di un cluster GKE senza modifiche sostanziali il codice dell'applicazione. Tuttavia, esistono alcuni modi chiave per preparare l'applicazione in modo che possa essere strumentata con Cloud Service Mesh:

  • Servizi per tutti i container: sia i deployment server sia loadgen hanno un servizio Kubernetes collegato. Anche loadgen, che non riceve richieste in entrata, ha un servizio.
  • Le porte nei servizi devono essere denominate, anche se GKE ti consente porte di servizio senza nome, Cloud Service Mesh richiede che tu fornisca un nome di una porta che corrisponde al protocollo della porta. Nel file YAML, la porta per server è denominata http perché server utilizza il protocollo di comunicazione HTTP. Se service utilizzava gRPC, il nome della porta sarà grpc.
  • I deployment sono etichettati: questo ti consente di utilizzare le funzionalità di gestione del traffico di Cloud Service Mesh, come la suddivisione del traffico tra le versioni dello stesso servizio.

Installa Cloud Service Mesh

Consulta la guida all'installazione di Cloud Service Mesh e segui le istruzioni per installare Cloud Service Mesh sul tuo cluster.

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.

Per eseguire la pulizia, elimina il cluster GKE. L'eliminazione del cluster elimina tutti i alle risorse che compongono il cluster dei container, come le istanze di calcolo, dischi e risorse di rete.

gcloud container clusters delete asm-ready

Passaggi successivi