Esegui il deployment di Apache Kafka su GKE utilizzando Strimzi

La guida mostra come utilizzare l'operatore Strimzi per eseguire il deployment di cluster Apache Kafka.

Kafka è un sistema di messaggistica distribuito open source progettato per gestire dati di streaming in tempo reale, ad alto volume e ad alta velocità effettiva. Consente di creare pipeline di dati di streaming per il trasferimento affidabile dei dati tra diversi sistemi e applicazioni, per supportare le attività di elaborazione e analisi.

Gli operatori sono estensioni software che utilizzano risorse personalizzate per gestire le applicazioni e i relativi componenti. Per saperne di più sul motivo per cui utilizzare gli operatori, consulta Pattern operatore nella documentazione di Kubernetes open source. L'operatore Strimzi offre flessibilità nelle opzioni di deployment e ti consente di utilizzare i taint e le tolleranze di Kubernetes per eseguire Kafka su nodi dedicati.

Questa guida è destinata ad amministratori di piattaforme, architetti cloud e professionisti delle operazioni interessati al deployment di cluster Kafka su GKE.

Questa soluzione è un buon punto di partenza se vuoi imparare a eseguire il deployment di cluster Kafka utilizzando un operatore di terze parti per automatizzare la gestione e ridurre gli errori. Se preferisci un controllo operativo più granulare, consulta Esegui il deployment di cluster Kafka a disponibilità elevata su GKE.

Prepara l'ambiente

In questo tutorial utilizzerai Cloud Shell per gestire le risorse ospitate su Google Cloud. Cloud Shell è preinstallato con il software necessario per questo tutorial, tra cui kubectl, gcloud CLI, Helm e Terraform.

Per configurare l'ambiente con Cloud Shell:

  1. Avvia una sessione di Cloud Shell dalla console Google Cloud facendo clic su Icona di attivazione di Cloud Shell Attiva Cloud Shell nella consoleGoogle Cloud . Viene avviata una sessione nel riquadro inferiore della console Google Cloud .

  2. Imposta le variabili di ambiente:

    export PROJECT_ID=PROJECT_ID
    export KUBERNETES_CLUSTER_PREFIX=kafka
    export REGION=us-central1
    

    Sostituisci PROJECT_ID: il tuo Google Cloud con il tuo ID progetto.

  3. Clona il repository GitHub:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  4. Passa alla directory di lavoro:

    cd kubernetes-engine-samples/streaming/
    

Crea l'infrastruttura del cluster

In questa sezione, esegui uno script Terraform per creare un cluster GKE regionale privato ad alta disponibilità. I seguenti passaggi consentono l'accesso pubblico al control plane. Per limitare l'accesso, crea un cluster privato.

Puoi installare l'operatore utilizzando un cluster standard o Autopilot.

Standard

Il seguente diagramma mostra un cluster GKE Standard regionale privato di cui è stato eseguito il deployment in tre zone diverse:

Per eseguire il deployment di questa infrastruttura, esegui questi comandi da Cloud Shell:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=kafka/terraform/gke-standard init
terraform -chdir=kafka/terraform/gke-standard apply -var project_id=${PROJECT_ID} \
  -var region=${REGION} \
  -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

Quando richiesto, digita yes. Il completamento di questo comando e la visualizzazione dello stato pronto del cluster potrebbero richiedere diversi minuti.

Terraform crea le seguenti risorse:

  • Una rete VPC e una subnet privata per i nodi Kubernetes.
  • Un router per accedere a internet tramite NAT.
  • Un cluster GKE privato nella regione us-central1.
  • 2 node pool con scalabilità automatica abilitata (1-2 nodi per zona, minimo 1 nodo per zona)
  • Un ServiceAccount con autorizzazioni di logging e monitoraggio.
  • Backup per GKE per il ripristino di emergenza.
  • Google Cloud Managed Service per Prometheus per il monitoraggio del cluster.

L'output è simile al seguente:

...
Apply complete! Resources: 14 added, 0 changed, 0 destroyed.

Outputs:

kubectl_connection_command = "gcloud container clusters get-credentials strimzi-cluster --region us-central1"

