===================================
目录
背景与目标
在日志分析系统中,Nginx 日志通过 Filebeat 发送到 Kafka 集群,需部署一个长期运行的消费者程序,将日志解析后写入 MySQL 并缓存到 Redis。
为提升部署效率、避免环境依赖冲突,采用 Docker 容器化方案,实现:
- 服务开机自启(
--restart=always) - 网络直连宿主机(
--network host) - 代码更新后快速重建
项目结构
项目存放于 /opt/log_consumer/,目录结构如下:
/opt/log_consumer/
├── consumer.py # 主程序:Kafka消费 + MySQL写入 + Redis缓存
├── requirements.txt # Python依赖列表
└── Dockerfile # Docker镜像构建定义
关键配置文件
Dockerfile
使用官方 python:3.9-slim 镜像,轻量且兼容性好:
# 使用轻量 Python 镜像
FROM python:3.9-slim
# 设置工作目录
WORKDIR /app
# 复制依赖文件
COPY requirements.txt .
# 安装 Python 依赖(禁用缓存确保干净构建)
RUN pip install --no-cache-dir -r requirements.txt
# 复制主程序
COPY consumer.py .
# 启动命令
CMD ["python", "consumer.py"]
requirements.txt
指定项目所需Python依赖及固定版本,避免版本兼容问题:
kafka-python==2.0.2
PyMySQL==1.1.0
redis==5.0.1
consumer.py 注意事项
Kafka 消费者初始化时,必须使用集群主机名,不可用 localhost 或 127.0.0.1,否则容器内无法访问宿主机Kafka集群:
consumer = KafkaConsumer(
‘nginx-logs’,
bootstrap_servers=[“kafka1:9092”, “kafka2:9092”, “kafka3:9092”], # ← 关键!
auto_offset_reset=’latest’,
enable_auto_commit=True,
group_id=’log-consumer-group’
)
同时开发时需确保:
- 所有依赖库已正确导入
- 每行参数末尾加英文逗号
,(避免 SyntaxError 语法错误) - 异常处理完善(防止进程意外退出导致容器重启)
部署流程
清理旧容器
容器名称冲突是部署最常见错误,部署前务必先停止并删除旧容器,即使容器已停止,名称仍会被占用:
docker stop log-consumer 2>/dev/null && docker rm log-consumer 2>/dev/null
语法预检
提前校验Python代码语法,避免因语法错误导致容器启动后无限重启,无输出即表示语法正确:
cd /opt/log_consumer
python3 -m py_compile consumer.py
构建镜像
基于当前目录的Dockerfile构建自定义镜像,镜像命名为log-consumer:
docker build -t log-consumer .
构建成功后,可通过 docker images 命令查看本地镜像列表,确认log-consumer镜像已生成。
启动容器
使用host网络模式让容器共享宿主机网络,实现直连Kafka集群,同时开启开机自启和后台运行:
docker run -d
–network host
–name log-consumer
–restart=always
log-consumer
参数说明:
-d:后台运行容器--network host:容器共享宿主机网络,可直接访问kafka1:9092等地址--name log-consumer:指定容器唯一名称--restart=always:容器异常退出/宿主机重启后自动重启容器
验证运行状态
通过查看容器实时日志,验证消费者程序是否正常启动和运行:
docker logs -f log-consumer
启动成功标志(程序输出类似内容):
启动Kafka日志消费者
OK MySQL连接成功
OK Redis连接成功
OK Kafka消费者创建成功
TARGET 开始监听日志...

也可通过前台运行方式直接验证(运行后按Ctrl+C停止):
docker run -it –network host –rm log-consumer
常见问题排查
容器不断重启
现象
执行docker ps查看容器状态,显示log-consumer容器状态为Restarting。
原因
程序启动后立即退出,核心原因包括代码语法错误、数据库/Redis/Kafka连接失败、依赖缺失等。
解决
# 先停止异常重启的容器
docker stop log-consumer
# 前台运行容器,直接查看控制台报错信息(关键排查步骤)
docker run -it --network host --rm log-consumer
# 根据前台输出的具体报错信息修复代码/环境问题后,重新构建启动
Kafka 连接失败(NoBrokersAvailable)
现象
容器日志中报错kafka.errors.NoBrokersAvailable,无法连接Kafka集群。
原因
bootstrap_servers配置为localhost:9092/127.0.0.1:9092,容器内无法解析- Kafka 服务未监听外网/宿主机IP,仅监听localhost
- 宿主机防火墙/安全组阻断9092端口
- 主机名(kafka1/kafka2/kafka3)未做DNS解析或
/etc/hosts映射
解决
# 1. 修正consumer.py中bootstrap_servers为集群主机名
# 2. 在宿主机测试Kafka端口连通性
telnet kafka1 9092
# 3. 确保宿主机/etc/hosts已配置Kafka主机名与IP的映射
# 4. 开放防火墙9092端口(如需要)
firewall-cmd --add-port=9092/tcp --permanent
firewall-cmd --reload
Python 语法错误
现象
容器日志报错SyntaxError: invalid syntax,但报错行代码看似无语法问题。
原因
- 上一行代码参数末尾缺少英文逗号(最常见原因)
- 代码中混入中文标点(如中文逗号、括号)
- 代码文件含BOM头或Windows格式的CRLF换行符
- 多行参数缩进不一致
典型错误示例(kafka3:9092末尾缺少逗号,导致代码行合并):
consumer = KafkaConsumer(
bootstrap_servers = [“kafka1:9092”, “kafka2:9092”, “kafka3:9092”]
‘nginx-logs’,
auto_offset_reset=’latest’,
enable_auto_commit=True,
group_id=’log-consumer-group’,
session_timeout_ms=30000,
heartbeat_interval_ms=10000
)
解决
# 1. 检查代码中的隐藏字符和格式问题
cat -A consumer.py
# 2. 再次用官方工具预检语法
python3 -m py_compile consumer.py
# 3. 手动重写可疑代码行,确保使用英文标点、缩进一致
# 4. 将文件转换为Linux换行格式(LF)
sed -i 's/\r$//' consumer.py
一键重启脚本
编写Shell脚本实现停止旧容器-删除旧容器-构建新镜像-启动新容器的一键化操作,简化代码更新后的部署流程:
#!/bin/bash
cd /opt/log_consumer
# 停旧容器,忽略容器不存在的错误
docker stop log-consumer 2>/dev/null
# 删除旧容器,忽略容器不存在的错误
docker rm log-consumer 2>/dev/null
# 构建新镜像
docker build -t log-consumer .
# 启动新容器
docker run -d --network host --name log-consumer --restart=always log-consumer
# 部署成功提示
echo "✅ 消费者容器已一键重启,查看实时日志:docker logs -f log-consumer"
脚本使用方式
# 给脚本添加执行权限
chmod +x restart_consumer.sh
# 执行一键重启
./restart_consumer.sh
总结
通过Docker容器化改造Kafka消费者程序,为日志监控系统带来了四大核心价值:
- 环境隔离:Python依赖库仅存在于容器内,不污染宿主机环境,避免多项目依赖冲突
- 快速部署:仅需6条核心命令即可完成从0到1的部署,新人可快速上手
- 高可用保障:通过
--restart=always实现容器异常自动重启,提升服务稳定性 - 部署标准化:任何人拿到项目代码和Dockerfile,均可在任意安装Docker的机器上一键运行
运行环境:CentOS 7 + Docker 24.0 + Kafka 3.3