Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Kafka on Azure

Production deployment guide for Apache Kafka on Microsoft Azure.


Kafka brokers across three Azure availability zonesKafka brokers across three Azure availability zonesAzure RegionVirtual NetworkZone 1Zone 2Zone 3Client SubnetBroker 1Premium SSDBroker 2Premium SSDBroker 3Premium SSDProducersConsumersReplicationReplicationReplication

WorkloadVM SizevCPUsMemoryNetworkUse Case
DevelopmentStandard_D2s_v528 GBUp to 12.5 GbpsTesting
Small ProductionStandard_D4s_v5416 GBUp to 12.5 GbpsLow throughput
Medium ProductionStandard_D8s_v5832 GB12.5 GbpsModerate throughput
Large ProductionStandard_E16s_v516128 GB12.5 GbpsHigh throughput
High PerformanceStandard_L8s_v3864 GB12.5 GbpsI/O intensive
  • Dsv5-series provides balanced compute for general workloads
  • Esv5-series provides additional memory for large page cache requirements
  • Lsv3-series provides local NVMe storage for I/O-intensive workloads
  • Accelerated networking must be enabled for production deployments

Disk TypeIOPS (max)Throughput (max)Use Case
Premium SSD v280,0001,200 MB/sRecommended
Premium SSD20,000900 MB/sStandard production
Standard SSD6,000750 MB/sDevelopment
Ultra Disk160,0004,000 MB/sHigh performance
Terminal window
# Create Premium SSD v2 disk
az disk create \
--resource-group kafka-rg \
--name kafka-data-1 \
--size-gb 1024 \
--sku PremiumV2_LRS \
--disk-iops-read-write 6000 \
--disk-mbps-read-write 500 \
--zone 1 \
--location eastus
MetricRecommendation
Disk Size10x daily data volume
IOPS3,000 + (500 × partitions per broker)
Throughput2x expected peak MB/s
Terminal window
# Format with XFS
mkfs.xfs /dev/sdc
# Mount options for Kafka
echo '/dev/sdc /kafka xfs noatime,nodiratime 0 2' >> /etc/fstab
mount /kafka
# Create Kafka directories
mkdir -p /kafka/data
chown -R kafka:kafka /kafka

Terminal window
# Create resource group
az group create --name kafka-rg --location eastus
# Create virtual network
az network vnet create \
--resource-group kafka-rg \
--name kafka-vnet \
--address-prefix 10.0.0.0/16
# Create subnets for each zone
az network vnet subnet create \
--resource-group kafka-rg \
--vnet-name kafka-vnet \
--name kafka-subnet-1 \
--address-prefix 10.0.1.0/24
az network vnet subnet create \
--resource-group kafka-rg \
--vnet-name kafka-vnet \
--name kafka-subnet-2 \
--address-prefix 10.0.2.0/24
az network vnet subnet create \
--resource-group kafka-rg \
--vnet-name kafka-vnet \
--name kafka-subnet-3 \
--address-prefix 10.0.3.0/24
Terminal window
# Create NSG
az network nsg create \
--resource-group kafka-rg \
--name kafka-nsg
# Allow inter-broker communication
az network nsg rule create \
--resource-group kafka-rg \
--nsg-name kafka-nsg \
--name AllowKafkaBrokers \
--priority 100 \
--source-address-prefixes 10.0.0.0/16 \
--destination-port-ranges 9092-9094 \
--access Allow \
--protocol Tcp
# Allow client access
az network nsg rule create \
--resource-group kafka-rg \
--nsg-name kafka-nsg \
--name AllowKafkaClients \
--priority 200 \
--source-address-prefixes 10.0.0.0/16 \
--destination-port-ranges 9092 \
--access Allow \
--protocol Tcp

Ports depend on your listener configuration; the table below shows common defaults.

PortProtocolPurpose
9092TCPClient or inter-broker (PLAINTEXT example)
9093TCPClient or inter-broker (SSL)
9094TCPClient or inter-broker (SASL_SSL)

Accelerated networking must be enabled for production deployments.