Autopilot

Il seguente diagramma mostra un cluster GKE Autopilot regionale privato:

Per eseguire il deployment dell'infrastruttura, esegui questi comandi da Cloud Shell:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform -chdir=kafka/terraform/gke-autopilot init
terraform -chdir=kafka/terraform/gke-autopilot apply -var project_id=${PROJECT_ID} \
  -var region=${REGION} \
  -var cluster_prefix=${KUBERNETES_CLUSTER_PREFIX}

Quando richiesto, digita yes. Il completamento di questo comando e la visualizzazione dello stato pronto del cluster potrebbero richiedere diversi minuti.

Terraform crea le seguenti risorse:

  • Rete VPC e subnet privata per i nodi Kubernetes.
  • Un router per accedere a internet tramite NAT.
  • Un cluster GKE privato nella regione us-central1.
  • Un ServiceAccount con autorizzazioni di logging e monitoraggio
  • Google Cloud Managed Service per Prometheus per il monitoraggio del cluster.

L'output è simile al seguente:

...
Apply complete! Resources: 12 added, 0 changed, 0 destroyed.

Outputs:

kubectl_connection_command = "gcloud container clusters get-credentials strimzi-cluster --region us-central1"

Connessione al cluster

Configura kubectl per comunicare con il cluster:

gcloud container clusters get-credentials ${KUBERNETES_CLUSTER_PREFIX}-cluster --region ${REGION}

Esegui il deployment dell'operatore Strimzi nel tuo cluster

In questa sezione, esegui il deployment dell'operatore Strimzi utilizzando un grafico Helm. Esistono anche diversi altri modi per eseguire il deployment di Strimzi.

  1. Aggiungi il repository del grafico Helm di Strimzi:

    helm repo add strimzi https://strimzi.io/charts/
    
  2. Aggiungi uno spazio dei nomi per l'operatore Strimzi e il cluster Kafka:

    kubectl create ns kafka
    
  3. Esegui il deployment dell'operatore del cluster Strimzi utilizzando Helm:

    helm install strimzi-operator strimzi/strimzi-kafka-operator -n kafka
    

    Per eseguire il deployment di Strimzi Cluster Operator e dei cluster Kafka in spazi dei nomi diversi, aggiungi il parametro --set watchNamespaces="{kafka-namespace,kafka-namespace-2,...}" al comando Helm.

  4. Verifica che l'operatore del cluster Strimzi sia stato implementato correttamente utilizzando Helm:

    helm ls -n kafka
    

    L'output è simile al seguente:

    NAME            NAMESPACE    REVISION    UPDATED                              STATUS    CHART                        APP VERSION
    strimzi-operator    kafka      1       2023-06-27 11:22:15.850545 +0200 CEST    deployed    strimzi-kafka-operator-0.35.0    0.35.0
    

Esegui il deployment di Kafka

Dopo aver eseguito il deployment dell'operatore nel cluster, puoi eseguire il deployment di un'istanza del cluster Kafka.

In questa sezione, esegui il deployment di Kafka in una configurazione di base e poi prova vari scenari di configurazione avanzata per soddisfare i requisiti di disponibilità, sicurezza e osservabilità.

Configurazione di base

