Apache Kafka & Terraform

Tomasz Gintowt
3 min readFeb 8, 2023

Jeśli pracujesz z Apache Kafka to pewnego dnia stajesz przed potrzebą posiadania jednego miejsca, w którym będziesz mógł zachować konfiguracje tematów ( topics), śledzić zmiany i wersjonowanie.

Rozwiązać ten problem można dwoma narzędziami, Ansible lub Terraform. W tym artykułe opisze jak można zarządzać konfiguracją topic’ów w Terraform.

W Terraform Registry znajdziemy kilkanaście modułów( Providers ) których możemy użyć.

Ja wybrałem jeden z najpopularniejszych — Mongey/terraform-provider-kafka .

Podstawowa konfiguracja w main.tf provider’a wygląda następująco:

terraform {
required_providers {
kafka = {
source = "Mongey/kafka"
version = "0.4.3"
}
}
}

Oczywiście dostępnych opcji jest dużo więcej, zachęcam do zapoznania się dokumentacją. Ja chciałbym się skupić na opcjach do konfiguracji samych tematów.

Jeśli masz więcej niż jeden klaster to można ładnie konfigurację poukładać i w main.tf dodawać klastry jako moduły.

terraform {
required_providers {
kafka = {
source = "Mongey/kafka"
version = "0.4.3"
}
}
}

module "production" {
source = "./production"
bootstrap_servers = ["prod01.example.com:9092", "prod02.example.com:9092"]
}

module "testing" {
source = "./testing"
bootstrap_servers = ["test01.example.com:9092", "test02.example.com:9092"]
}

W tym momencie powinniśmy mieć jeden plik main.tf i dwa katalogi: production oraz testing.

Teraz przechodzimy do najciekawszej cześci - jak zapisać konfigurację topic’ów w Terraform. Mamy do wyboru trzy opcje.

Opcja pierwsza

Plik main.tf pozostaje bez zmian, jedynie w katalogu production/main.tf dodajemy

resource "kafka_topic" "logs" {
name = "systemd_logs"
replication_factor = 2
partitions = 100

config = {
"segment.ms" = "20000"
"cleanup.policy" = "compact"
}
}

Jest bardzo czytelna ale też sprawia najwięcej problemów, cała konfigurację trzeba kopiować dla każdego topic’u. Z jednej strony mamy ładną przejrzystą konfigurację, z drugiej duża ilość kodu. Człowiek to istota z natury leniwa więc zobaczmy co daje opcja druga.

Opcja druga

Ta opcja świetnie się sprawdza, jeżeli mamy dużo topic’ów z taką sama konfiguracją, którą zapiszemy w JSON.

locals {
local_data = jsondecode(file("topics.tf.json"))
}

resource "kafka_topic" "topics" {
# list defined in topics.tf.json
for_each = toset( var.topics )

name = each.key
replication_factor = 2
partitions = 16

config = {
"cleanup.policy" = "compact"
}
}

Plik topics.tf.json będzie wyglądał tak

{
"variable": {
"topics": {
"type": "list(object({ name=string, retention_ms=number }))",
"default": [
{
"name": "my_topic_1",
"retention": 86400000
},
{
"name": "my_topic_2",
"retention": 86400000
}
]
}
}
}

Wygląda znośnie, problem pojawia się jeśli chcemy, każdy z tematów ma różną ilość parametrów konfiguracyjnych. Linia list(object({ name=string, retention_ms=number })) nie jest najszczęśliwszym rozwiązaniem. Wiadomo ma swoje wady i zalety. Ta metoda świetnie sprawdza się, jeśli każdy temat ma tyle samo parametrów konfiguracyjnych.

Opcja trzecia

FOR się nudzi więc dajmu mu jakieś zajęcie.

locals {
topics_local = {
replication_factor = 2,
partitions = 48,
config = {
"retention.ms" = 432000000,
"cleanup.policy" = "compact,delete"
}
}
topics = {for k,v in var.topics_config:
k => merge(local.topics_local, v)
}

}

resource "kafka_topic" "topics" {
for_each = local.topics
name = each.key
replication_factor = each.value.replication_factor
partitions = each.value.partitions
config = each.value.config
}

variable "topics_config" {
default = {
topic_test = {
name = "topic_test",
},
topic_test_1= {
name = "topic_test_1",
partitions = 14,
config = {
"retention.ms" = 86000000,
"cleanup.policy" = ""
}
},
}
}

Ta metoda daje sporo swobody, możemy zarówno mieć dużo topic’ów o jednakowej konfiguracji, jak i tych które maja dodatkowe parametry. Jedynie parametr config jest nieoptymalny, ponieważ zmiana jednego parametru powoduje, że musimy skopiować cały blok. FOR którego używamy nie ma zastosowania do parametrów config, które są podrzędne.

Osobiście wybrałem opcję trzęcią, jest to taki kompromis pomiędzy czytelną konfiguracją, a niepowielaniem dużej części kodu.

Miłej zabawy z Terraform i Apache Kafka!

Tomasz Gintowt jest Architektem/DevOps/DBA/Trenerem, głównie skupiony na dostarczaniu rozwiązań składowania i przetwarzania danych. Nie są mu obce wszelkiej maści bazy danych, systemy real-time data i streamingu. Obecnie pracuje z Apache Kafka, RabbitMQ, Elastic Stack i PostgreSQL. Organizator spotkań DataOps Poland.

https://www.linkedin.com/in/tomasz-gintowt/

https://dataops-academy.pl — kursy i szkolenia.

--

--

Tomasz Gintowt

Architect, DevOps, SysOps, and DBA. Currently, I’m an IT Systems Engineer working with Apache Kafka, RabbitMQ, PostgreSQL, Elastic Stack in Real-Time Data Team.