Docker 安装 kafka (bitnami/kafka:4.0)

1 拉取镜像

docker pull bitnami/kafka:4.0

2 创建挂载目录

mkdir -p /user/lzl/tool/docker/kafka/bitnami/bitnami_kafka_4.0/home/data
mkdir -p /user/lzl/tool/docker/kafka/bitnami/bitnami_kafka_4.0/home/logs

3 给挂载目录授权

chmod 777 /user/lzl/tool/docker/kafka/bitnami/bitnami_kafka_4.0/home/data
chmod 777 /user/lzl/tool/docker/kafka/bitnami/bitnami_kafka_4.0/home/logs

4 运行容器

4.1 运行命令

docker run -d \
  --name bitnami_kafka_4.0 \
  --restart always \
  --ulimit nofile=65536:65536 \
  -e TZ=Asia/Shanghai \
  -e KAFKA_ENABLE_KRAFT=yes \
  -e KAFKA_CFG_NODE_ID=0 \
  -e KAFKA_CFG_PROCESS_ROLES=controller,broker \
  -e KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@127.0.0.1:9093 \
  -e KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \
  -e KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://113.45.38.93:9092 \
  -e KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT \
  -e KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER \
  -e KAFKA_CFG_LOG_DIRS=/bitnami/kafka/data \
  -p 9092:9092 \
  -v /user/lzl/tool/docker/kafka/bitnami/bitnami_kafka_4.0/home/data:/bitnami/kafka \
  -v /user/lzl/tool/docker/kafka/bitnami/bitnami_kafka_4.0/home/logs:/opt/bitnami/kafka/logs \
  --memory=512m \
  --cpus="1.0" \
  bitnami/kafka:4.0

4.2 命令解释

下面先给出这条 docker run 命令的整体概览,然后逐行详解各个参数和环境变量的作用。

这条命令启动了一个基于 Bitnami 提供的 Kafka 4.0 镜像的容器,并在 KRaft 模式(即不依赖 Zookeeper)下同时担任 controller 和 broker。它设置了时区、节点 ID、监听器及广告地址,指定数据和日志存储目录,限制了文件句柄数、内存和 CPU 使用,并在主机上映射了对应端口,保证容器重启策略为“始终重启”。


4.2.1 基本启动与命名
docker run -d \
  --name bitnami_kafka_4.0 \
  --restart always \
  • docker run -d:以“后台模式”(detached)启动容器,使其在后台运行,不占用当前终端。
  • --name bitnami_kafka_4.0:为容器指定名字,方便后续管理和运维。
  • --restart always:容器退出(无论退出码为何)或 Docker 守护进程重启后,都会自动重启该容器,保证 Kafka 服务的高可用性。

4.2.2 文件句柄限制
  --ulimit nofile=65536:65536 \
  • --ulimit nofile=65536:65536:将容器内“最大打开文件数”(nofile)软限制和硬限制都设置为 65536,避免 Kafka 在高并发情况下因文件描述符不足而崩溃。

4.2.3 时区设置
  -e TZ=Asia/Shanghai \
  • -e TZ=Asia/Shanghai:设置容器时区为北京时间(东八区),使 Kafka 日志及监控时间戳与本地时间保持一致,便于分析与排查。

4.2.4 KRaft 模式开启及节点角色
  -e KAFKA_ENABLE_KRAFT=yes \
  -e KAFKA_CFG_NODE_ID=0 \
  -e KAFKA_CFG_PROCESS_ROLES=controller,broker \
  -e KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@127.0.0.1:9093 \
  • KAFKA_ENABLE_KRAFT=yes:启用 KRaft 模式(Kafka Raft Metadata),这是 Kafka 未来推荐的无 Zookeeper 架构。
  • KAFKA_CFG_NODE_ID=0:为该 Kafka 实例分配唯一的节点 ID,KRaft 模式下用于集群内部元数据选举。
  • KAFKA_CFG_PROCESS_ROLES=controller,broker:指定该节点同时承担 “controller” 和 “broker” 两种角色。
  • KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@127.0.0.1:9093:定义控制器选举的投票列表,格式为 <nodeId>@<host>:<port>,此处只有一个节点自身(单节点集群)。

