零运维基础:Kafka Docker完整部署+全链路问题排查实战指南
前言
我是一名Go后端开发工程师,不熟悉运维工作。这篇文章记录的是我零运维基础,通过SSH直接连接裸服务器进行Kafka部署的全过程。
我们购买的是纯裸服务器,没有集成Docker、K8s等任何开箱即用的云端工具,所有环境都需要自己手动搭建。这是在测试环境进行的部署,目的是尽量和生产环境保持一致的Kafka环境(生产环境使用的是云服务器厂商提供的托管Kafka产品)。
本文完整记录了从0到1的部署步骤,以及遇到的4类核心问题、一步步的排查思路和最终解决方案,哪怕是和我一样没有运维基础的开发人员,也能跟着本文完成部署。
一、部署背景与前期规划
1. 需求说明
本次部署的核心要求:
- 测试环境指定Kafka版本:
2.3.0(与生产环境托管版本对齐) - 部署方式:Docker + Docker Compose,方便后续运维管理
- 安全要求:双端口隔离(内网服务免密访问、外网客户端强制账号密码认证)
- 配套工具:Kafdrop可视化管理面板,方便Topic、消息的可视化运维
- 目录规范:和本地开发环境的目录结构对齐,降低维护成本
2. 服务器与环境说明
- 服务器:Linux云服务器(裸机,无预装环境),公网访问地址为【你的服务器公网IP】
- Docker版本:
24.0.9(手动安装) - 部署目录:
/opt/docker/kafka(符合Linux第三方应用目录规范) - 镜像选型:业界通用的
wurstmeister/kafka(兼容性强、配置简单,适配指定的2.3.0版本)
3. 目录结构规划
提前规划好持久化目录,避免容器重启后数据丢失,同时和本地开发结构对齐:
/opt/docker/kafka/
├── docker-compose.yml # 核心编排文件
├── kafka_server_jaas.conf # SASL账号密码认证配置
├── config/ # (可选) 额外配置文件目录
├── data/ # Kafka数据持久化目录
├── logs/ # Kafka运行日志目录
├── zookeeper-data/ # Zookeeper数据目录
└── zookeeper-logs/ # Zookeeper日志目录
二、完整部署步骤
1. 服务器目录创建与权限配置
通过SSH登录服务器,进入目标目录后执行以下命令创建所有需要的子目录:
# 进入目标根目录
cd /opt/docker/kafka
# 直接在当前目录下创建所有子目录
sudo mkdir -p config data logs zookeeper-data zookeeper-logs
# 配置目录权限(wurstmeister镜像默认使用1001用户运行,必须开放对应权限)
sudo chown -R 1001:1001 /opt/docker/kafka
2. 编写认证配置文件
为了实现外网强制账号密码认证,需要创建JAAS认证配置文件kafka_server_jaas.conf,放在/opt/docker/kafka目录下:
KafkaServer {
org.apache.kafka.common.security.plain.PlainLoginModule required
serviceName="kafka"
username="【管理员账号】"
password="【管理员密码】"
user_【管理员账号】="【管理员密码】"
user_【应用接入账号】="【应用接入密码】";
};
配置说明:
- 第一组账号密码为Kafka集群间通信的管理员账号
- 格式规范:
user_用户名="密码",可按需新增多个业务接入账号
3. 编写docker-compose.yml核心编排文件
最终版编排文件实现了双端口安全隔离:
- 内网端口
9093:容器内部/服务器本地免密访问,给Kafdrop、同服务器的业务服务使用 - 外网端口
9092:强制SASL账号密码认证,给远程客户端、本地开发环境使用
完整docker-compose.yml内容如下:
version: '2'
# 自定义桥接网络,所有服务通过服务名直接通信
networks:
kafka-network:
driver: bridge
services:
# Zookeeper:Kafka依赖的元数据协调服务
zookeeper:
image: wurstmeister/zookeeper
container_name: zookeeper
restart: always
ports:
- "2181:2181"
networks:
- kafka-network
volumes:
- ./zookeeper-data:/data
- ./zookeeper-logs:/datalog
# Kafka Broker核心服务,固定2.3.0版本和生产环境对齐
kafka:
image: wurstmeister/kafka:2.12-2.3.0
container_name: kafka
restart: always
ports:
- "9092:9092" # 外网认证端口
environment:
# 核心监听配置:区分内网免密、外网认证
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9093,SASL_PLAINTEXT://0.0.0.0:9092
# 对外公布的连接地址,必须替换为自己的服务器公网IP
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9093,SASL_PLAINTEXT://【你的服务器公网IP】:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,SASL_PLAINTEXT:SASL_PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
# Zookeeper连接地址,通过服务名直接通信
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
# 生产基础配置
KAFKA_DEFAULT_REPLICATION_FACTOR: 1
KAFKA_NUM_PARTITIONS: 3
KAFKA_MESSAGE_MAX_BYTES: 20000000
# 开启SASL账号密码认证
KAFKA_SASL_ENABLED_MECHANISMS: PLAIN
KAFKA_OPTS: -Djava.security.auth.login.config=/kafka/config/kafka_server_jaas.conf
# 数据持久化挂载
volumes:
- ./data:/kafka
- ./logs:/opt/kafka/logs
- ./kafka_server_jaas.conf:/kafka/config/kafka_server_jaas.conf
networks:
- kafka-network
depends_on:
- zookeeper
# Kafdrop可视化管理面板,通过内网免密端口连接Kafka
kafdrop:
image: obsidiandynamics/kafdrop
container_name: kafdrop
restart: always
ports:
- "9000:9000"
environment:
KAFKA_BROKERCONNECT: kafka:9093
SERVER_PORT: 9000
networks:
- kafka-network
depends_on:
- kafka
4. 启动服务
编排文件和认证文件准备完成后,执行启动命令。
三、部署过程中的问题排查与解决
本次部署过程中遇到了4类典型问题,以下是完整的排查思路、根因定位和解决方法,也是Kafka Docker部署中90%的人都会踩的坑。
问题1:docker-compose命令不存在,Docker已正常安装
现象
执行docker-compose up -d启动服务时,报错:
Command 'docker-compose' not found, but can be installed with:
apt install docker-compose
但执行docker --version,能正常输出版本号Docker version 24.0.9, build 2936816。
排查思路与根因定位
因为是裸服务器,只手动安装了Docker核心引擎,没有安装docker-compose编排工具。虽然Docker 20.10+版本内置了V2版本的插件(命令为docker compose),但系统默认没有安装,因此无法识别旧版的docker-compose命令。
解决方法
根据系统提示,直接使用apt包管理器安装旧版独立二进制docker-compose:
apt update
apt install docker-compose
安装完成后,用docker-compose --version验证,输出版本号即安装成功。
最终效果
执行docker-compose up -d,成功拉取镜像、启动容器。
问题2:Go客户端连接报错:client has run out of available brokers to talk to
现象
使用Go语言sarama客户端编写的初始化代码,连接服务器Kafka时,报错:
初始化Kafka客户端失败: 连接Kafka失败: kafka: client has run out of available brokers to talk to (Is your cluster reachable?)
原始代码核心配置如下:
var defaultKafkaConfig = &KafkaConfig{
Brokers: []string{"【你的服务器公网IP】:9092"},
Version: "0.10.2.0",
}
排查思路
Kafka客户端报这个错误,核心原因只有3类,按优先级排查:
- 网络链路不通,客户端根本无法到达服务器的9092端口
- Kafka服务端配置错误,监听器/公布地址配置不当
- 客户端配置错误,比如缺少认证配置、协议不匹配
我们先从最基础的网络链路开始排查,这是最容易被忽略的点。
问题3:本地端口连通性测试失败,Ping服务器正常
现象
在本地Windows电脑的PowerShell中,执行端口连通性测试命令:
Test-NetConnection 【你的服务器公网IP】 -Port 9092
输出结果:
警告: TCP connect to (【你的服务器公网IP】 : 9092) failed
PingSucceeded: True
TcpTestSucceeded: False
可以Ping通服务器IP,说明三层网络正常,但TCP端口连接失败,说明四层端口被拦截。
排查步骤1:验证服务器本地端口是否正常监听
登录服务器,执行命令查看9092端口的监听状态:
netstat -tlnp | grep 9092
输出结果:
tcp 0 0 0.0.0.0:9092 0.0.0.0:* LISTEN 943/dockerd
这个结果说明:
- 9092端口正在监听
0.0.0.0(所有网卡,包括公网网卡) - 端口由Docker守护进程正常转发,Kafka容器的端口映射完全正常
- 服务端本身没有问题,问题出在服务器外部的网络访问拦截
排查步骤2:定位拦截点
Ping通、TCP不通,99%的原因是云服务器的安全组/防火墙没有放行9092端口。
云服务器默认只放行22(SSH)、3389(远程桌面)等基础端口,自定义的9092端口会被默认拦截,外部流量无法进入。
解决方法
针对的是华为云(其他的云服务器厂商设置端口规则,大同小异)
- 登录云服务器控制台,进入实例的「更多」→「网络/安全组」→「安全组规则配置」
- 进入入方向规则页面,点击「添加入方向规则」,按以下配置填写:
- 优先级:1
- 策略:允许
- 类型:IPv4
- 协议端口:自定义TCP,端口号9092
- 源地址:0.0.0.0/0(测试用,生产环境建议改为本地公网IP,更安全)
- 描述:Kafka外网访问端口
- 点击确定保存,等待1-3分钟规则生效。


