3. 开发环境搭建:Docker Compose 一键部署、Flink 集群配置、Kafka 安装与 Topic 创建、Doris 建表与 Redis 配置
说实话,搭建开发环境这件事,看着简单,但坑是真不少。我见过太多团队,项目还没开始跑,光环境就折腾了两三天。所以这一章,咱们直接上 Docker Compose,把 Flink、Kafka、Doris、Redis 一次性搞定。
你想想看,如果每个组件都手动装一遍,版本冲突、端口占用、配置遗漏……光是排查这些问题就够你喝一壶的。我个人习惯,只要是本地开发环境,能容器化就容器化。干净、可复现、一键销毁,这才是现代开发该有的样子。
本章核心目标:用 Docker Compose 在本地拉起一套完整的实时指标平台开发环境,包含 Flink 集群(1 JobManager + 2 TaskManager)、Kafka(含 Zookeeper)、Doris(FE + BE)和 Redis。
3.1 Docker Compose 一键部署
我们先从 docker-compose.yml 开始。这个文件是整个环境的「总开关」。我习惯把每个服务拆成一个独立的 service 块,方便后续单独启停。
下面是我整理好的配置,你直接复制就能用。注意版本号,我选的都是经过生产验证的稳定版本。
version: '3.8'
services:
# ========== Zookeeper ==========
zookeeper:
image: confluentinc/cp-zookeeper:7.4.0
hostname: zookeeper
container_name: zookeeper
ports:
- "2181:2181"
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
networks:
- realtime-net
# ========== Kafka ==========
kafka:
image: confluentinc/cp-kafka:7.4.0
hostname: kafka
container_name: kafka
depends_on:
- zookeeper
ports:
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
networks:
- realtime-net
# ========== Flink JobManager ==========
flink-jobmanager:
image: flink:1.17.1-scala_2.12
hostname: flink-jobmanager
container_name: flink-jobmanager
ports:
- "8081:8081"
command: jobmanager
environment:
- JOB_MANAGER_RPC_ADDRESS=flink-jobmanager
networks:
- realtime-net
# ========== Flink TaskManager ==========
flink-taskmanager-1:
image: flink:1.17.1-scala_2.12
hostname: flink-taskmanager-1
container_name: flink-taskmanager-1
depends_on:
- flink-jobmanager
command: taskmanager
environment:
- JOB_MANAGER_RPC_ADDRESS=flink-jobmanager
- TASK_MANAGER_NUMBER_OF_TASK_SLOTS=4
networks:
- realtime-net
flink-taskmanager-2:
image: flink:1.17.1-scala_2.12
hostname: flink-taskmanager-2
container_name: flink-taskmanager-2
depends_on:
- flink-jobmanager
command: taskmanager
environment:
- JOB_MANAGER_RPC_ADDRESS=flink-jobmanager
- TASK_MANAGER_NUMBER_OF_TASK_SLOTS=4
networks:
- realtime-net
# ========== Doris FE ==========
doris-fe:
image: apache/doris:2.0.3-fe
hostname: doris-fe
container_name: doris-fe
ports:
- "8030:8030"
- "9030:9030"
environment:
- FE_ROLE=leader
networks:
- realtime-net
# ========== Doris BE ==========
doris-be:
image: apache/doris:2.0.3-be
hostname: doris-be
container_name: doris-be
depends_on:
- doris-fe
ports:
- "8040:8040"
environment:
- FE_MASTER_HOST=doris-fe
- FE_MASTER_PORT=9010
networks:
- realtime-net
# ========== Redis ==========
redis:
image: redis:7.2.3
hostname: redis
container_name: redis
ports:
- "6379:6379"
command: redis-server --requirepass realtime123
networks:
- realtime-net
networks:
realtime-net:
driver: bridge
我的经验:Kafka 的 ADVERTISED_LISTENERS 一定要配成 localhost:9092,否则你在宿主机上用客户端连 Kafka 会报连接超时。这个坑我踩过两次,第一次排查了半小时才发现是地址没配对。
配置写好了,启动就一句话:
docker compose up -d
等个一两分钟,所有容器都起来后,用 docker ps 检查一下。你应该能看到 8 个容器都在运行状态。
3.2 Flink 集群配置
Flink 集群启动后,访问 http://localhost:8081 就能看到 Web UI。我个人习惯先检查两个东西:TaskManager 数量和 Task Slot 总数。
默认配置下,我们有两个 TaskManager,每个 4 个 Slot,总共 8 个并发槽位。对于本地开发来说,完全够用了。
如果你想调整并行度,可以在 flink-conf.yaml 里改。但容器化环境下,我更推荐通过环境变量传参:
environment:
- TASK_MANAGER_NUMBER_OF_TASK_SLOTS=4
- JOB_MANAGER_RPC_ADDRESS=flink-jobmanager
注意:Flink 容器之间通过容器名通信,所以 JOB_MANAGER_RPC_ADDRESS 必须填 service 名称,不能填 localhost 或 127.0.0.1。否则 TaskManager 注册不上 JobManager。
3.3 Kafka 安装与 Topic 创建
Kafka 容器起来后,我们进到容器里创建 Topic。这个步骤我建议写成脚本,因为后面会反复用到。
先进入 Kafka 容器:
docker exec -it kafka bash
然后创建两个核心 Topic:
# 创建点击事件 Topic
kafka-topics --create \
--bootstrap-server localhost:9092 \
--replication-factor 1 \
--partitions 3 \
--topic click_events
# 创建订单流 Topic
kafka-topics --create \
--bootstrap-server localhost:9092 \
--replication-factor 1 \
--partitions 3 \
--topic order_flow
验证一下 Topic 是否创建成功:
kafka-topics --list --bootstrap-server localhost:9092
你应该能看到 click_events 和 order_flow 两个 Topic。
为什么分区数设 3? 分区数决定了 Kafka 的并行消费能力。本地开发设 3 个分区,既能模拟多分区场景,又不会太浪费资源。生产环境一般按业务流量估算,通常 6~12 个分区起步。
3.4 Doris 建表
Doris 的 FE 启动后,我们用 MySQL 客户端连上去。默认端口是 9030,用户名 root,密码为空。
mysql -h 127.0.0.1 -P 9030 -u root
连上之后,先建数据库,再建表。咱们这个平台核心是实时指标,所以表结构要支持高并发写入和快速聚合查询。
-- 创建数据库
CREATE DATABASE IF NOT EXISTS realtime_platform;
-- 使用数据库
USE realtime_platform;
-- 创建点击事件明细表
CREATE TABLE IF NOT EXISTS click_events (
event_id VARCHAR(64) NOT NULL,
user_id VARCHAR(32) NOT NULL,
page_url VARCHAR(512) NOT NULL,
click_time DATETIME NOT NULL,
event_type VARCHAR(32) NOT NULL,
duration_ms INT DEFAULT 0,
load_time DATETIME REPLACE_IF_NOT_NULL DEFAULT '1970-01-01 00:00:00'
)
ENGINE = OLAP
UNIQUE KEY(event_id, user_id)
DISTRIBUTED BY HASH(user_id) BUCKETS 10
PROPERTIES (
"replication_num" = "1",
"storage_medium" = "SSD"
);
关键点说明:
- UNIQUE KEY:保证同一事件不会重复写入,适合实时去重场景
- DISTRIBUTED BY HASH:按 user_id 分桶,查询时能快速定位到对应分片
- BUCKETS 10:本地开发 10 个桶够用,生产环境按数据量调整
- replication_num = 1:本地单副本,生产环境至少 3 副本
建完表后,用 SHOW TABLES; 确认一下。如果看到 click_events 表,说明 Doris 这边搞定了。
3.5 Redis 配置
Redis 我们用来做实时指标的缓存层。比如用户最近 5 分钟的点击次数、实时排行榜这些,直接从 Redis 读比查 Doris 快得多。
在 docker-compose.yml 里,我已经配了密码:realtime123。连接方式如下:
redis-cli -h 127.0.0.1 -p 6379 -a realtime123
验证一下连通性:
127.0.0.1:6379> PING
PONG
能返回 PONG,说明 Redis 跑起来了。
我的习惯:开发环境 Redis 密码设简单点没关系,但生产环境一定要用强密码,并且开启 TLS 加密。另外,建议把 maxmemory 设一个上限,防止 Redis 把宿主机内存吃光。
3.6 环境验证清单
所有组件都配好了,最后跑一遍验证清单,确保每个环节都没问题。
| 组件 | 验证方式 | 预期结果 |
|---|---|---|
| Docker 容器 | docker ps | wc -l |
8 个容器运行中 |
| Flink Web UI | 浏览器访问 localhost:8081 |
显示 2 个 TaskManager,8 个 Slot |
| Kafka Topic | kafka-topics --list |
显示 click_events, order_flow |
| Doris 建表 | SHOW TABLES; |
显示 click_events 表 |
| Redis 连通性 | PING |
返回 PONG |
到这步,你的开发环境就全部就绪了。接下来就可以开始写 Flink 作业,把数据从 Kafka 读到 Doris,再用 Redis 做实时缓存。嗯,这才是真正有意思的部分。