4.2.5 监听器配置
  -e KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \
  -e KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://IP:9092 \
  -e KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT \
  -e KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER \
  • KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093:定义两个监听端口:
    • PLAINTEXT:对外提供普通客户端连接,监听容器内部 9092 端口;
    • CONTROLLER:内部控制器通信,监听容器内部 9093 端口。
  • KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://IP:9092:告诉客户端连接时使用的地址和端口,通常设置为宿主机或对外 IP,方便外部服务或用户连接。
  • KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT:将每个监听器映射到安全协议,此处均为明文(PLAINTEXT)。
  • KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER:指定用于 controller 通信的监听器名称为 CONTROLLER

4.2.6 日志与数据目录挂载
  -e KAFKA_CFG_LOG_DIRS=/bitnami/kafka/data \
  -p 9092:9092 \
  -v /user/lzl/tool/docker/kafka/bitnami/bitnami_kafka_4.0/home/data:/bitnami/kafka \
  -v /user/lzl/tool/docker/kafka/bitnami/bitnami_kafka_4.0/home/logs:/opt/bitnami/kafka/logs \
  • KAFKA_CFG_LOG_DIRS=/bitnami/kafka/data:Kafka 存储分区数据的目录。
  • -p 9092:9092:将宿主机的 9092 端口映射到容器的 9092,使外部客户端可以访问。
  • -v …/data:/bitnami/kafka:把宿主机的数据目录挂载到容器中,用于持久化 Kafka topic 数据。
  • -v …/logs:/opt/bitnami/kafka/logs:把宿主机的日志目录挂载到容器,用于持久化 Kafka 日志文件,便于排查。

4.2.7 资源限制
  --memory=512m \
  --cpus="1.0" \
  • --memory=512m:限制容器使用最多 512MB 内存,避免单容器占用过多宿主机资源。
  • --cpus="1.0":限制容器最多使用一个 CPU 核心,保障宿主机上其他服务的性能。

4.2.8 镜像与版本
  bitnami/kafka:4.0
  • 使用 Bitnami 官方维护的 bitnami/kafka:4.0 镜像。Bitnami 镜像通常附带最佳实践的配置和管理脚本,方便快速部署生产级 Kafka 服务。

5 SpringBoot 整合

5.1 引入依赖

 <!-- https://mvnrepository.com/artifact/org.springframework.kafka/spring-kafka -->
            <dependency>
                <groupId>org.springframework.kafka</groupId>
                <artifactId>spring-kafka</artifactId>
                <version>${spring.kafka.version}</version>
            </dependency>

5.2 一次拉取一条消息

5.2.1 yml 配置
spring:
  kafka:
    bootstrap-servers: IP:9092
    listener:
      ack-mode: manual_immediate
    consumer:
      group-id: kafka_consumer_group
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      # earliest 启动时,如果找不到有效的偏移量(如消费组第一次启动或偏移量已过期),从 Topic 的最早消息开始消费
      # latest(默认值) 启动时,如果找不到有效的偏移量,从 Topic 的最新消息开始消费(跳过历史消息)
      # none 如果没有有效偏移量,则抛出异常
      auto-offset-reset: earliest
      enable-auto-commit: false
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
      # 发送消息失败允许重试次数
      retries: 5
5.2.2 使用 kafka 发送消息
import org.springframework.kafka.core.KafkaTemplate;

/**
 * 消息发送
 */
@Slf4j
@Component
public class EventPublisher {

    @Resource
    private KafkaTemplate<String, String> kafkaTemplate;

    public void publish(String topic, BaseEvent.EventMessage<?> eventMessage) {
        String messageJson = JSONUtil.toJsonStr(eventMessage);
        publish(topic, messageJson);
    }

