topfans/docker/build.sh
Lenticular Studio Agent 65ce6bba12 feat: Dify 部署脚本修复 + AI 搭子 MVP 接入
主要改动:

fix(docker/dify-deploy): 修复脚本核心功能
- heredoc 单引号 bug: 'ENVEOF' 改为 ENVEOF,变量正确展开
- 端口默认值 8083/8084/8085 对齐 .env.prod 生产配置
- 加 dc_cmd() 兼容 docker-compose v1/v2 plugin
- openssl rand 生成强随机密码与 SECRET_KEY(42 字符)
- install 跳过已存在 .env,保护用户配置(管理员密码/SECRET_KEY)
- read -p < /dev/tty 兼容非 tty 环境(CI/CD)
- show-config 改用 DIFY_NGINX_PORT(nginx 入口)而非 APP_WEB_PORT

docs(mvp-design): 修正 §3.2 workflow inputs 描述
- 实际只有 query,删除错误的 user_id input 声明
- 节点序列图同步更新

feat(aiChatService): 新增 Dify 客户端与适配器
- service/dify_client.go: Dify Workflow 调用 + SSE 解析
- service/dify_adapter.go: 与现有 chat_service 桥接
- provider/ai_chat_provider.go: Dubbo 入口简化
- main.go: 装配 ConversationRepository + DifyClient

feat(migrations): 新增 AI 搭子会话表 ai_chat.sql
- ai_conversations / ai_messages 表 + 索引

docs: 新增 Dify 集成设计文档
- 2026-06-29-ai-chat-dify-mvp-design.md (MVP 实施级)
- 2026-06-29-ai-chat-dify-integration-v2-design.md (V2 演进路线图)
- docs/dify/角角.yml (Workflow DSL 导出)

config: 更新 env 模板与 docker 配置
- backend/.env.example: DIFY_* 环境变量声明
- docker/.env.prod: DIFY_API_BASE 对齐 8083
- docker/build.sh: 微调
- CLAUDE.md: 项目规范补充

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-02 12:32:34 +08:00

