228 lines
9.5 KiB
Bash
Executable File
228 lines
9.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# =============================================================================
|
||
# 03-start-infra.sh — 启动 Docker 基础设施(Redis / Kafka / Etcd / LiveKit)
|
||
#
|
||
# 数据目录: .local-dev/docker-data/<svc>/
|
||
# 容器日志: .local-dev/docker-logs/<svc>/<svc>-YYYYMMDD.log(每日一文件)
|
||
# 脚本日志: .local-dev/script-logs/03-start-infra-<ts>.log
|
||
#
|
||
# 后续步骤:04-build.sh(编译后端服务)
|
||
# =============================================================================
|
||
set -euo pipefail
|
||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh"
|
||
load_env
|
||
init_dirs
|
||
init_script_log # ← 脚本执行日志
|
||
require_docker_running
|
||
|
||
# Docker 日志驱动公共参数(JSON 文件,最多 5 个 50MB 轮转)
|
||
LOG_OPTS=(
|
||
--log-driver json-file
|
||
--log-opt max-size=50m
|
||
--log-opt max-file=5
|
||
)
|
||
|
||
header "步骤 3 / 5 — 启动 Docker 基础设施"
|
||
|
||
# ──────────────────────────────────────────────────────────────────────────────
|
||
# Redis
|
||
# ──────────────────────────────────────────────────────────────────────────────
|
||
step "Redis"
|
||
|
||
if docker ps --format '{{.Names}}' | grep -q '^dev-redis$'; then
|
||
success "Redis 已在运行 (container=dev-redis) :${REDIS_PORT}"
|
||
elif docker ps -a --format '{{.Names}}' | grep -q '^dev-redis$'; then
|
||
info "重新启动已有容器 dev-redis..."
|
||
docker start dev-redis > /dev/null
|
||
success "Redis 已启动 :${REDIS_PORT}"
|
||
else
|
||
info "创建并启动 Redis 容器..."
|
||
docker run -d \
|
||
--name dev-redis \
|
||
--restart unless-stopped \
|
||
-p "${REDIS_PORT}:6379" \
|
||
-v "${DATA_DIR}/redis:/data" \
|
||
"${LOG_OPTS[@]}" \
|
||
redis:7-alpine \
|
||
redis-server --requirepass "${REDIS_PASSWORD:-openIM123}" --appendonly yes \
|
||
> /dev/null
|
||
success "Redis 容器已创建并启动 :${REDIS_PORT} (密码: ${REDIS_PASSWORD:-openIM123})"
|
||
fi
|
||
|
||
sleep 1
|
||
if docker exec dev-redis redis-cli -a "${REDIS_PASSWORD:-openIM123}" ping 2>/dev/null | grep -q PONG; then
|
||
success "Redis 连通性: PONG ✓"
|
||
else
|
||
warn "Redis 未响应 PING,请查看日志: ./deploy-test/logs.sh redis"
|
||
fi
|
||
start_docker_logger "dev-redis"
|
||
|
||
# ──────────────────────────────────────────────────────────────────────────────
|
||
# Kafka(KRaft 模式)
|
||
# ──────────────────────────────────────────────────────────────────────────────
|
||
step "Kafka (KRaft)"
|
||
|
||
if docker ps --format '{{.Names}}' | grep -q '^dev-kafka$'; then
|
||
success "Kafka 已在运行 (container=dev-kafka) :${KAFKA_PORT}"
|
||
elif docker ps -a --format '{{.Names}}' | grep -q '^dev-kafka$'; then
|
||
info "重新启动已有容器 dev-kafka..."
|
||
docker start dev-kafka > /dev/null
|
||
info "等待 Kafka 就绪 (8s)..."
|
||
sleep 8
|
||
success "Kafka 已启动 :${KAFKA_PORT}"
|
||
else
|
||
info "创建并启动 Kafka 容器(首次拉取镜像可能较慢)..."
|
||
KAFKA_CLUSTER_ID="MkU3OEVBNTcwNTJENDM2Qk"
|
||
|
||
docker run -d \
|
||
--name dev-kafka \
|
||
--restart unless-stopped \
|
||
-p "${KAFKA_PORT}:9092" \
|
||
-v "${DATA_DIR}/kafka:/bitnami/kafka" \
|
||
-e KAFKA_CFG_NODE_ID=0 \
|
||
-e KAFKA_CFG_PROCESS_ROLES=controller,broker \
|
||
-e KAFKA_CFG_LISTENERS="PLAINTEXT://:9092,CONTROLLER://:9093" \
|
||
-e KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP="CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT" \
|
||
-e KAFKA_CFG_CONTROLLER_QUORUM_VOTERS="0@localhost:9093" \
|
||
-e KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER \
|
||
-e KAFKA_CFG_ADVERTISED_LISTENERS="PLAINTEXT://127.0.0.1:${KAFKA_PORT}" \
|
||
-e KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE=true \
|
||
-e KAFKA_KRAFT_CLUSTER_ID="$KAFKA_CLUSTER_ID" \
|
||
"${LOG_OPTS[@]}" \
|
||
bitnami/kafka:3.7 \
|
||
> /dev/null
|
||
|
||
info "等待 Kafka 就绪 (15s)..."
|
||
sleep 15
|
||
success "Kafka 容器已创建并启动 :${KAFKA_PORT}"
|
||
fi
|
||
start_docker_logger "dev-kafka"
|
||
|
||
# 初始化必要 Topics
|
||
step "Kafka Topics 初始化"
|
||
TOPICS=(toRedis toMongo toPush toOfflinePush)
|
||
for topic in "${TOPICS[@]}"; do
|
||
if docker exec dev-kafka kafka-topics.sh \
|
||
--bootstrap-server localhost:9092 \
|
||
--list 2>/dev/null | grep -q "^${topic}$"; then
|
||
info " topic 已存在: $topic"
|
||
else
|
||
docker exec dev-kafka kafka-topics.sh \
|
||
--create \
|
||
--topic "$topic" \
|
||
--bootstrap-server localhost:9092 \
|
||
--partitions 8 \
|
||
--replication-factor 1 \
|
||
2>/dev/null \
|
||
&& success " ✓ 创建 topic: $topic" \
|
||
|| warn " ✗ 创建失败: $topic(Kafka 未就绪,重试: ./deploy-test/03-start-infra.sh)"
|
||
fi
|
||
done
|
||
|
||
# ──────────────────────────────────────────────────────────────────────────────
|
||
# Etcd
|
||
# ──────────────────────────────────────────────────────────────────────────────
|
||
step "Etcd"
|
||
|
||
if docker ps --format '{{.Names}}' | grep -q '^dev-etcd$'; then
|
||
success "Etcd 已在运行 (container=dev-etcd) :${ETCD_PORT}"
|
||
elif docker ps -a --format '{{.Names}}' | grep -q '^dev-etcd$'; then
|
||
info "重新启动已有容器 dev-etcd..."
|
||
docker start dev-etcd > /dev/null
|
||
sleep 2
|
||
success "Etcd 已启动 :${ETCD_PORT}"
|
||
else
|
||
info "创建并启动 Etcd 容器..."
|
||
docker run -d \
|
||
--name dev-etcd \
|
||
--restart unless-stopped \
|
||
-p "${ETCD_PORT}:2379" \
|
||
-v "${DATA_DIR}/etcd:/etcd-data" \
|
||
-e ALLOW_NONE_AUTHENTICATION=yes \
|
||
-e ETCD_DATA_DIR=/etcd-data \
|
||
"${LOG_OPTS[@]}" \
|
||
bitnami/etcd:3.5 \
|
||
> /dev/null
|
||
sleep 2
|
||
success "Etcd 容器已创建并启动 :${ETCD_PORT}"
|
||
fi
|
||
|
||
if docker exec dev-etcd etcdctl endpoint health 2>/dev/null | grep -q 'is healthy'; then
|
||
success "Etcd 连通性: healthy ✓"
|
||
else
|
||
warn "Etcd 未返回健康状态,可能仍在启动中"
|
||
fi
|
||
start_docker_logger "dev-etcd"
|
||
|
||
# ──────────────────────────────────────────────────────────────────────────────
|
||
# LiveKit(本地 Docker 容器,复用 dev-redis)
|
||
# ──────────────────────────────────────────────────────────────────────────────
|
||
step "LiveKit"
|
||
|
||
LK_CONF="$ROOT_DIR/livekit/livekit.yaml"
|
||
|
||
if [[ ! -f "$LK_CONF" ]]; then
|
||
warn "livekit/livekit.yaml 不存在,请先执行: ./deploy-test/02-patch-config.sh"
|
||
else
|
||
if docker ps --format '{{.Names}}' | grep -q '^dev-livekit$'; then
|
||
success "LiveKit 已在运行 (container=dev-livekit) :7880"
|
||
elif docker ps -a --format '{{.Names}}' | grep -q '^dev-livekit$'; then
|
||
info "重新启动已有容器 dev-livekit..."
|
||
docker start dev-livekit > /dev/null
|
||
sleep 2
|
||
success "LiveKit 已启动 :7880"
|
||
else
|
||
info "创建并启动 LiveKit 容器(首次拉取镜像需要一点时间)..."
|
||
|
||
EXTRA_HOSTS=""
|
||
[[ "$(uname -s)" == "Linux" ]] && EXTRA_HOSTS="--add-host host.docker.internal:host-gateway"
|
||
|
||
# shellcheck disable=SC2086
|
||
docker run -d \
|
||
--name dev-livekit \
|
||
--restart unless-stopped \
|
||
-p 7880:7880 \
|
||
-p 7882:7882/tcp \
|
||
-p 7882:7882/udp \
|
||
-p 50000-51000:50000-51000/udp \
|
||
-v "${LK_CONF}:/etc/livekit.yaml:ro" \
|
||
"${LOG_OPTS[@]}" \
|
||
$EXTRA_HOSTS \
|
||
livekit/livekit-server:latest \
|
||
--config /etc/livekit.yaml \
|
||
> /dev/null
|
||
|
||
sleep 3
|
||
if docker ps --format '{{.Names}}' | grep -q '^dev-livekit$'; then
|
||
success "LiveKit 容器已创建并启动 :7880"
|
||
info " 公网 IP: ${LIVEKIT_NODE_IP} (WebRTC 媒体流直连)"
|
||
info " API Key: ${LIVEKIT_API_KEY}"
|
||
else
|
||
error "LiveKit 启动失败,查看日志: ./deploy-test/logs.sh livekit"
|
||
fi
|
||
fi
|
||
start_docker_logger "dev-livekit"
|
||
fi
|
||
|
||
# ──────────────────────────────────────────────────────────────────────────────
|
||
# 汇总
|
||
# ──────────────────────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo -e "${BOLD}基础设施状态:${NC}"
|
||
print_container_status "Redis" "dev-redis" "${REDIS_PORT}"
|
||
print_container_status "Kafka" "dev-kafka" "${KAFKA_PORT}"
|
||
print_container_status "Etcd" "dev-etcd" "${ETCD_PORT}"
|
||
print_container_status "LiveKit" "dev-livekit" "7880"
|
||
echo ""
|
||
echo -e "${BOLD}日志目录:${NC}"
|
||
echo " Docker 容器日志: $DOCKER_LOG_DIR/"
|
||
echo " 本脚本执行日志: $_CURRENT_SCRIPT_LOG"
|
||
echo ""
|
||
echo -e " LiveKit 公网: ${LIVEKIT_NODE_IP}:50000-51000/udp (WebRTC 媒体流)"
|
||
echo ""
|
||
success "Docker 基础设施已就绪!"
|
||
echo ""
|
||
echo -e "${BOLD}下一步:${NC}"
|
||
echo -e " 编译所有后端 Go 服务:"
|
||
echo -e " ${CYAN}./deploy-test/04-build.sh${NC}"
|