    public void publish(String topic, String eventMessageJSON) {
        try {
            kafkaTemplate.send(topic, eventMessageJSON);
            log.info("发送MQ消息 topic:{} message:{}", topic, eventMessageJSON);
        } catch (Exception e) {
            log.error("发送MQ消息失败 topic:{} message:{}", topic, eventMessageJSON, e);
            throw e;
        }
    }
}

5.2.3 使用 kafka 消费消息
 @KafkaListener(topics = {topic}, groupId = "${spring.kafka.consumer.group-id}")
    public void listener(ConsumerRecord<String, String> record, Acknowledgment acknowledgment) {

        String message = record.value();
        try {
            log.info("监听发送消息,topic: {} message: {}", topic, message);
      
      		// 手动确认消费成功
            acknowledgment.acknowledge();
        } catch (Exception e) {
            log.error("监听发送消息,消费失败 topic: {} message: {}", topic, message);
        }

    }

5.3 批量拉取消息

5.3.1 yml 配置

增加 spring.kafka.consumer.max-poll-records ,提高 kafka 消费者批量拉去消息数量;
增加 spring.kafka.consumer.fetch-min-size(Broker 至少准备多少字节数据才返回给 Consumer) 和 spring.kafka.consumer.fetch-max-wait (如果数据没达到 fetch.min.bytes,最多等待多长时间才返回),提高 kafka 消费者批量拉取效率;

spring:
  kafka:
    bootstrap-servers: IP:9092
    listener:
      ack-mode: manual_immediate
    consumer:
      group-id: kafka_consumer_group
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      # earliest 启动时,如果找不到有效的偏移量(如消费组第一次启动或偏移量已过期),从 Topic 的最早消息开始消费
      # latest(默认值) 启动时,如果找不到有效的偏移量,从 Topic 的最新消息开始消费(跳过历史消息)
      # none 如果没有有效偏移量,则抛出异常
      auto-offset-reset: earliest
      enable-auto-commit: false
      # 控制每次 poll() 从 Kafka 中拉取的最大消息数
      max-poll-records: 5
      # 拉取最少1MB数据
      fetch-min-size: 1048576
      # 最多等100ms
      fetch-max-wait: 100
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
      # 发送消息失败允许重试次数
      retries: 5
5.3.2 配置批处理容器工厂
package com.scheme.kafka.factory;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.listener.ContainerProperties;

@Configuration
public class KafkaConsumerConfig {

    @Bean("batchFactory")
    public ConcurrentKafkaListenerContainerFactory<String, String> batchFactory(
            ConsumerFactory<String, String> consumerFactory) {
        ConcurrentKafkaListenerContainerFactory<String, String> factory =
                new ConcurrentKafkaListenerContainerFactory<>();
        factory.setConsumerFactory(consumerFactory);
        factory.setBatchListener(true); // 开启批量消费
        factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL); // 手动 ack(可选)
        return factory;
    }
}
5.3.3 使用 kafka 发送消息
package com.scheme.kafka.producer;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

@Component
public class TestProducer {


    @Resource
    private KafkaTemplate<String, String> kafkaTemplate;

    @PostConstruct
    public void init() {
        for(int i = 0; i < 10; i++) {
            kafkaTemplate.send("test_topic", String.format("testMessage%s", i));
        }
    }

}
5.3.4 使用 kafka 消费消息
package com.scheme.kafka.consumer;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.boot.autoconfigure.jms.AcknowledgeMode;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class TestConsumer {

    @KafkaListener(topics = {"test_topic"}, containerFactory = "batchFactory")
    public void consume(List<ConsumerRecord<String, String>> records, Acknowledgment acknowledgmente) {

        System.out.println(records);
        for (ConsumerRecord<String, String> record : records) {
            String value = record.value();
            System.out.println("================================================================================");
            System.out.println(value);
            System.out.println("================================================================================");
        }

        acknowledgmente.acknowledge();

    }

}
5.3.5 containerFactory 参数介绍