282 lines
10 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# ===================================================================
# TopFans Docker 一键构建脚本
# 功能:编译并打包所有后端服务为 Docker 镜像
# ===================================================================
#
# 使用方式:
# ./build.sh # 构建所有服务(默认)
# ./build.sh --no-cache # 无缓存构建
# ./build.sh gateway # 仅构建 Gateway
# ./build.sh userService # 仅构建 UserService
# ./build.sh prod # 使用生产配置构建
#
# 示例:
# ./build.sh # 构建所有服务
# ./build.sh --no-cache # 清除缓存重新构建
# ./build.sh gateway userService # 仅构建指定服务
# ===================================================================
set -e # 遇到错误立即退出
# ==================== 颜色定义 ====================
# 用于终端输出彩色文字,提升可读性
RED='\033[0;31m' # 红色 - 错误信息
GREEN='\033[0;32m' # 绿色 - 成功信息
YELLOW='\033[1;33m' # 黄色 - 警告/进度信息
BLUE='\033[0;34m' # 蓝色 - 标题信息
NC='\033[0m' # 重置颜色
# ==================== 路径配置 ====================
# 获取脚本所在目录(支持从任意目录调用)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# ==================== 构建配置 ====================
# 镜像前缀,用于标记和组织镜像(必须小写)
IMAGE_PREFIX="topfans"
# Dockerfile 路径
DOCKERFILE="Dockerfile.services"
# 目标架构amd64 适用于大多数服务器)
TARGET_ARCH="linux/amd64"
# ==================== 默认设置 ====================
# 是否使用缓存(默认使用,构建更快)
NO_CACHE=""
# 构建配置文件local 或 prod
PROFILE="local"
# 要构建的服务列表(留空则构建全部)
SERVICES=()
# ==================== 解析命令行参数 ====================
# 支持多种使用方式
# --no-cache: 清除 Docker 缓存,强制重新构建
# --profile prod: 使用生产配置
# 服务名: 仅构建指定服务(如 gateway, userService 等)
while [[ $# -gt 0 ]]; do
case $1 in
--no-cache)
# 启用无缓存构建,适用于代码更新后确保完全重新编译
NO_CACHE="--no-cache"
echo -e "${YELLOW}警告: 无缓存模式,构建时间较长${NC}"
shift
;;
--profile)
# 指定构建配置local 或 prod
PROFILE="$2"
shift 2
;;
--help|-h)
# 显示帮助信息
echo "用法: $0 [选项] [服务名...]"
echo ""
echo "选项:"
echo " --no-cache 不使用 Docker 缓存,强制重新构建"
echo " --profile <env> 使用配置文件 (local/prod),默认 local"
echo " --help, -h 显示此帮助信息"
echo ""
echo "服务名 (可选):"
echo " gateway, userService, socialService, assetService,"
echo " galleryService, activityService, taskService, starbookService, aiChatService,"
echo " statisticService"
echo " notificationService, moderationService"
echo ""
echo "示例:"
echo " $0 # 构建所有服务"
echo " $0 --no-cache # 无缓存构建所有服务"
echo " $0 gateway # 仅构建 Gateway"
echo " $0 --profile prod # 使用生产配置构建"
exit 0
;;
*)
# 未知参数,假设是服务名
# 支持的服务名映射(别名 -> 实际 target 名)
case $1 in
gateway) SERVICES+=("gateway") ;;
user|userService) SERVICES+=("userService") ;;
social|socialService) SERVICES+=("socialService") ;;
asset|assetService) SERVICES+=("assetService") ;;
gallery|galleryService) SERVICES+=("galleryService") ;;
activity|activityService) SERVICES+=("activityService") ;;
task|taskService) SERVICES+=("taskService") ;;
starbook|starbookService) SERVICES+=("starbookService") ;;
ai|aiChatService|aichatservice) SERVICES+=("aiChatService") ;;
statistic|statisticService|statisticservice) SERVICES+=("statisticservice") ;;
notification|notificationService|notificationservice) SERVICES+=("notificationservice") ;;
moderation|moderationService|moderationservice) SERVICES+=("moderationservice") ;;
oss-cors-init|osS-cors-init|ossCorsInit) SERVICES+=("oss-cors-init") ;;
all)
# all 关键字,构建所有服务
SERVICES=()
break
;;
*)
echo -e "${RED}错误: 未知服务 '$1'${NC}"
echo "使用 --help 查看可用服务列表"
exit 1
;;
esac
shift
;;
esac
done
# ==================== 服务列表 ====================
# 所有可用服务及其配置(使用小写 target 名)
ALL_SERVICES_NAME=("gateway" "userservice" "socialservice" "assetservice" "galleryservice" "activityservice" "taskservice" "starbookservice" "aichatservice" "statisticservice" "notificationservice" "moderationservice" "oss-cors-init")
# 确定要构建的服务
if [ ${#SERVICES[@]} -eq 0 ]; then
# 未指定服务,构建全部
SERVICE_NAMES=("${ALL_SERVICES_NAME[@]}")
else
SERVICE_NAMES=("${SERVICES[@]}")
fi
# ==================== 构建函数 ====================
# 打印分隔线
print_line() {
echo -e "${BLUE}========================================${NC}"
}
# 打印带颜色的消息
print_msg() {
local color=$1
local msg=$2
echo -e "${color}${msg}${NC}"
}
# 构建单个服务的镜像
# 参数: service_name docker_target
build_service() {
local service_name=$1
local docker_target=$2
echo -e "\n${YELLOW}正在构建 ${service_name}...${NC}"
# 检查 Dockerfile 是否存在
if [ ! -f "$DOCKERFILE" ]; then
echo -e "${RED}错误: Dockerfile ($DOCKERFILE) 不存在${NC}"
return 1
fi
# 构建镜像
# 镜像命名: topfans/gateway:latest, topfans/userService:latest 等
# -f: 指定 Dockerfile
# --target: 指定构建阶段(对应 Dockerfile 中的 AS xxx
# --platform: 指定目标平台
# $NO_CACHE: 是否使用缓存
docker build \
$NO_CACHE \
-f "$DOCKERFILE" \
--target "$docker_target" \
--platform "$TARGET_ARCH" \
-t "${IMAGE_PREFIX}/${docker_target}:latest" \
../
if [ $? -eq 0 ]; then
print_msg "$GREEN" "${service_name} 构建成功"
return 0
else
print_msg "$RED" "${service_name} 构建失败"
return 1
fi
}
# ==================== 主构建流程 ====================
main() {
print_line
print_msg "$BLUE" " TopFans Docker 构建脚本"
print_msg "$BLUE" " 配置: ${PROFILE}"
print_msg "$BLUE" " 架构: ${TARGET_ARCH}"
print_line
# 记录开始时间
START_TIME=$(date +%s)
# 统计构建结果
SUCCESS_COUNT=0
FAIL_COUNT=0
# 构建每个服务
for service in "${SERVICE_NAMES[@]}"; do
# 服务名到 target 的映射(统一使用小写 target
case $service in
gateway) docker_target="gateway" ;;
userservice) docker_target="userservice" ;;
socialservice) docker_target="socialservice" ;;
assetservice) docker_target="assetservice" ;;
galleryservice) docker_target="galleryservice" ;;
activityservice) docker_target="activityservice" ;;
taskservice) docker_target="taskservice" ;;
starbookservice) docker_target="starbookservice" ;;
aichatservice) docker_target="aichatservice" ;;
statisticservice) docker_target="statisticservice" ;;
notificationservice) docker_target="notificationservice" ;;
moderationservice) docker_target="moderationservice" ;;
oss-cors-init) docker_target="oss-cors-init" ;;
# 兼容旧的大写服务名
userService) docker_target="userservice" ;;
socialService) docker_target="socialservice" ;;
assetService) docker_target="assetservice" ;;
galleryService) docker_target="galleryservice" ;;
activityService) docker_target="activityservice" ;;
taskService) docker_target="taskservice" ;;
starbookService) docker_target="starbookservice" ;;
statisticService) docker_target="statisticservice" ;;
statisticservice) docker_target="statisticservice" ;;
notificationService) docker_target="notificationservice" ;;
moderationService) docker_target="moderationservice" ;;
ossCorsInit) docker_target="oss-cors-init" ;;
*) docker_target="$service" ;;
esac
if build_service "$service" "$docker_target"; then
((SUCCESS_COUNT++))
else
((FAIL_COUNT++))
fi
done
# ==================== 构建结果 ====================
print_line
print_msg "$BLUE" " 构建完成"
# 计算耗时
END_TIME=$(date +%s)
ELAPSED=$((END_TIME - START_TIME))
MINUTES=$((ELAPSED / 60))
SECONDS=$((ELAPSED % 60))
echo ""
print_msg "$GREEN" "✅ 成功: ${SUCCESS_COUNT} 个服务"
if [ $FAIL_COUNT -gt 0 ]; then
print_msg "$RED" "❌ 失败: ${FAIL_COUNT} 个服务"
fi
echo -e "${YELLOW}⏱ 耗时: ${MINUTES}${SECONDS}${NC}"
print_line
# 显示构建的镜像
echo ""
print_msg "$BLUE" "构建的镜像列表:"
echo ""
for service in "${SERVICE_NAMES[@]}"; do
# 获取镜像大小
SIZE=$(docker images "${IMAGE_PREFIX}/${service}:latest" --format "{{.Size}}" 2>/dev/null || echo "未知")
echo -e " ${GREEN}${IMAGE_PREFIX}/${service}:latest${NC} (${SIZE})"
done
echo ""
print_msg "$GREEN" "🎉 构建完成!"
echo ""
echo "下一步:"
echo " 启动服务 (本地): docker-compose -f docker-compose.local.yml --profile local up -d"
echo " 启动服务 (生产): docker-compose -f docker-compose.prod.yml --profile prod up -d"
echo ""
}
# 执行主函数
main