最终效果
再次在本地执行端口测试命令:
Test-NetConnection 【你的服务器公网IP】 -Port 9092
输出TcpTestSucceeded: True,端口连通性问题彻底解决。
问题4:端口通了,Go客户端还是连接失败
现象
端口已经可以正常连通,但执行Go代码还是报同样的连接错误。
根因定位
经过排查,原始代码有2个致命错误,完全匹配不上服务端的配置:
- 缺少SASL认证配置:服务端外网9092端口强制账号密码认证,代码里完全没有开启SASL、配置账号密码
- 缺少安全协议配置:没有指定
SASL_PLAINTEXT安全协议,客户端用默认的明文协议连接,和服务端不匹配
(注:Kafka版本是向下兼容的,代码里的0.10.2.0可以正常连接服务端的2.3.0,无需修改版本号)
解决方法:修正后的完整Go代码
package main
import (
"fmt"
"sync"
"github.com/Shopify/sarama"
)
var (
KafkaClient sarama.Client
KafkaProducer sarama.SyncProducer
kafkaLock sync.Mutex
)
// KafkaConfig 配置结构体
type KafkaConfig struct {
Brokers []string
Version string
}
// 正确配置:和服务端地址、认证完全匹配
var defaultKafkaConfig = &KafkaConfig{
Brokers: []string{"【你的服务器公网IP】:9092"},
Version: "0.10.2.0", // Kafka版本向下兼容,无需修改
}
// createKafkaConfig 创建带认证的Kafka配置
func createKafkaConfig() (*sarama.Config, error) {
config := sarama.NewConfig()
// 配置Kafka版本
version, err := sarama.ParseKafkaVersion(defaultKafkaConfig.Version)
if err != nil {
return nil, err
}
config.Version = version
// 开启SASL账号密码认证,和服务端配置一致
config.Net.SASL.Enable = true
config.Net.SASL.User = "【管理员账号】" // 服务端配置的账号
config.Net.SASL.Password = "【管理员密码】" // 服务端配置的密码
config.Net.SASL.Mechanism = sarama.SASLTypePlaintext
// 生产者必填配置:开启成功/错误返回
config.Producer.Return.Successes = true
config.Producer.Return.Errors = true
return config, nil
}
// InitKafkaClient 初始化Kafka客户端和生产者
func InitKafkaClient() error {
kafkaLock.Lock()
defer kafkaLock.Unlock()
// 单例判断:如果客户端已存在且未关闭,直接返回
if KafkaClient != nil && !KafkaClient.Closed() {
return nil
}
// 创建配置
config, err := createKafkaConfig()
if err != nil {
return fmt.Errorf("创建Kafka配置失败: %w", err)
}
brokers := defaultKafkaConfig.Brokers
fmt.Printf("尝试连接到Kafka brokers: %v\n", brokers)
// 创建客户端
client, err := sarama.NewClient(brokers, config)
if err != nil {
return fmt.Errorf("连接Kafka失败: %w", err)
}
// 创建同步生产者
producer, err := sarama.NewSyncProducerFromClient(client)
if err != nil {
client.Close()
return fmt.Errorf("创建生产者失败: %w", err)
}
// 赋值全局变量
KafkaClient = client
KafkaProducer = producer
fmt.Println("✅ Kafka 连接成功!")
return nil
}
func main() {
// 初始化Kafka
err := InitKafkaClient()
if err != nil {
panic(fmt.Sprintf("Kafka初始化失败: %v", err))
}
// 测试发送消息
partition, offset, err := KafkaProducer.SendMessage(&sarama.ProducerMessage{
Topic: "test-topic",
Value: sarama.StringEncoder("Hello Kafka! 测试环境部署成功"),
})
if err != nil {
panic(fmt.Sprintf("发送消息失败: %v", err))
}
fmt.Printf("消息发送成功!partition: %d, offset: %d\n", partition, offset)
}
最终效果
执行代码,成功输出:
尝试连接到Kafka brokers: [【你的服务器公网IP】:9092]
✅ Kafka 连接成功!
消息发送成功!partition: 0, offset: 0
同时访问http://【你的服务器公网IP】:9000,可以通过Kafdrop面板看到创建的Topic和发送的消息,全链路部署成功。
四、零运维基础部署避坑总结
作为一名不懂运维的Go开发,本次部署踩了很多坑,这里总结5条核心避坑原则:
- 端口连通性优先排查:遇到客户端连接问题,先测端口通不通,再排查服务端和客户端配置,90%的问题都出在网络层面。
- Kafka监听器配置是核心:
LISTENERS是Kafka监听的地址,ADVERTISED_LISTENERS是对外公布的地址,必须填客户端能访问到的IP/域名,这是Kafka最容易踩的坑。 - 安全组/防火墙配置前置:部署前先规划好需要开放的端口,提前在安全组放行,避免部署完才发现网络不通。
- 目录创建注意当前路径:执行
mkdir命令前,确保已进入正确的目标目录(如/opt/docker/kafka),避免目录结构创建错误。 - Docker和Docker Compose是两个东西:裸服务器只装Docker是不够的,还需要单独安装Docker Compose编排工具。
更多推荐

所有评论(0)