Pular para o conteúdo principal

Instalação

Strimzi Operators

Toda configuração é feita em um operator (controller) que cuida de gerenciar e fazer o deploy através dos custom resources por ele disponibilizado.

Existe mais de um operator que iremos instalar pouco a pouco.

Vamos instalar o operator mas vamos instalar via helm.

helm repo add strimzi https://strimzi.io/charts/
helm repo update
## Se quiser ver o values.yaml completo
helm show values strimzi/strimzi-kafka-operator

Vamos definir duas replicas neste values, sendo que uma sempre precise estar ativa para garantir uma alta disponibilidade. Crie o values.yaml abaixo.

#values.yaml
replicas: 2

# A versão padrão das imagens que irá utilizar.
# Ou seja, é a versão do strimzi
defaultImageTag: 0.45.0

leaderElection:
enable: true

podDisruptionBudget:
enabled: true
minAvailable: 1
maxUnavailable:

Importante mencionar que não definimos qual namespace esse operator irá observar. Por default irá observar o namespace kafka, na verdade o mesmo em que ele for instalado. Se necessita que observe recursos criados em outros namespaces deve ser definido no values.

Vamos aplicar.

helm install strimzi strimzi/strimzi-kafka-operator --values values.yaml --namespace kafka --create-namespace

k get deploy -n kafka
NAME READY UP-TO-DATE AVAILABLE AGE
strimzi-cluster-operator 2/2 2 2 3m30s

kubectl get pods -n kafka

NAME READY STATUS RESTARTS AGE
strimzi-cluster-operator-6bf566db79-kwbk6 1/1 Running 0 108s
strimzi-cluster-operator-6bf566db79-qft2r 1/1 Running 0 108s

# Se quiser conferir os logs
kubectl logs deployment/strimzi-cluster-operator -n kafka -f

O Operator irá disponibilizar para nós vários custom resources que utilizaremos para configurar o nosso cluster e gerenciá-lo através de manifestos no kubernetes.

Isso já evita que o crossplane precise extender a API e tampouco precisa de um provider, o que facilitaria muito a integração com IDPs.

Um overview sobre os custom resources existentes até o momento.

kubectl api-resources | grep strimzi  
strimzipodsets sps core.strimzi.io/v1beta2 true StrimziPodSet
kafkabridges kb kafka.strimzi.io/v1beta2 true KafkaBridge
kafkaconnectors kctr kafka.strimzi.io/v1beta2 true KafkaConnector
kafkaconnects kc kafka.strimzi.io/v1beta2 true KafkaConnect
kafkamirrormaker2s kmm2 kafka.strimzi.io/v1beta2 true KafkaMirrorMaker2
kafkamirrormakers kmm kafka.strimzi.io/v1beta2 true KafkaMirrorMaker
kafkanodepools knp kafka.strimzi.io/v1beta2 true KafkaNodePool
kafkarebalances kr kafka.strimzi.io/v1beta2 true KafkaRebalance
kafkas k kafka.strimzi.io/v1beta2 true Kafka
kafkatopics kt kafka.strimzi.io/v1beta2 true KafkaTopic
kafkausers ku kafka.strimzi.io/v1beta2 true KafkaUser

Estude os exemplo do Strimzi que tem muita coisa boa e podemos ir configurando o cluster pouco a pouco.

Existem vários operators diferentes que são controllers diferentes para propósito diferentes no cluster.

Criei um projeto no github com todos os manifestos que iremos aplicar ao longo do caminho.

Como é um cluster de teste vou dimensioná-lo com um volume pequeno, somente de 5GB. Se for criar em produção ajuste.

Primeiro vamos falar sobre os tipos de armazenamento pois é muito importante esclarecer isso.

