复制项目

This commit is contained in:
kim.dev.6789
2026-01-14 22:16:44 +08:00
parent e2577b8cee
commit e50142a3b9
691 changed files with 97009 additions and 1 deletions

535
.gitea/workflows/build.yml Normal file
View File

@@ -0,0 +1,535 @@
name: OpenIM Server 构建和发布
on:
push:
branches: [ main, master, wallet, develop, release-* ]
paths:
- '**'
pull_request:
branches: [ main, master, wallet ]
paths:
- '**'
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: "Tag version to be used for Docker image"
required: true
default: "latest"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
REGISTRY: docker.io
DOCKER_USER: ${{ secrets.DOCKER_USERNAME || 'mag1666888' }}
GO_VERSION: "1.24"
jobs:
build-and-push:
runs-on: openim
permissions:
contents: read
packages: write
steps:
- name: 检出代码
uses: actions/checkout@v4
with:
submodules: recursive
- name: 配置 SSH 密钥
run: |
echo "🔑 配置 SSH 密钥..."
# 创建 .ssh 目录
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# 从 secrets 中获取 SSH 私钥并 base64 解码
echo "${{ secrets.SSH_PRIVATE_KEY }}" | base64 -d > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
# 配置 SSH 主机密钥验证(可选,避免首次连接时的确认提示)
ssh-keyscan -H git.imall.cloud >> ~/.ssh/known_hosts 2>/dev/null || true
chmod 644 ~/.ssh/known_hosts
# 验证 SSH 密钥
if [ -f ~/.ssh/id_rsa ]; then
echo "✅ SSH 密钥配置成功"
else
echo "❌ SSH 密钥配置失败"
exit 1
fi
- name: 检出 protocol 仓库
run: |
echo "📦 克隆 protocol 仓库..."
# 使用 SSH 方式克隆 protocol 仓库
git clone git@git.imall.cloud:openim/protocol.git ./protocol || true
cd ./protocol
git fetch --all
git checkout v1.0.4
cd ..
# 创建父目录的protocol符号链接使replace ../protocol 能正确找到
ln -sf $PWD/protocol ../protocol || true
echo "✅ protocol 仓库检出完成"
- name: 设置 Go 缓存
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: 设置 Go 环境
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: 检查 Go 环境
run: |
if command -v go &> /dev/null; then
echo "Go: $(go version)"
go mod verify >/dev/null 2>&1
go mod tidy >/dev/null 2>&1
go mod download >/dev/null 2>&1
echo "Go modules verified"
else
echo "Go not found, skipping Go steps"
fi
- name: 检查系统资源
run: |
echo "系统资源信息:"
echo "CPU核心数: $(nproc)"
echo "内存总量: $(free -h | awk '/^Mem:/ {print $2}')"
echo "可用内存: $(free -h | awk '/^Mem:/ {print $7}')"
echo "磁盘空间: $(df -h / | awk 'NR==2 {print $4}')"
echo ""
- name: 清理 Docker 环境
run: |
echo "清理Docker环境..."
docker image prune -f >/dev/null 2>&1 || true
- name: 登录到 Docker Hub
uses: docker/login-action@v3.3.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: 设置 Docker Buildx
uses: docker/setup-buildx-action@v3.8.0
with:
driver-opts: |
image=moby/buildkit:buildx-stable-1
network=host
- name: 构建和推送所有服务镜像
working-directory: ${{ github.workspace }}
run: |
# 设置错误处理
trap 'echo "脚本在行 $LINENO 处失败,退出状态: $?"' ERR
set -e
# 获取版本标签(使用分支名)
if [ "${{ github.event_name }}" = "release" ]; then
VERSION_TAG="${{ github.event.release.tag_name }}"
elif [ -n "${{ github.event.inputs.tag }}" ]; then
VERSION_TAG="${{ github.event.inputs.tag }}"
else
# 使用分支名作为标签
VERSION_TAG="${{ github.ref_name }}"
fi
echo "构建OpenIM Server镜像 (标签: $VERSION_TAG)"
echo "Docker用户: $DOCKER_USER"
# 定义构建顺序openim-msggateway 和 openim-push 优先构建)
CORE_SERVICES=(
"openim-msggateway"
"openim-push"
"openim-rpc-msg"
"openim-api"
"openim-msgtransfer"
"openim-crontask"
)
RPC_SERVICES=(
"openim-rpc-auth"
"openim-rpc-user"
"openim-rpc-friend"
"openim-rpc-group"
"openim-rpc-conversation"
"openim-rpc-third"
)
# 构建函数
build_service() {
local service=$1
local dockerfile="build/images/$service/Dockerfile"
local start_time=$(date +%s)
if [ -f "$dockerfile" ]; then
echo "📦 构建 $service..."
if docker buildx build \
--platform linux/amd64 \
--file "$dockerfile" \
--tag "$DOCKER_USER/$service:$VERSION_TAG" \
--tag "$DOCKER_USER/$service:prod" \
--push \
--progress=plain \
--cache-from type=gha,scope=openim-build-${{ github.ref_name }}-$service \
--cache-to type=gha,mode=max,scope=openim-build-${{ github.ref_name }}-$service \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--build-arg GOCACHE=/go-cache \
--build-arg GOMAXPROCS=$(nproc) \
--provenance=false \
--sbom=false \
. > "/tmp/build_${service}.log" 2>&1; then
local end_time=$(date +%s)
local duration=$((end_time - start_time))
echo "✅ $service 构建成功 (${duration}秒)"
else
echo "❌ $service 构建失败,查看详细错误日志:"
echo "=========================================="
cat "/tmp/build_${service}.log"
echo "=========================================="
echo "最后 50 行错误日志:"
tail -50 "/tmp/build_${service}.log"
return 1
fi
else
echo "❌ $service - 未找到 Dockerfile: $dockerfile"
return 1
fi
}
# 初始化构建统计
failed_services=()
successful_services=()
# 计算总服务数
total_services=$((${#CORE_SERVICES[@]} + ${#RPC_SERVICES[@]}))
echo "开始构建 $total_services 个服务..."
# 先构建核心服务
for service in "${CORE_SERVICES[@]}"; do
if build_service "$service"; then
successful_services+=("$service")
else
failed_services+=("$service")
fi
done
# 构建RPC服务
for service in "${RPC_SERVICES[@]}"; do
if build_service "$service"; then
successful_services+=("$service")
else
failed_services+=("$service")
fi
done
# 输出构建结果统计
echo ""
echo "🎉 构建完成总结"
echo "✅ 成功构建: ${#successful_services[@]} 个服务"
echo "❌ 构建失败: ${#failed_services[@]} 个服务"
echo "📊 成功率: $(( ${#successful_services[@]} * 100 / total_services ))%"
if [ ${#failed_services[@]} -gt 0 ]; then
echo ""
echo "失败服务错误日志:"
for service in "${failed_services[@]}"; do
echo "=== $service ==="
cat "/tmp/build_${service}.log" 2>/dev/null || echo "无法读取日志文件"
echo ""
done
exit 1
fi
- name: 配置 kubectl
if: success()
run: |
echo "🔧 配置 kubectl 连接到阿里云 ACK..."
# 创建 kubeconfig 目录
mkdir -p ~/.kube
# 从 secrets 中获取 kubeconfig 内容并处理
echo "📝 处理 kubeconfig 文件..."
# 直接解码 base64 内容
echo "🔍 解码 base64 编码的 kubeconfig..."
echo "${{ secrets.KUBECONFIG }}" | base64 -d > ~/.kube/config
# 验证解码是否成功
if [ ! -s ~/.kube/config ]; then
echo "❌ kubeconfig 解码失败或文件为空"
exit 1
fi
# 显示 kubeconfig 内容供手动检查
echo "🔍 解码后的 kubeconfig 内容:"
cat ~/.kube/config
chmod 600 ~/.kube/config
echo "✅ kubeconfig 配置完成"
# 详细验证 kubectl 配置
echo "🔍 验证 kubectl 配置..."
echo "当前上下文:"
kubectl config current-context 2>&1 || echo "无法获取当前上下文"
echo "可用上下文:"
kubectl config get-contexts 2>&1 || echo "无法获取上下文列表"
echo "集群信息:"
kubectl cluster-info 2>&1 || echo "无法获取集群信息"
echo "API 版本:"
kubectl version --short 2>&1 || echo "无法获取版本信息"
- name: 部署到阿里云 ACK
if: success()
run: |
echo "🚀 开始部署到阿里云 ACK..."
# 简单验证 kubectl
if ! kubectl version --client >/dev/null 2>&1; then
echo "❌ kubectl 不可用,跳过部署步骤"
exit 0
fi
echo "✅ kubectl 可用,尝试部署..."
# 获取版本标签(使用分支名)
if [ "${{ github.event_name }}" = "release" ]; then
VERSION_TAG="${{ github.event.release.tag_name }}"
elif [ -n "${{ github.event.inputs.tag }}" ]; then
VERSION_TAG="${{ github.event.inputs.tag }}"
else
# 使用分支名作为标签
VERSION_TAG="${{ github.ref_name }}"
fi
echo "版本标签: $VERSION_TAG"
echo "Docker用户: $DOCKER_USER"
# 检查部署文件是否存在
DEPLOY_DIR="deployments/deploy"
if [ ! -d "$DEPLOY_DIR" ]; then
echo "❌ 部署目录不存在: $DEPLOY_DIR"
echo "📁 当前目录内容:"
ls -la
echo "⚠️ 部署失败,但构建流程继续"
exit 0
fi
echo "📁 进入部署目录: $DEPLOY_DIR"
cd "$DEPLOY_DIR"
# 设置命名空间
NS=${NS:-default}
echo "使用命名空间: $NS"
# 创建命名空间(如果不存在)
kubectl get ns "$NS" >/dev/null 2>&1 || kubectl create ns "$NS"
kubectl config set-context --current --namespace="$NS"
# 尝试部署,如果失败则继续
echo "🚀 开始部署OpenIM Server服务..."
# 定义所有部署文件
DEPLOYMENT_FILES=(
"openim-api-deployment.yml"
"openim-crontask-deployment.yml"
"openim-rpc-user-deployment.yml"
"openim-msggateway-deployment.yml"
"openim-push-deployment.yml"
"openim-msgtransfer-deployment.yml"
"openim-rpc-conversation-deployment.yml"
"openim-rpc-auth-deployment.yml"
"openim-rpc-group-deployment.yml"
"openim-rpc-friend-deployment.yml"
"openim-rpc-msg-deployment.yml"
"openim-rpc-third-deployment.yml"
)
# 更新镜像标签并部署
DEPLOYMENT_ERRORS=()
for file in "${DEPLOYMENT_FILES[@]}"; do
if [ -f "$file" ]; then
echo "📦 处理 $file..."
# 备份原文件(保留 imagePullSecrets 等配置)
cp "$file" "$file.bak"
# 更新镜像标签(替换用户名和标签,但保留 imagePullSecrets
sed -i "s|image: .*/openim-|image: $DOCKER_USER/openim-|g" "$file"
sed -i "s|:prod|:prod|g" "$file"
# 验证 imagePullSecrets 是否保留
if ! grep -q "imagePullSecrets:" "$file"; then
echo "⚠️ 警告: $file 中缺少 imagePullSecrets从备份恢复..."
cp "$file.bak" "$file"
# 只更新镜像,不修改其他内容
sed -i "s|image: .*/openim-|image: $DOCKER_USER/openim-|g" "$file"
sed -i "s|:prod|:prod|g" "$file"
fi
# 应用文件并捕获详细错误
echo "🔍 执行: kubectl apply -f $file"
if kubectl apply -f "$file" 2>&1; then
echo "✅ $file 部署成功"
else
ERROR_OUTPUT=$(kubectl apply -f "$file" 2>&1)
echo "❌ $file 部署失败:"
echo "$ERROR_OUTPUT"
DEPLOYMENT_ERRORS+=("$file: $ERROR_OUTPUT")
echo "⚠️ 继续处理下一个文件..."
fi
# 清理备份文件
rm -f "$file.bak"
else
echo "⚠️ $file 不存在,跳过"
fi
done
# 显示部署错误总结
if [ ${#DEPLOYMENT_ERRORS[@]} -gt 0 ]; then
echo ""
echo "🚨 部署错误总结:"
echo "=========================================="
for error in "${DEPLOYMENT_ERRORS[@]}"; do
echo "❌ $error"
done
echo "=========================================="
fi
echo "✅ 部署步骤完成"
# 强制重启所有部署以使用新镜像
echo "🔄 强制重启所有部署以使用新镜像..."
DEPLOYMENTS=(
"openim-api"
"openim-crontask"
"messagegateway-rpc-server"
"openim-msgtransfer-server"
"push-rpc-server"
"auth-rpc-server"
"user-rpc-server"
"friend-rpc-server"
"group-rpc-server"
"conversation-rpc-server"
"third-rpc-server"
"msg-rpc-server"
)
for deployment in "${DEPLOYMENTS[@]}"; do
echo "🔄 重启部署: $deployment"
# 先删除 pod 以强制拉取新镜像(即使 imagePullPolicy 是 Always有时也需要删除 pod
if kubectl delete pods -l app="$deployment" --grace-period=0 --force 2>&1; then
echo "✅ $deployment Pod 已删除,将重新创建并拉取新镜像"
fi
# 然后重启 deployment
if kubectl rollout restart deployment "$deployment" 2>&1; then
echo "✅ $deployment 重启成功"
else
echo "⚠️ $deployment 重启失败,可能不存在"
fi
done
echo "⏳ 等待部署完成..."
for deployment in "${DEPLOYMENTS[@]}"; do
echo "⏳ 等待 $deployment 就绪..."
if kubectl rollout status deployment "$deployment" --timeout=300s; then
echo "✅ $deployment 部署完成"
else
echo "⚠️ $deployment 超时检查Pod状态..."
echo "Pod状态:"
kubectl get pods -l app="$deployment" 2>&1 || echo "无法获取Pod状态"
echo "Pod事件:"
kubectl get events --field-selector involvedObject.name="$deployment" --sort-by='.lastTimestamp' 2>&1 | tail -10 || echo "无法获取事件"
echo "部署详情:"
kubectl describe deployment "$deployment" 2>&1 | tail -20 || echo "无法获取部署详情"
fi
done
- name: 验证部署状态
if: success()
run: |
echo "🔍 验证部署状态..."
# 详细检查集群连接和权限
echo "🔍 检查集群连接..."
if kubectl cluster-info 2>&1; then
echo "✅ 集群连接正常"
else
CLUSTER_ERROR=$(kubectl cluster-info 2>&1)
echo "❌ 集群连接失败: $CLUSTER_ERROR"
fi
echo "🔍 检查命名空间权限..."
if kubectl get namespaces 2>&1; then
echo "✅ 命名空间权限正常"
else
NS_ERROR=$(kubectl get namespaces 2>&1)
echo "❌ 命名空间权限不足: $NS_ERROR"
fi
echo "🔍 检查 Pod 状态..."
if kubectl get pods -l app=openim 2>&1; then
echo "✅ Pod 状态检查完成"
else
POD_ERROR=$(kubectl get pods -l app=openim 2>&1)
echo "❌ Pod 状态检查失败: $POD_ERROR"
fi
echo "🔍 检查部署状态..."
if kubectl get deployments -l app=openim 2>&1; then
echo "✅ 部署状态检查完成"
else
DEPLOY_ERROR=$(kubectl get deployments -l app=openim 2>&1)
echo "❌ 部署状态检查失败: $DEPLOY_ERROR"
fi
echo "✅ 验证完成"
- name: 生成构建报告
run: |
# 获取版本标签(使用分支名)
if [ "${{ github.event_name }}" = "release" ]; then
VERSION_TAG="${{ github.event.release.tag_name }}"
elif [ -n "${{ github.event.inputs.tag }}" ]; then
VERSION_TAG="${{ github.event.inputs.tag }}"
else
# 使用分支名作为标签
VERSION_TAG="${{ github.ref_name }}"
fi
echo "## OpenIM Server Build Complete" >> $GITHUB_STEP_SUMMARY
echo "**Tag:** $VERSION_TAG" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
echo "**Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "**Platform:** linux/amd64" >> $GITHUB_STEP_SUMMARY
echo "**Mode:** 完整构建和部署" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Images:**" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-api:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-msggateway:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-msgtransfer:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-push:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-crontask:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-rpc-auth:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-rpc-user:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-rpc-friend:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-rpc-group:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-rpc-conversation:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-rpc-third:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY
echo "- \`$DOCKER_USER/openim-rpc-msg:$VERSION_TAG\`" >> $GITHUB_STEP_SUMMARY