name: Deploy to Production on: push: branches: - main workflow_dispatch: # 允许手动触发 env: DEPLOY_PATH: /home/atai/kt-financial-system APP_NAME: kt-financial-system HEALTH_CHECK_URL: http://172.16.74.149:8080 jobs: build-and-test: name: Build and Test runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 with: fetch-depth: 0 # 获取完整历史,用于版本号生成 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '20' - name: Setup pnpm uses: pnpm/action-setup@v2 with: version: 9 - name: Get pnpm store directory id: pnpm-cache shell: bash run: | echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT - name: Setup pnpm cache uses: actions/cache@v3 with: path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm-store- - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build project run: pnpm build - name: Run tests run: pnpm test:unit || echo "No tests configured" continue-on-error: true deploy: name: Deploy to Server runs-on: ubuntu-latest needs: build-and-test steps: - name: Deploy to server uses: appleboy/ssh-action@v1.0.0 with: host: ${{ secrets.SERVER_HOST || '172.16.74.149' }} username: ${{ secrets.SERVER_USER || 'atai' }} password: ${{ secrets.SERVER_PASSWORD || 'wengewudi666808' }} port: ${{ secrets.SERVER_PORT || '22' }} command_timeout: 30m script: | set -e # 遇到错误立即退出 echo "🚀 开始部署 KT财务系统..." # 设置部署路径 DEPLOY_PATH="${DEPLOY_PATH}" # 切换到部署目录 cd /home/atai # 如果目录不存在,克隆仓库 if [ ! -d "kt-financial-system" ]; then echo "📥 克隆代码仓库..." git clone https://gitea.ktyun.cc/chenjiangjiang/kt-financial-system.git cd kt-financial-system else cd kt-financial-system # 保存当前版本信息 CURRENT_COMMIT=$(git rev-parse HEAD) echo "📌 当前版本: $CURRENT_COMMIT" # 拉取最新代码 echo "📥 拉取最新代码..." git fetch origin main git reset --hard origin/main NEW_COMMIT=$(git rev-parse HEAD) echo "📌 新版本: $NEW_COMMIT" if [ "$CURRENT_COMMIT" = "$NEW_COMMIT" ]; then echo "ℹ️ 代码无变化,跳过部署" exit 0 fi fi # 显示最新提交信息 echo "📝 最新提交:" git log -1 --pretty=format:"%h - %an: %s" || true # 停止旧容器(保留数据卷) echo "🛑 停止旧容器..." sudo docker-compose down || true # 构建新镜像 echo "🏗️ 构建新镜像..." sudo docker-compose build --no-cache # 启动新容器 echo "🚀 启动新容器..." sudo docker-compose up -d # 等待服务启动 echo "⏳ 等待服务启动..." sleep 10 # 确认PostgreSQL已就绪 echo "⏳ 等待PostgreSQL就绪..." POSTGRES_READY=0 for i in {1..10}; do if sudo docker-compose exec -T postgres pg_isready -U kt_financial -d kt_financial > /dev/null 2>&1; then echo "✅ PostgreSQL 已就绪" POSTGRES_READY=1 break fi echo " 第${i}次重试..." sleep 3 done if [ "$POSTGRES_READY" -ne 1 ]; then echo "❌ PostgreSQL 未在预期时间内就绪" exit 1 fi # 导入财务交易数据 echo "📦 导入财务数据..." sudo docker-compose exec -T kt-financial \ sh -lc "pnpm --dir apps/backend import:data -- --csv /app/data/finance/finance-combined.csv --year 2025" # 验证数据条数 echo "🔢 检查交易记录条数..." sudo docker-compose exec -T postgres \ psql -U kt_financial -d kt_financial -c "SELECT COUNT(*) AS transaction_count FROM finance_transactions;" # 1. 检查容器状态 echo "📊 容器状态:" sudo docker-compose ps # 2. 检查端口占用情况 echo "" echo "🔍 检查端口8080占用:" sudo lsof -i :8080 || echo "端口8080未被占用" # 3. 检查容器内部监听情况 echo "" echo "🔍 检查容器内部监听:" CONTAINER_ID=$(sudo docker-compose ps -q kt-financial 2>/dev/null || echo "") if [ -n "$CONTAINER_ID" ]; then sudo docker exec $CONTAINER_ID ss -tlnp | grep ':80' || echo "容器内无80端口监听" fi # 4. 检查容器详细日志(增加行数) echo "" echo "📝 容器日志(最近100行):" sudo docker-compose logs --tail=100 # 5. 检查容器健康状态 echo "" echo "🏥 容器健康检查:" sudo docker inspect --format='{{.State.Health.Status}}' $CONTAINER_ID 2>/dev/null || echo "未配置健康检查" # 清理旧镜像和悬空镜像 echo "" echo "🧹 清理旧镜像..." sudo docker image prune -f echo "✅ 部署完成!" - name: Send notification on success if: success() run: | echo "✅ 部署成功!" echo "🌐 访问地址: ${{ env.HEALTH_CHECK_URL }}" - name: Send notification on failure if: failure() run: | echo "❌ 部署失败!请检查日志"