No contexto do Strimzi Kafka Operator e do Kubernetes, as diferenças entre os tipos de armazenamento Ephemeral e JBOD (Just a Bunch Of Disks) são bastante importantes.

  • Ephemeral Storage (Armazenamento Efêmero): refere-se a um tipo de armazenamento temporário que é associado aos pods enquanto eles estão em execução. Quando o pod é destruído ou reiniciado, todos os dados armazenados nesse volume são perdidos.

    • Os dados não são persistentes entre reinicializações do pod.
    • Usa a infraestrutura de armazenamento local dos nós, o que pode ser mais rápido e barato, mas não oferece durabilidade.
    • Ideal para dados temporários, como caches, logs, ou dados intermediários que não precisam ser persistidos entre reinicializações.
    • Pode ser útil em ambientes de desenvolvimento ou testes onde a durabilidade dos dados não é uma prioridade.
  • JBOD (Just a Bunch of Disks): Refere-se a um tipo de configuração de armazenamento onde você pode adicionar múltiplos discos físicos (ou volumes) ao pod Kafka. Cada disco pode ser usado para armazenar uma parte do log de mensagens do Kafka.

    • Usa volumes persistentes (Persistent Volumes - PVs), o que significa que os dados permanecem armazenados mesmo se o pod Kafka for reiniciado.
    • Proporciona maior segurança e garantia de durabilidade dos dados armazenados.
    • Pode adicionar mais volumes conforme a necessidade para distribuir a carga de armazenamento do Kafka. É possível ter múltiplos volumes conectados ao Kafka, o que aumenta a capacidade de armazenamento.
    • É a escolha recomendada quando se precisa garantir a durabilidade dos dados, pois os volumes persistem mesmo após falhas ou reinicializações do pod.

Um nó pode ser do tipo broker, controle ou ambos. Já que vamos utilizar o Kraft será ambos.

Observe que estamos utilizando custom resources criados pelo Strimzi. Porém isso é só uma definição para o que esperamos dos nodes.

apiVersion: kafka.strimzi.io/v1beta2 ## Custom Resource!
kind: KafkaNodePool
metadata:
name: broker
labels:
strimzi.io/cluster: kafka-cluster # A qual cluster irá pertencer (Vamos definir esse nome no manifesto do cluster ainda)
namespace: kafka # O operator atua sobre esse namespace
spec:
replicas: 3 # Número de nodes que vamos usar.
roles: # Terá as duas funções
- controller
- broker
storage:
type: jbod # tipo do storage
volumes:
- id: 0
type: persistent-claim
size: 5Gi # Como é um cluster simples só de estudo local não precisamos criar com storages muito grandes, mas em produção não é suficiente.
kraftMetadata: shared
deleteClaim: false
# Esse recurso é muito baixo para um cluster kafka, isso é somente para brincar localmente criar uns tópicos
resources:
requests:
memory: 1Gi
cpu: "0.3"
limits:
memory: 1Gi
cpu: "0.3"
# Vamos distribuir os nós entre diferentes nodes fisicos do kubernetes
template:
pod:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: strimzi.io/cluster
operator: In
values:
- kafka-cluster
topologyKey: kubernetes.io/hostname

Aplique o manifesto acima no cluster e nada irá acontecer, pois ele só será criado realmente depois que definirmos o cluster abaixo.

Vou deixar os comentários para entender melhor as partes deste custom resource.