Terminal window
# Enable accelerated networking on NIC
az network nic update \
--resource-group kafka-rg \
--name kafka-broker-nic \
--accelerated-networking true

Brokers must be distributed across availability zones for fault tolerance.

Terminal window
# Create VM in zone 1
az vm create \
--resource-group kafka-rg \
--name kafka-broker-1 \
--zone 1 \
--image UbuntuLTS \
--size Standard_D8s_v5
# Create VM in zone 2
az vm create \
--resource-group kafka-rg \
--name kafka-broker-2 \
--zone 2 \
--image UbuntuLTS \
--size Standard_D8s_v5
# Create VM in zone 3
az vm create \
--resource-group kafka-rg \
--name kafka-broker-3 \
--zone 3 \
--image UbuntuLTS \
--size Standard_D8s_v5
# Broker 1 (Zone 1)
broker.id=1
broker.rack=zone-1
# Broker 2 (Zone 2)
broker.id=2
broker.rack=zone-2
# Broker 3 (Zone 3)
broker.id=3
broker.rack=zone-3

main.tf
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "kafka" {
name = "kafka-rg"
location = "East US"
}
resource "azurerm_virtual_network" "kafka" {
name = "kafka-vnet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.kafka.location
resource_group_name = azurerm_resource_group.kafka.name
}
resource "azurerm_subnet" "kafka" {
count = 3
name = "kafka-subnet-${count.index + 1}"
resource_group_name = azurerm_resource_group.kafka.name
virtual_network_name = azurerm_virtual_network.kafka.name
address_prefixes = ["10.0.${count.index + 1}.0/24"]
}
resource "azurerm_network_interface" "kafka" {
count = 3
name = "kafka-nic-${count.index + 1}"
location = azurerm_resource_group.kafka.location
resource_group_name = azurerm_resource_group.kafka.name
enable_accelerated_networking = true
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.kafka[count.index].id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_linux_virtual_machine" "kafka" {
count = 3
name = "kafka-broker-${count.index + 1}"
resource_group_name = azurerm_resource_group.kafka.name
location = azurerm_resource_group.kafka.location
size = "Standard_D8s_v5"
zone = count.index + 1
admin_username = "azureuser"
admin_ssh_key {
username = "azureuser"
public_key = file("~/.ssh/id_rsa.pub")
}
network_interface_ids = [
azurerm_network_interface.kafka[count.index].id,
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
disk_size_gb = 100
}
source_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-jammy"
sku = "22_04-lts"
version = "latest"
}
tags = {
Role = "kafka-broker"
}
}
resource "azurerm_managed_disk" "kafka_data" {
count = 3
name = "kafka-data-${count.index + 1}"
location = azurerm_resource_group.kafka.location
resource_group_name = azurerm_resource_group.kafka.name
storage_account_type = "PremiumV2_LRS"
create_option = "Empty"
disk_size_gb = 1024
zone = count.index + 1
disk_iops_read_write = 6000
disk_mbps_read_write = 500
}
resource "azurerm_virtual_machine_data_disk_attachment" "kafka_data" {
count = 3
managed_disk_id = azurerm_managed_disk.kafka_data[count.index].id
virtual_machine_id = azurerm_linux_virtual_machine.kafka[count.index].id
lun = 0
caching = "None"
}
resource "azurerm_network_security_group" "kafka" {
name = "kafka-nsg"
location = azurerm_resource_group.kafka.location
resource_group_name = azurerm_resource_group.kafka.name
security_rule {
name = "AllowKafka"
priority = 100
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "9092-9094"
source_address_prefix = "10.0.0.0/16"
destination_address_prefix = "*"
}
}

For secure connectivity from other Azure services.

Terminal window
# Create private endpoint for Kafka
az network private-endpoint create \
--resource-group kafka-rg \
--name kafka-private-endpoint \
--vnet-name client-vnet \
--subnet client-subnet \
--private-connection-resource-id /subscriptions/xxx/resourceGroups/kafka-rg/... \
--connection-name kafka-connection