La configurazione di base per l'istanza Kafka include i seguenti componenti:

  • Tre repliche dei broker Kafka, con un minimo di due repliche disponibili necessarie per la coerenza del cluster.
  • Tre repliche dei nodi ZooKeeper, che formano un cluster.
  • Due listener Kafka: uno senza autenticazione e uno che utilizza l'autenticazione TLS con un certificato generato da Strimzi.
  • MaxHeapSize e MinHeapSize di Java impostati su 4 GB per Kafka e 2 GB per ZooKeeper.
  • Allocazione delle risorse CPU di 1 richiesta CPU e 2 limiti CPU sia per Kafka che per ZooKeeper, insieme a 5 GB di richieste e limiti di memoria per Kafka (4 GB per il servizio principale e 0,5 GB per l'esportatore di metriche) e 2,5 GB per ZooKeeper (2 GB per il servizio principale e 0,5 GB per l'esportatore di metriche).
  • Operatore dell'entità con le seguenti richieste e limiti:
    • tlsSidecar: CPU da 100 m/500 m e 128 Mi di memoria.
    • topicOperator: CPU da 100 m/500 m e 512 Mi di memoria.
    • userOperator: 500 m di CPU e 2 Gi di memoria.
  • 100 GB di spazio di archiviazione allocati a ogni pod utilizzando premium-rwo storageClass.
  • Tolleranze, nodeAffinity e podAntiAffinity configurati per ogni workload, garantendo una distribuzione corretta tra i nodi, utilizzando i rispettivi pool di nodi e zone diverse.
  • Comunicazione all'interno del cluster protetta da certificati autofirmati: CA separate per cluster e client (mTLS). Puoi anche configurare l'utilizzo di un'autorità di certificazione diversa.

Questa configurazione rappresenta la configurazione minima richiesta per creare un cluster Kafka pronto per la produzione. Le sezioni seguenti mostrano configurazioni personalizzate per gestire aspetti quali la sicurezza del cluster, gli elenchi di controllo dell'accesso (ACL), la gestione degli argomenti, la gestione dei certificati e altro ancora.

Crea un cluster Kafka di base

  1. Crea un nuovo cluster Kafka utilizzando la configurazione di base:

    kubectl apply -n kafka -f kafka-strimzi/manifests/01-basic-cluster/my-cluster.yaml
    

    Questo comando crea una risorsa personalizzata Kafka dell'operatore Strimzi che include richieste e limiti di CPU e memoria, richieste di archiviazione a blocchi e una combinazione di taint e affinità per distribuire i pod di cui è stato eseguito il provisioning tra i nodi Kubernetes.

  2. Attendi qualche minuto mentre Kubernetes avvia i carichi di lavoro richiesti:

    kubectl wait kafka/my-cluster --for=condition=Ready --timeout=600s -n kafka
    
  3. Verifica che siano stati creati i carichi di lavoro Kafka:

    kubectl get pod,service,deploy,pdb -l=strimzi.io/cluster=my-cluster -n kafka
    

    L'output è simile al seguente:

    NAME                                            READY   STATUS  RESTARTS   AGE
    pod/my-cluster-entity-operator-848698874f-j5m7f   3/3   Running   0        44m
    pod/my-cluster-kafka-0                          1/1   Running   0        5m
    pod/my-cluster-kafka-1                          1/1   Running   0        5m
    pod/my-cluster-kafka-2                          1/1   Running   0        5m
    pod/my-cluster-zookeeper-0                      1/1   Running   0        6m
    pod/my-cluster-zookeeper-1                      1/1   Running   0        6m
    pod/my-cluster-zookeeper-2                      1/1   Running   0        6m
    
    NAME                                TYPE      CLUSTER-IP   EXTERNAL-IP   PORT(S)                             AGE
    service/my-cluster-kafka-bootstrap  ClusterIP   10.52.8.80   <none>      9091/TCP,9092/TCP,9093/TCP          5m
    service/my-cluster-kafka-brokers    ClusterIP   None         <none>      9090/TCP,9091/TCP,9092/TCP,9093/TCP   5m
    service/my-cluster-zookeeper-client   ClusterIP   10.52.11.144   <none>      2181/TCP                            6m
    service/my-cluster-zookeeper-nodes  ClusterIP   None         <none>      2181/TCP,2888/TCP,3888/TCP          6m
    
    NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/my-cluster-entity-operator   1/1   1          1         44m
    
    NAME                                            MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
    poddisruptionbudget.policy/my-cluster-kafka     2             N/A             1                   5m
    poddisruptionbudget.policy/my-cluster-zookeeper   2             N/A             1                   6m
    