# Basic configuration (required)
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
# Nome do nosso cluster.
# Todos os recursos desse cluster deve ter uma label para avisar ao operator que pertence a este cluster
# A label que será usadas será strimzi.io/cluster: kafka-cluster
name: kafka-cluster
# Deployment specifications
annotations:
# Através dessa annotations estamos avisando que queremos com raft e as configurações dos nodes estão definidas em um node-pool que fizemos antes.
strimzi.io/node-pools: enabled
strimzi.io/kraft: enabled
spec:
kafka:
# Aqui temos algumas portas que vamos utilizar.
listeners:
# Name to identify the listener. Must be unique within the Kafka cluster.
- name: plain
# Port number used by the listener inside Kafka. The port number has to be unique within a given Kafka cluster. Allowed port numbers are 9092 and higher with the exception of ports 9404 and 9999, which are already used for Prometheus and JMX. Depending on the listener type, the port number might not be the same as the port number that connects Kafka clients.
port: 9092
# Listener type specified as internal or cluster-ip (to expose Kafka using per-broker ClusterIP services), or for external listeners, as route (OpenShift only), loadbalancer, nodeport or ingress (Kubernetes only).
type: internal
# Enables or disables TLS encryption for each listener. For route and ingress type listeners, TLS encryption must always be enabled by setting it to true.
tls: false
# Defines whether the fully-qualified DNS names including the cluster service suffix (usually .cluster.local) are assigned.
configuration:
useServiceDnsDomain: true
- name: tls
port: 9093
type: internal
tls: true
# - name: external
# port: 9094
# type: ingress
# tls: true
# authentication:
# type: scram-sha-512
# configuration:
# bootstrap:
# annotations:
# nginx.ingress.kubernetes.io/rewrite-target: "/"
# brokers:
# - broker: 0
# annotations:
# nginx.ingress.kubernetes.io/service-upstream: "true"
# - broker: 1
# annotations:
# nginx.ingress.kubernetes.io/service-upstream: "true"
# - broker: 2
# annotations:
# nginx.ingress.kubernetes.io/service-upstream: "true"
# ingress:
# # Adicionando a anotação para o controlador NGINX
# annotations:
# kubernetes.io/ingress.class: "nginx" # Define que o NGINX será o controlador de ingress
# hosts:
# - kafka.localhost
# # tls:
# # - secretName: kafka-tls # Certificado TLS, se você tiver
# # hosts:
# # - kafka.localhost
# rules:
# - host: kafka.localhost
# http:
# paths:
# - path: /
# pathType: Prefix
# backend:
# service:
# name: kafka-cluster-kafka-bootstrap # O serviço Kafka a ser acessado externamente
# port:
# number: 9092 # Porta do Kafka
# Listener authentication mechanism specified as mTLS, SCRAM-SHA-512, or token-based OAuth 2.0.
# authentication:
# type: tls
# - name: external1
# port: 9094
# type: route
# tls: true
# configuration:
# brokerCertChainAndKey: # (9)
# secretName: my-secret
# certificate: my-certificate.crt
# key: my-key.key

# Kafka version (recommended)
version: "3.9.0"
# KRaft metadata version (recommended)
metadataVersion: "3.9"
# Kafka configuration (recommended)
config: # (12)
auto.create.topics.enable: "false"
offsets.topic.replication.factor: 3
transaction.state.log.replication.factor: 3
transaction.state.log.min.isr: 2
default.replication.factor: 3
min.insync.replicas: 2
# Resources requests and limits (recommended)
# Removido por que estamos usando nodepool
resources:
requests:
memory: 3Gi
cpu: "3"
limits:
memory: 3Gi
cpu: "3"
# Logging configuration (optional)
# Kafka loggers and log levels added directly (inline) or indirectly (external) through a ConfigMap. A custom Log4j configuration must be placed under the log4j.properties key in the ConfigMap. For the Kafka kafka.root.logger.level logger, you can set the log level to INFO, ERROR, WARN, TRACE, DEBUG, FATAL or OFF.
logging: # (14)
type: inline
loggers:
kafka.root.logger.level: INFO
log4j.logger.io.strimzi: "DEBUG"
log4j.logger.kafka: "DEBUG"
log4j.logger.org.apache.kafka: "DEBUG"
# Readiness probe (optional)
readinessProbe: #
initialDelaySeconds: 15
timeoutSeconds: 5
# Liveness probe (optional)
livenessProbe:
initialDelaySeconds: 15
timeoutSeconds: 5

# JVM options (optional)
# JVM configuration options to optimize performance for the Virtual Machine (VM) running Kafka.
# jvmOptions:
# -Xms: 8192m
# -Xmx: 8192m

# Authorization (optional)
# Authorization enables simple, OAUTH 2.0, or OPA authorization on the Kafka broker. Simple authorization uses the AclAuthorizer and StandardAuthorizer Kafka plugins.
# authorization:
# type: simple
# type: opa