containerFactory = "batchFactory" 是 Spring Kafka 中 @KafkaListener 注解的参数,用于指定KafkaListenerContainerFactory 的 Bean 名称,决定当前监听器的消息消费方式和行为策略。

参数说明
@KafkaListener(
    topics = "my-topic",
    containerFactory = "batchFactory"
)
参数名含义
containerFactory指定使用哪一个 Kafka 监听容器工厂(KafkaListenerContainerFactory Bean)来创建消费者容器。
常见容器工厂区别
Bean 名称消费方式说明
默认(未指定)单条消费每次拉取处理一条消息。
"batchFactory"批量消费每次拉取多条消息,一次性处理一个 List<ConsumerRecord<K,V>>

6 参考

6.1 配置文件地址

/opt/bitnami/kafka/config/
### 正确配置 `bitnami/zookeeper` 和 `bitnami/kafka` 的 Docker 容器 为了实现 ZooKeeper 和 Kafka 集群的正确配置,可以按照以下方式设置容器及其参数。 #### 1. **ZooKeeper 配置** 对于 `bitnami/zookeeper` 容器,需要定义每个节点的身份 (`ZOO_SERVER_ID`) 及其连接地址列表。以下是具体的环境变量和端口映射: - 环境变量: - `ZOO_SERVER_ID=1`: 表示第一个 ZooKeeper 节点的 ID[^1]。 - `ZOO_SERVERS=localhost:2888:3888;localhost:2889:3889;localhost:2890:3890`: 列出了所有 ZooKeeper 节点的地址和端口。 - 端口映射: - `-p 2181:2181`: 对应客户端通信端口。 - `-p 2888:2888`: 同步端口用于内部集群同步。 - `-p 3888:3888`: Leader选举端口。 ```yaml version: '3' services: zookeeper1: image: 'bitnami/zookeeper:latest' environment: - ALLOW_ANONYMOUS_LOGIN=yes - ZOO_SERVER_ID=1 - ZOO_SERVERS=zookeeper1:2888:3888;zookeeper2:2888:3888;zookeeper3:2888:3888 ports: - '2181:2181' - '2888:2888' - '3888:3888' ``` #### 2. **Kafka 配置** 针对 `bitnami/kafka` 容器,需指定 ZooKeeper 连接字符串及其他必要参数: - 环境变量: - `KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper1:2181,zookeeper2:2181,zookeeper3:2181`: 指定 ZooKeeper 集群的连接地址。 - `ALLOW_PLAINTEXT_LISTENER=yes`: 允许明文监听器(仅适用于测试环境)[^3]。 - 端口映射: - `-p 9092:9092`: 外部访问 Kafka 的默认端口。 ```yaml kafka1: image: 'bitnami/kafka:latest' depends_on: - zookeeper1 - zookeeper2 - zookeeper3 environment: - KAFKA_BROKER_ID=1 - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper1:2181,zookeeper2:2181,zookeeper3:2181 - ALLOW_PLAINTEXT_LISTENER=yes ports: - '9092:9092' ``` #### 3. **Network Mode** 推荐为所有服务创建一个自定义网络以便于管理和服务发现: ```yaml networks: app-tier: driver: bridge ``` 并将该网络应用到所有服务中: ```yaml services: zookeeper1: networks: - app-tier kafka1: networks: - app-tier ``` #### 4. **集成 Kafka Manager** 要监控 Kafka 集群的状态,可以通过部署 `Yahoo/kafka-manager` 来完成。具体配置如下: - 环境变量: - `ZK_HOSTS=zookeeper1:2181,zookeeper2:2181,zookeeper3:2181`: 指向 ZooKeeper 集群的地址[^4]。 ```yaml kafka-manager: image: 'yahoo/kafka-manager:latest' environment: - ZK_HOSTS=zookeeper1:2181,zookeeper2:2181,zookeeper3:2181 ports: - '9000:9000' networks: - app-tier ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路上阡陌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值