L'operatore crea le seguenti risorse:

  • Due StrimziPodSets per Kafka e ZooKeeper.
  • Tre pod per le repliche del broker Kafka.
  • Tre pod per le repliche di ZooKeeper.
  • Due PodDisruptionBudgets, che garantiscono una disponibilità minima di due repliche per la coerenza del cluster.
  • Un servizio denominato my-cluster-kafka-bootstrap, che funge da server di bootstrap per i client Kafka che si connettono dall'interno del cluster Kubernetes. Tutti i listener Kafka interni sono disponibili in questo servizio.
  • Un servizio headless denominato my-cluster-kafka-brokers che consente la risoluzione DNS direttamente degli indirizzi IP dei pod del broker Kafka. Questo servizio viene utilizzato per la comunicazione tra broker.
  • Un servizio denominato my-cluster-zookeeper-client che consente ai broker Kafka di connettersi ai nodi ZooKeeper come client.
  • Un servizio headless denominato my-cluster-zookeeper-nodes che consente la risoluzione DNS direttamente degli indirizzi IP dei pod ZooKeeper. Questo servizio viene utilizzato per connettersi tra le repliche di ZooKeeper.
  • Un deployment denominato my-cluster-entity-operator che contiene topic-operator e user-operator e facilita la gestione delle risorse personalizzate KafkaTopics e KafkaUsers.

Puoi anche configurare due NetworkPolicies per facilitare la connettività ai listener Kafka da qualsiasi pod e spazio dei nomi. Questi criteri limiterebbero anche le connessioni a ZooKeeper ai broker e consentirebbero la comunicazione tra i pod del cluster e le porte di servizio interne esclusive per la comunicazione del cluster.

Autenticazione e gestione degli utenti

Questa sezione mostra come attivare l'autenticazione e l'autorizzazione per proteggere i listener Kafka e condividere le credenziali con i client.

Strimzi fornisce un metodo nativo di Kubernetes per la gestione degli utenti utilizzando un User Operator separato e la relativa risorsa personalizzata Kubernetes, KafkaUser, che definisce la configurazione utente. La configurazione utente include le impostazioni per l'autenticazione e l'autorizzazione e il provisioning dell'utente corrispondente in Kafka.

Strimzi può creare listener e utenti Kafka che supportano diversi meccanismi di autenticazione come l'autenticazione basata su nome utente e password (SCRAM-SHA-512) o TLS. Puoi utilizzare anche l'autenticazione OAuth 2.0, spesso considerata un approccio migliore rispetto all'utilizzo di password o certificati per l'autenticazione a causa della sicurezza e della gestione delle credenziali esterne.

Esegui il deployment di un cluster Kafka

Questa sezione mostra come eseguire il deployment di un operatore Strimzi che dimostra le funzionalità di gestione degli utenti, tra cui:

  • Un cluster Kafka con autenticazione basata su password (SCRAM-SHA-512) attivata su uno dei listener.
  • Un KafkaTopic con 3 repliche.
  • Un KafkaUser con un ACL che specifica che l'utente dispone delle autorizzazioni di lettura e scrittura per l'argomento.
  1. Configura il cluster Kafka in modo che utilizzi un listener con autenticazione SCRAM-SHA-512 basata su password sulla porta 9094 e autorizzazione semplice:

    kubectl apply -n kafka -f kafka-strimzi/manifests/03-auth/my-cluster.yaml
    
  2. Crea un Topic, un User e un pod client per eseguire comandi sul cluster Kafka:

    kubectl apply -n kafka -f kafka-strimzi/manifests/03-auth/topic.yaml
    kubectl apply -n kafka -f kafka-strimzi/manifests/03-auth/my-user.yaml
    

    Il Secret my-user con le credenziali utente viene montato sul pod client come volume.

    Queste credenziali confermano che l'utente dispone delle autorizzazioni per pubblicare messaggi nell'argomento utilizzando il listener con l'autenticazione basata su password (SCRAM-SHA-512) abilitata.

  3. Crea un pod client:

    kubectl apply -n kafka -f kafka-strimzi/manifests/03-auth/kafkacat.yaml
    
  4. Attendi qualche minuto finché il pod client non diventa Ready, quindi connettiti:

    kubectl wait --for=condition=Ready pod --all -n kafka --timeout=600s
    kubectl exec -it kafkacat -n kafka -- /bin/sh
    
  5. Produci un nuovo messaggio con le credenziali my-user e prova a utilizzarlo:

    echo "Message from my-user" |kcat \
      -b my-cluster-kafka-bootstrap.kafka.svc.cluster.local:9094 \
      -X security.protocol=SASL_SSL \
      -X sasl.mechanisms=SCRAM-SHA-512 \
      -X sasl.username=my-user \
      -X sasl.password=$(cat /my-user/password) \
      -t my-topic -P
    kcat -b my-cluster-kafka-bootstrap.kafka.svc.cluster.local:9094 \
      -X security.protocol=SASL_SSL \
      -X sasl.mechanisms=SCRAM-SHA-512 \
      -X sasl.username=my-user \
      -X sasl.password=$(cat /my-user/password) \
      -t my-topic -C
    

    L'output è simile al seguente:

    Message from my-user
    % Reached end of topic my-topic [0] at offset 0
    % Reached end of topic my-topic [2] at offset 1
    % Reached end of topic my-topic [1] at offset 0
    

    Digita CTRL+C per interrompere la procedura consumer.

  6. Esci dalla shell del pod

    exit
    