# Metrics configuration (optional)
# Prometheus metrics enabled. In this example, metrics are configured for the Prometheus JMX Exporter (the default metrics exporter).
# metricsConfig:
# type: jmxPrometheusExporter
# valueFrom:
# # Rules for exporting metrics in Prometheus format to a Grafana dashboard through the Prometheus JMX Exporter, which are enabled by referencing a ConfigMap containing configuration for the Prometheus JMX exporter. You can enable metrics without further configuration using a reference to a ConfigMap containing an empty file under metricsConfig.valueFrom.configMapKeyRef.key.
# configMapKeyRef:
# name: kafka-metrics
# key: kafka-kraft-metrics-config.yml
# Entity Operator (recommended)
# Entity Operator configuration, which specifies the configuration for the Topic Operator and User Operator.
entityOperator:
topicOperator:
# Ter um namespace só para itens do kafka ou utilizar o mesmo?
watchedNamespace: kafka
reconciliationIntervalMs: 60000
# Resources requests and limits (recommended)
resources:
requests:
memory: 512Mi
cpu: "1"
limits:
memory: 512Mi
cpu: "1"
# Logging configuration (optional)
# Specified Topic Operator loggers and log levels. This example uses inline logging.
logging: # (23)
type: inline
loggers:
rootLogger.level: INFO
userOperator:
watchedNamespace: kafka
reconciliationIntervalMs: 60000
# Resources requests and limits (recommended)
resources:
requests:
memory: 512Mi
cpu: "1"
limits:
memory: 512Mi
cpu: "1"
logging: # (24)
type: inline
loggers:
rootLogger.level: INFO
# Kafka Exporter (optional)
kafkaExporter: {} # (25)
# ...
# Cruise Control (optional)
cruiseControl: {}
# ...

Crie o manifesto acima aplique no cluster. Já esta definido o namespace kafka criado anteriormente. O operator irá entender o que deve fazer e aplicará tudo.

Também vamos explorar o cruiseControl que foi definido no manifesto mas não tem suas regras aindas definidas para o rebalance. Vários exemplos de como utilizar o cruise control estão disponíveis, vamos utilizar o mais genérico por enquando que funciona bem. As coisas devem ser adaptadas de acordo com a proposta e tamanho do seu cluster. Não é obrigatório, mas é muito bem vindo.

apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaRebalance
metadata:
name: rebalance
namespace: kafka
labels:
strimzi.io/cluster: kafka-cluster
annotations:
strimzi.io/rebalance-auto-approval: "true"
spec:
goals:
- CpuCapacityGoal
- NetworkInboundCapacityGoal
- DiskCapacityGoal
- RackAwareGoal
- MinTopicLeadersPerBrokerGoal
- NetworkOutboundCapacityGoal
- ReplicaCapacityGoal

Aplique também o manifesto acima caso queira e vamos ver o que temos.

❯ kubectl get kafkanodepools.kafka.strimzi.io -n kafka
NAME DESIRED REPLICAS ROLES NODEIDS
broker 3 ["controller","broker"] [0,1,2]


❯ kubectl get kafka -n kafka
NAME DESIRED KAFKA REPLICAS DESIRED ZK REPLICAS READY METADATA STATE WARNINGS
kafka-cluster True KRaft


❯ kubectl get deploy -n kafka
NAME READY UP-TO-DATE AVAILABLE AGE
kafka-cluster-cruise-control 1/1 1 1 5d1h
kafka-cluster-entity-operator 1/1 1 1 5d22h
kafka-cluster-kafka-exporter 1/1 1 1 5d
strimzi-cluster-operator 1/1 1 1 7d19h

❯ kubectl get pods -n kafka
NAME READY STATUS RESTARTS AGE
kafka-cluster-broker-0 1/1 Running 0 4h10m
kafka-cluster-broker-1 1/1 Running 0 4h10m
kafka-cluster-broker-2 1/1 Running 0 4h10m
kafka-cluster-cruise-control-5f87855476-jvf9c 1/1 Running 0 4h6m
kafka-cluster-entity-operator-794c776cb7-dd44n 2/2 Running 0 4h6m
kafka-cluster-kafka-exporter-6dcfc78f98-tlhfj 1/1 Running 0 4h6m
strimzi-cluster-operator-6bf566db79-rtwrj 1/1 Running 0 4h8m