Backup e ripristino di emergenza

Sebbene l'operatore Strimzi non offra funzionalità di backup integrate, puoi implementare strategie di backup efficienti seguendo determinati pattern.

Puoi utilizzare Backup per GKE per eseguire il backup di:

  • Manifest delle risorse Kubernetes.
  • Risorse personalizzate dell'API Strimzi e relative definizioni estratte dal server API Kubernetes del cluster sottoposto a backup.
  • Volumi che corrispondono alle risorse PersistentVolumeClaim trovate nei manifest.

Per maggiori informazioni su come eseguire il backup e il ripristino dei cluster Kafka utilizzando Backup per GKE, consulta Prepararsi per il disaster recovery.

Puoi anche eseguire il backup di un cluster Kafka di cui è stato eseguito il deployment utilizzando l'operatore Strimzi. Devi eseguire il backup di:

  • La configurazione di Kafka, che include tutte le risorse personalizzate dell'API Strimzi, come KafkaTopics e KafkaUsers.
  • I dati, archiviati nei PersistentVolume dei broker Kafka.

L'archiviazione dei manifest delle risorse Kubernetes, incluse le configurazioni Strimzi, nei repository Git può eliminare la necessità di un backup separato per la configurazione di Kafka, perché le risorse possono essere riapplicate a un nuovo cluster Kubernetes, se necessario.

Per salvaguardare il recupero dei dati Kafka negli scenari in cui viene persa un'istanza del server Kafka o un cluster Kubernetes in cui è stato eseguito il deployment di Kafka, ti consigliamo di configurare la classe di archiviazione Kubernetes utilizzata per il provisioning dei volumi per i broker Kafka con l'opzione reclaimPolicy impostata su Retain. Ti consigliamo inoltre di creare snapshot dei volumi del broker Kafka.

Il seguente manifest descrive una StorageClass che utilizza l'opzione reclaimPolicy Retain:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: premium-rwo-retain
...
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer

L'esempio seguente mostra la StorageClass aggiunta a spec di una risorsa personalizzata del cluster Kafka:

# ...
spec:
  kafka:
    # ...
    storage:
      type: persistent-claim
      size: 100Gi
      class: premium-rwo-retain

Con questa configurazione, i PersistentVolume di cui è stato eseguito il provisioning utilizzando StorageClass non vengono eliminati anche quando viene eliminato il PersistentVolumeClaim corrispondente.

Per recuperare l'istanza Kafka su un nuovo cluster Kubernetes utilizzando la configurazione esistente e i dati dell'istanza del broker:

  1. Applica le risorse personalizzate Strimzi Kafka esistenti (Kakfa, KafkaTopic, KafkaUser e così via) a un nuovo cluster Kubernetes
  2. Aggiorna PersistentVolumeClaims con il nome delle nuove istanze del broker Kafka ai vecchi PersistentVolumes utilizzando la proprietà spec.volumeName in PersistentVolumeClaim.