From 7ea3d8142b21fa617549b751a48ded077d28770e Mon Sep 17 00:00:00 2001 From: xujiang Date: Tue, 15 Jul 2025 13:46:20 +0800 Subject: [PATCH 01/10] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=98=BF?= =?UTF-8?q?=E9=87=8C=E4=BA=91=E5=AE=B9=E5=99=A8=E9=95=9C=E5=83=8F=E4=BB=93?= =?UTF-8?q?=E5=BA=93=E8=AE=A4=E8=AF=81=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 增加 Docker 登录验证步骤 - 添加构建重试机制 - 优化认证流程稳定性 - 增强错误处理和日志输出 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .gitea/workflows/deploy-backend.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.gitea/workflows/deploy-backend.yml b/.gitea/workflows/deploy-backend.yml index ed08553..111b5fc 100644 --- a/.gitea/workflows/deploy-backend.yml +++ b/.gitea/workflows/deploy-backend.yml @@ -54,6 +54,16 @@ jobs: registry: ${{ env.REGISTRY }} username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} + env: + DOCKER_CLI_EXPERIMENTAL: enabled + + - name: 🔍 验证镜像仓库连接 + run: | + echo "🔍 验证镜像仓库连接..." + docker pull hello-world:latest || true + docker logout ${{ env.REGISTRY }} || true + echo "🏷️ 重新登录镜像仓库..." + echo "${{ secrets.DOCKER_PASSWORD }}" | docker login ${{ env.REGISTRY }} --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin - name: 📝 提取元数据 id: meta @@ -79,6 +89,23 @@ jobs: cache-to: type=gha,mode=max provenance: false sbom: false + continue-on-error: true + id: build_push + + - name: 🔄 重试构建和推送 + if: steps.build_push.outcome == 'failure' + run: | + echo "⚠️ 构建推送失败,等待10秒后重试..." + sleep 10 + docker buildx build --push \ + --platform linux/amd64 \ + --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \ + --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \ + --cache-from type=gha \ + --cache-to type=gha,mode=max \ + --provenance=false \ + --sbom=false \ + ./backend - name: 📦 同步配置文件 run: | From 169dafc72280696408329154b6f887597361f91a Mon Sep 17 00:00:00 2001 From: xujiang Date: Tue, 15 Jul 2025 14:01:12 +0800 Subject: [PATCH 02/10] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=E9=98=BF?= =?UTF-8?q?=E9=87=8C=E4=BA=91=E9=95=9C=E5=83=8F=E6=8E=A8=E9=80=81=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E5=92=8C=E5=A2=9E=E5=BC=BA=E9=94=99=E8=AF=AF=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用正确的镜像仓库路径格式 - 增强镜像推送的日志输出 - 改进重试机制和错误提示 - 添加详细的推送状态信息 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .gitea/workflows/deploy-backend.yml | 137 +++++++++++++++++++--------- 1 file changed, 93 insertions(+), 44 deletions(-) diff --git a/.gitea/workflows/deploy-backend.yml b/.gitea/workflows/deploy-backend.yml index 111b5fc..84741c1 100644 --- a/.gitea/workflows/deploy-backend.yml +++ b/.gitea/workflows/deploy-backend.yml @@ -48,22 +48,33 @@ jobs: # 验证配置 docker info | grep -A 5 "Registry Mirrors" || true - - name: 🔑 登录到镜像仓库 - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - env: - DOCKER_CLI_EXPERIMENTAL: enabled - - - name: 🔍 验证镜像仓库连接 + - name: 🔑 登录到镜像仓库(使用阿里云访问令牌) run: | - echo "🔍 验证镜像仓库连接..." - docker pull hello-world:latest || true - docker logout ${{ env.REGISTRY }} || true - echo "🏷️ 重新登录镜像仓库..." - echo "${{ secrets.DOCKER_PASSWORD }}" | docker login ${{ env.REGISTRY }} --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin + echo "🔑 使用阿里云访问令牌登录..." + # 创建 Docker 配置文件 + mkdir -p ~/.docker + cat > ~/.docker/config.json << EOF + { + "auths": { + "${{ env.REGISTRY }}": { + "auth": "$(echo -n '${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }}' | base64 -w 0)" + } + } + } + EOF + + # 验证登录状态 + echo "🔍 验证登录状态..." + if docker pull ${{ env.REGISTRY }}/library/hello-world:latest 2>/dev/null; then + echo "✅ 镜像仓库认证成功" + else + echo "❌ 镜像仓库认证失败,尝试基础认证..." + # 使用基础认证 + echo "${{ secrets.DOCKER_PASSWORD }}" | docker login ${{ env.REGISTRY }} --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin || { + echo "❌ 所有认证方式都失败" + exit 1 + } + fi - name: 📝 提取元数据 id: meta @@ -76,36 +87,74 @@ jobs: type=sha,prefix={{branch}}- type=raw,value=latest,enable={{is_default_branch}} - - name: 🏗️ 构建并推送镜像 - uses: docker/build-push-action@v5 - with: - context: ./backend - file: ./backend/Dockerfile - platforms: linux/amd64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max - provenance: false - sbom: false - continue-on-error: true - id: build_push - - - name: 🔄 重试构建和推送 - if: steps.build_push.outcome == 'failure' + - name: 🏗️ 构建镜像(使用正确格式) run: | - echo "⚠️ 构建推送失败,等待10秒后重试..." - sleep 10 - docker buildx build --push \ - --platform linux/amd64 \ - --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \ - --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \ - --cache-from type=gha \ - --cache-to type=gha,mode=max \ - --provenance=false \ - --sbom=false \ - ./backend + echo "🔨 开始构建 Docker 镜像..." + cd ./backend + + # 设置正确的镜像标签格式 + IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" + IMAGE_TAG_LATEST="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" + + echo "🏷️ 镜像标签:" + echo " - $IMAGE_TAG" + echo " - $IMAGE_TAG_LATEST" + + # 构建镜像 + docker build -t $IMAGE_TAG -t $IMAGE_TAG_LATEST . + + # 验证镜像 + echo "🔍 验证镜像构建..." + docker images | grep photography-backend + + echo "✅ 镜像构建完成" + + - name: 📤 推送镜像(使用正确路径) + run: | + IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" + IMAGE_TAG_LATEST="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" + + echo "📤 开始推送镜像..." + echo "📋 目标仓库: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" + + # 重试机制 + max_attempts=3 + attempt=1 + + while [ $attempt -le $max_attempts ]; do + echo "📤 推送尝试 $attempt/$max_attempts..." + echo "🚀 推送命令: docker push $IMAGE_TAG" + + if docker push $IMAGE_TAG; then + echo "✅ 版本标签推送成功" + + echo "🚀 推送 latest 标签: docker push $IMAGE_TAG_LATEST" + if docker push $IMAGE_TAG_LATEST; then + echo "✅ latest 标签推送成功" + break + else + echo "⚠️ latest 标签推送失败,但版本标签已成功" + break + fi + else + echo "❌ 推送失败,等待重试..." + if [ $attempt -lt $max_attempts ]; then + echo "⏳ 等待15秒后重试..." + sleep 15 + fi + fi + + attempt=$((attempt + 1)) + done + + if [ $attempt -gt $max_attempts ]; then + echo "❌ 所有推送尝试都失败" + echo "📋 请检查以下配置:" + echo " - 仓库地址: ${{ env.REGISTRY }}" + echo " - 镜像名称: ${{ env.IMAGE_NAME }}" + echo " - 认证信息: ${{ secrets.DOCKER_USERNAME }}" + exit 1 + fi - name: 📦 同步配置文件 run: | From cdcccbd00ec54f56a1aadb421c14fa5e98fbd552 Mon Sep 17 00:00:00 2001 From: xujiang Date: Tue, 15 Jul 2025 14:31:33 +0800 Subject: [PATCH 03/10] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20docker=20compose=20?= =?UTF-8?q?=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/deploy-backend.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.gitea/workflows/deploy-backend.yml b/.gitea/workflows/deploy-backend.yml index 84741c1..290e258 100644 --- a/.gitea/workflows/deploy-backend.yml +++ b/.gitea/workflows/deploy-backend.yml @@ -196,19 +196,19 @@ jobs: # 停止现有服务 echo "🛑 停止现有服务..." - docker-compose down api || true + docker compose down api || true # 拉取最新镜像 echo "📥 拉取最新镜像..." - docker-compose pull api + docker compose pull api # 数据库迁移需要手动执行 echo "⚠️ 数据库迁移需要手动执行,请在部署后运行:" - echo " docker-compose exec api ./main migrate" + echo " docker compose exec api ./main migrate" # 启动后端服务 echo "🚀 启动后端服务..." - docker-compose up -d api + docker compose up -d api # 等待服务启动 echo "⏳ 等待服务启动..." @@ -227,7 +227,7 @@ jobs: # 检查服务状态 echo "📊 检查服务状态..." - docker-compose ps + docker compose ps # 清理旧镜像 (保留最近3个) echo "🧹 清理旧镜像..." @@ -238,7 +238,7 @@ jobs: echo "🎉 后端部署完成!" echo "📋 请记住手动运行数据库迁移:" - echo " docker-compose exec api ./main migrate" + echo " docker compose exec api ./main migrate" - name: 📧 发送部署通知 if: always() @@ -256,7 +256,7 @@ jobs: ${{ job.status == 'success' && '✅ 部署成功' || '❌ 部署失败' }} - ${{ job.status == 'success' && '⚠️ 请记住手动运行数据库迁移: docker-compose exec api ./main migrate' || '' }} + ${{ job.status == 'success' && '⚠️ 请记住手动运行数据库迁移: docker compose exec api ./main migrate' || '' }} 🌐 API: https://api.photography.iriver.top/health 📊 监控: https://admin.photography.iriver.top @@ -287,16 +287,16 @@ jobs: echo "📦 找到备份镜像: $BACKUP_IMAGE" # 停止当前服务 - docker-compose down backend + docker compose down backend # 标记备份镜像为最新 docker tag $BACKUP_IMAGE photography_backend:rollback - # 修改 docker-compose 使用回滚镜像 + # 修改 docker compose 使用回滚镜像 sed -i 's|build: .*|image: photography_backend:rollback|g' docker-compose.yml # 启动回滚版本 - docker-compose up -d backend + docker compose up -d backend echo "✅ 回滚完成" else From 4bb20e588211204e8911933a47b4a292bba95eeb Mon Sep 17 00:00:00 2001 From: xujiang Date: Tue, 15 Jul 2025 14:42:31 +0800 Subject: [PATCH 04/10] fix bug --- .gitea/workflows/deploy-backend.yml | 35 +++++++++++++++++++++++++---- backend/docker-compose.prod.yml | 3 ++- backend/docker-compose.yml | 3 ++- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/deploy-backend.yml b/.gitea/workflows/deploy-backend.yml index 290e258..c423984 100644 --- a/.gitea/workflows/deploy-backend.yml +++ b/.gitea/workflows/deploy-backend.yml @@ -188,6 +188,26 @@ jobs: # 切换到后端项目目录 cd /data/docker/photography/backend + # 修复 Docker 权限问题 + echo "🔧 检查并修复 Docker 权限..." + sudo systemctl status docker || sudo systemctl start docker + sudo usermod -aG docker ${{ secrets.TYY_USER }} || true + + # 确保 Docker 服务正常运行 + echo "🐳 检查 Docker 服务状态..." + sudo systemctl is-active --quiet docker || { + echo "❌ Docker 服务未运行,尝试启动..." + sudo systemctl start docker + sleep 5 + } + + # 验证 Docker 权限 + echo "🔍 验证 Docker 权限..." + docker --version || { + echo "❌ Docker 命令不可用" + exit 1 + } + # 备份当前运行的容器 (如果存在) if docker ps -q -f name=photography-api; then echo "📦 备份当前后端容器..." @@ -196,11 +216,18 @@ jobs: # 停止现有服务 echo "🛑 停止现有服务..." - docker compose down api || true + docker compose down api || { + echo "⚠️ 停止服务时遇到问题,继续执行..." + docker stop photography-api || true + docker rm photography-api || true + } # 拉取最新镜像 echo "📥 拉取最新镜像..." - docker compose pull api + docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} || { + echo "❌ 镜像拉取失败,检查网络连接..." + exit 1 + } # 数据库迁移需要手动执行 echo "⚠️ 数据库迁移需要手动执行,请在部署后运行:" @@ -287,7 +314,7 @@ jobs: echo "📦 找到备份镜像: $BACKUP_IMAGE" # 停止当前服务 - docker compose down backend + docker compose down api # 标记备份镜像为最新 docker tag $BACKUP_IMAGE photography_backend:rollback @@ -296,7 +323,7 @@ jobs: sed -i 's|build: .*|image: photography_backend:rollback|g' docker-compose.yml # 启动回滚版本 - docker compose up -d backend + docker compose up -d api echo "✅ 回滚完成" else diff --git a/backend/docker-compose.prod.yml b/backend/docker-compose.prod.yml index 025817f..4376bc5 100644 --- a/backend/docker-compose.prod.yml +++ b/backend/docker-compose.prod.yml @@ -1,7 +1,8 @@ # Photography Portfolio Backend - Production Docker Compose # 生产环境配置 - 使用现有 PostgreSQL 和 Redis 服务 -version: '3.8' +# version 字段已废弃,不再需要使用 +# version: '3.8' services: # 后端API服务 (仅API服务,无数据库) diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml index b0f8b42..c70f044 100644 --- a/backend/docker-compose.yml +++ b/backend/docker-compose.yml @@ -1,7 +1,8 @@ # Photography Portfolio Backend - Docker Compose # 本地开发和测试环境配置 -version: '3.8' +# version 字段已废弃,不再需要使用 +# version: '3.8' services: # PostgreSQL 数据库 From 737fd73af2ad8b3d34c2d9af12d3b8b5b900c91a Mon Sep 17 00:00:00 2001 From: xujiang Date: Tue, 15 Jul 2025 15:26:50 +0800 Subject: [PATCH 05/10] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=20CI/CD=20Docker=20=E7=99=BB=E5=BD=95=E5=92=8C?= =?UTF-8?q?=E6=9D=83=E9=99=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在服务器端部署前添加阿里云镜像仓库登录步骤 - 优化 Docker 权限处理,减少 sudo 使用 - 修复镜像拉取失败导致的部署中断 --- .gitea/workflows/deploy-backend.yml | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.gitea/workflows/deploy-backend.yml b/.gitea/workflows/deploy-backend.yml index c423984..9b3b820 100644 --- a/.gitea/workflows/deploy-backend.yml +++ b/.gitea/workflows/deploy-backend.yml @@ -188,18 +188,13 @@ jobs: # 切换到后端项目目录 cd /data/docker/photography/backend - # 修复 Docker 权限问题 - echo "🔧 检查并修复 Docker 权限..." - sudo systemctl status docker || sudo systemctl start docker - sudo usermod -aG docker ${{ secrets.TYY_USER }} || true - - # 确保 Docker 服务正常运行 + # 检查 Docker 服务状态 echo "🐳 检查 Docker 服务状态..." - sudo systemctl is-active --quiet docker || { - echo "❌ Docker 服务未运行,尝试启动..." - sudo systemctl start docker + if ! docker info >/dev/null 2>&1; then + echo "❌ Docker 服务未运行或权限不足,尝试使用 sudo..." + echo '${{ secrets.TYY_PWD }}' | sudo -S systemctl start docker sleep 5 - } + fi # 验证 Docker 权限 echo "🔍 验证 Docker 权限..." @@ -208,6 +203,13 @@ jobs: exit 1 } + # 登录阿里云镜像仓库 + echo "🔑 登录阿里云镜像仓库..." + echo "${{ secrets.DOCKER_PASSWORD }}" | docker login ${{ env.REGISTRY }} --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin || { + echo "❌ Docker 登录失败,检查认证信息..." + exit 1 + } + # 备份当前运行的容器 (如果存在) if docker ps -q -f name=photography-api; then echo "📦 备份当前后端容器..." From 45cacfd5b53e1f057242f23ba9085772bac23cd8 Mon Sep 17 00:00:00 2001 From: xujiang Date: Tue, 15 Jul 2025 15:35:36 +0800 Subject: [PATCH 06/10] fix cicd --- .gitea/workflows/deploy-backend.yml | 316 ++-------------------------- 1 file changed, 16 insertions(+), 300 deletions(-) diff --git a/.gitea/workflows/deploy-backend.yml b/.gitea/workflows/deploy-backend.yml index 9b3b820..fcf78ef 100644 --- a/.gitea/workflows/deploy-backend.yml +++ b/.gitea/workflows/deploy-backend.yml @@ -3,10 +3,7 @@ name: 部署后端服务 on: push: branches: [ main ] - paths: - - 'backend/**' - - '.env.example' - - '.gitea/workflows/deploy-backend.yml' + paths: [ 'backend/**', '.env.example' ] workflow_dispatch: env: @@ -14,170 +11,27 @@ env: IMAGE_NAME: photography-backend/photography jobs: - build-and-deploy: - name: 🚀 构建并部署 + deploy: + name: 🚀 构建并部署后端 runs-on: ubuntu-latest - if: github.ref == 'refs/heads/main' steps: - name: 📥 检出代码 uses: actions/checkout@v4 - - name: 🐳 设置 Docker Buildx - uses: docker/setup-buildx-action@v3 - with: - driver-opts: | - network=host - - - name: 🔧 配置 Docker 镜像代理 + - name: 🐳 构建并推送镜像 run: | - # 创建 Docker daemon 配置文件 - sudo mkdir -p /etc/docker - sudo tee /etc/docker/daemon.json < ~/.docker/config.json << EOF - { - "auths": { - "${{ env.REGISTRY }}": { - "auth": "$(echo -n '${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }}' | base64 -w 0)" - } - } - } - EOF - - # 验证登录状态 - echo "🔍 验证登录状态..." - if docker pull ${{ env.REGISTRY }}/library/hello-world:latest 2>/dev/null; then - echo "✅ 镜像仓库认证成功" - else - echo "❌ 镜像仓库认证失败,尝试基础认证..." - # 使用基础认证 - echo "${{ secrets.DOCKER_PASSWORD }}" | docker login ${{ env.REGISTRY }} --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin || { - echo "❌ 所有认证方式都失败" - exit 1 - } - fi - - - name: 📝 提取元数据 - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch - type=ref,event=pr - type=sha,prefix={{branch}}- - type=raw,value=latest,enable={{is_default_branch}} - - - name: 🏗️ 构建镜像(使用正确格式) - run: | - echo "🔨 开始构建 Docker 镜像..." - cd ./backend - - # 设置正确的镜像标签格式 + cd backend IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" - IMAGE_TAG_LATEST="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" - echo "🏷️ 镜像标签:" - echo " - $IMAGE_TAG" - echo " - $IMAGE_TAG_LATEST" + # 登录镜像仓库 + echo "${{ secrets.DOCKER_PASSWORD }}" | docker login ${{ env.REGISTRY }} --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin - # 构建镜像 - docker build -t $IMAGE_TAG -t $IMAGE_TAG_LATEST . - - # 验证镜像 - echo "🔍 验证镜像构建..." - docker images | grep photography-backend - - echo "✅ 镜像构建完成" + # 构建并推送 + docker build -t $IMAGE_TAG . + docker push $IMAGE_TAG - - name: 📤 推送镜像(使用正确路径) - run: | - IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" - IMAGE_TAG_LATEST="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" - - echo "📤 开始推送镜像..." - echo "📋 目标仓库: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" - - # 重试机制 - max_attempts=3 - attempt=1 - - while [ $attempt -le $max_attempts ]; do - echo "📤 推送尝试 $attempt/$max_attempts..." - echo "🚀 推送命令: docker push $IMAGE_TAG" - - if docker push $IMAGE_TAG; then - echo "✅ 版本标签推送成功" - - echo "🚀 推送 latest 标签: docker push $IMAGE_TAG_LATEST" - if docker push $IMAGE_TAG_LATEST; then - echo "✅ latest 标签推送成功" - break - else - echo "⚠️ latest 标签推送失败,但版本标签已成功" - break - fi - else - echo "❌ 推送失败,等待重试..." - if [ $attempt -lt $max_attempts ]; then - echo "⏳ 等待15秒后重试..." - sleep 15 - fi - fi - - attempt=$((attempt + 1)) - done - - if [ $attempt -gt $max_attempts ]; then - echo "❌ 所有推送尝试都失败" - echo "📋 请检查以下配置:" - echo " - 仓库地址: ${{ env.REGISTRY }}" - echo " - 镜像名称: ${{ env.IMAGE_NAME }}" - echo " - 认证信息: ${{ secrets.DOCKER_USERNAME }}" - exit 1 - fi - - - name: 📦 同步配置文件 - run: | - # 安装sshpass用于密码认证 - sudo apt-get update && sudo apt-get install -y sshpass - - # 同步配置文件到服务器 - echo "📋 同步配置文件到服务器..." - export SSHPASS=${{ secrets.TYY_PWD }} - sshpass -e scp -o StrictHostKeyChecking=no -P ${{ secrets.PORT }} backend/docker-compose.prod.yml ${{ secrets.TYY_USER }}@${{ secrets.HOST }}:/data/docker/photography/backend/docker-compose.yml - - # 创建生产环境配置文件 - echo "📋 创建生产环境配置..." - sed -e "s/DB_USER=.*/DB_USER=${{ secrets.POSTGRES_PHOTO_USER }}/" \ - -e "s/DB_PASSWORD=.*/DB_PASSWORD=${{ secrets.POSTGRES_PHOTO_PWD }}/" \ - -e "s/DB_HOST=.*/DB_HOST=localhost/" \ - -e "s/APP_ENV=.*/APP_ENV=production/" \ - backend/.env.example > /tmp/production.env - - sshpass -e scp -o StrictHostKeyChecking=no -P ${{ secrets.PORT }} /tmp/production.env ${{ secrets.TYY_USER }}@${{ secrets.HOST }}:/data/docker/photography/backend/.env - echo "✅ 配置文件同步完成" - - - name: 🚀 部署到生产环境 + - name: 🚀 部署到服务器 uses: appleboy/ssh-action@v1.0.0 with: host: ${{ secrets.HOST }} @@ -185,150 +39,12 @@ jobs: password: ${{ secrets.TYY_PWD }} port: ${{ secrets.PORT }} script: | - # 切换到后端项目目录 cd /data/docker/photography/backend - # 检查 Docker 服务状态 - echo "🐳 检查 Docker 服务状态..." - if ! docker info >/dev/null 2>&1; then - echo "❌ Docker 服务未运行或权限不足,尝试使用 sudo..." - echo '${{ secrets.TYY_PWD }}' | sudo -S systemctl start docker - sleep 5 - fi - - # 验证 Docker 权限 - echo "🔍 验证 Docker 权限..." - docker --version || { - echo "❌ Docker 命令不可用" - exit 1 - } - - # 登录阿里云镜像仓库 - echo "🔑 登录阿里云镜像仓库..." - echo "${{ secrets.DOCKER_PASSWORD }}" | docker login ${{ env.REGISTRY }} --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin || { - echo "❌ Docker 登录失败,检查认证信息..." - exit 1 - } - - # 备份当前运行的容器 (如果存在) - if docker ps -q -f name=photography-api; then - echo "📦 备份当前后端容器..." - docker commit photography-api photography_backend_backup_$(date +%Y%m%d_%H%M%S) - fi - - # 停止现有服务 - echo "🛑 停止现有服务..." - docker compose down api || { - echo "⚠️ 停止服务时遇到问题,继续执行..." - docker stop photography-api || true - docker rm photography-api || true - } - - # 拉取最新镜像 - echo "📥 拉取最新镜像..." - docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} || { - echo "❌ 镜像拉取失败,检查网络连接..." - exit 1 - } - - # 数据库迁移需要手动执行 - echo "⚠️ 数据库迁移需要手动执行,请在部署后运行:" - echo " docker compose exec api ./main migrate" - - # 启动后端服务 - echo "🚀 启动后端服务..." + # 拉取最新镜像并重启 + IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" + docker pull $IMAGE_TAG + docker compose down api docker compose up -d api - # 等待服务启动 - echo "⏳ 等待服务启动..." - sleep 30 - - # 健康检查 - echo "🔍 执行健康检查..." - for i in {1..30}; do - if curl -f http://localhost:8080/health > /dev/null 2>&1; then - echo "✅ 后端服务健康检查通过" - break - fi - echo "等待后端服务启动... ($i/30)" - sleep 10 - done - - # 检查服务状态 - echo "📊 检查服务状态..." - docker compose ps - - # 清理旧镜像 (保留最近3个) - echo "🧹 清理旧镜像..." - docker images ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} --format "table {{.Repository}}:{{.Tag}}\t{{.CreatedAt}}" | tail -n +2 | sort -k2 -r | tail -n +4 | awk '{print $1}' | xargs -r docker rmi || true - - # 清理旧备份容器 (保留最近5个) - docker images photography_backend_backup_* --format "table {{.Repository}}:{{.Tag}}\t{{.CreatedAt}}" | tail -n +2 | sort -k2 -r | tail -n +6 | awk '{print $1}' | xargs -r docker rmi || true - - echo "🎉 后端部署完成!" - echo "📋 请记住手动运行数据库迁移:" - echo " docker compose exec api ./main migrate" - - - name: 📧 发送部署通知 - if: always() - uses: appleboy/telegram-action@master - with: - to: ${{ secrets.TELEGRAM_TO }} - token: ${{ secrets.TELEGRAM_TOKEN }} - message: | - 🔧 摄影作品集后端部署 - - 📦 项目: ${{ github.repository }} - 🌿 分支: ${{ github.ref_name }} - 👤 提交者: ${{ github.actor }} - 📝 提交信息: ${{ github.event.head_commit.message }} - - ${{ job.status == 'success' && '✅ 部署成功' || '❌ 部署失败' }} - - ${{ job.status == 'success' && '⚠️ 请记住手动运行数据库迁移: docker compose exec api ./main migrate' || '' }} - - 🌐 API: https://api.photography.iriver.top/health - 📊 监控: https://admin.photography.iriver.top - - rollback: - name: 🔄 回滚部署 - runs-on: ubuntu-latest - if: failure() && github.ref == 'refs/heads/main' - needs: build-and-deploy - - steps: - - name: 🔄 执行回滚 - uses: appleboy/ssh-action@v1.0.0 - with: - host: ${{ secrets.HOST }} - username: ${{ secrets.TYY_USER }} - password: ${{ secrets.TYY_PWD }} - port: ${{ secrets.PORT }} - script: | - cd /data/docker/photography/backend - - echo "🔄 开始回滚后端服务..." - - # 查找最新的备份容器 - BACKUP_IMAGE=$(docker images photography_backend_backup_* --format "table {{.Repository}}:{{.Tag}}\t{{.CreatedAt}}" | tail -n +2 | sort -k2 -r | head -n 1 | awk '{print $1}') - - if [ -n "$BACKUP_IMAGE" ]; then - echo "📦 找到备份镜像: $BACKUP_IMAGE" - - # 停止当前服务 - docker compose down api - - # 标记备份镜像为最新 - docker tag $BACKUP_IMAGE photography_backend:rollback - - # 修改 docker compose 使用回滚镜像 - sed -i 's|build: .*|image: photography_backend:rollback|g' docker-compose.yml - - # 启动回滚版本 - docker compose up -d api - - echo "✅ 回滚完成" - else - echo "❌ 未找到备份镜像,无法回滚" - exit 1 - fi \ No newline at end of file + echo "✅ 后端部署完成!" \ No newline at end of file From c10abdab1951e55e84c04c7ce69d6aa147f5702e Mon Sep 17 00:00:00 2001 From: xujiang Date: Tue, 15 Jul 2025 15:46:17 +0800 Subject: [PATCH 07/10] fix --- backend/docker-compose.prod.yml | 4 +- backend/docker-compose.yml | 133 ++++++++------------------------ 2 files changed, 34 insertions(+), 103 deletions(-) diff --git a/backend/docker-compose.prod.yml b/backend/docker-compose.prod.yml index 4376bc5..eedfeeb 100644 --- a/backend/docker-compose.prod.yml +++ b/backend/docker-compose.prod.yml @@ -7,9 +7,7 @@ services: # 后端API服务 (仅API服务,无数据库) api: - build: - context: . - dockerfile: Dockerfile + image: crpi-b4fqtfbvv583enk2.cn-shanghai.personal.cr.aliyuncs.com/photography-backend/photography:latest container_name: photography-api environment: # 数据库配置 (连接现有服务) diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml index c70f044..eedfeeb 100644 --- a/backend/docker-compose.yml +++ b/backend/docker-compose.yml @@ -1,104 +1,53 @@ -# Photography Portfolio Backend - Docker Compose -# 本地开发和测试环境配置 +# Photography Portfolio Backend - Production Docker Compose +# 生产环境配置 - 使用现有 PostgreSQL 和 Redis 服务 # version 字段已废弃,不再需要使用 # version: '3.8' services: - # PostgreSQL 数据库 - db: - image: postgres:16-alpine - container_name: photography-db - environment: - POSTGRES_DB: photography - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres123 - POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C" - ports: - - "5432:5432" - volumes: - - postgres_data:/var/lib/postgresql/data - - ./configs/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro - networks: - - photography-network - restart: unless-stopped - healthcheck: - test: ["CMD-SHELL", "pg_isready -U postgres -d photography"] - interval: 10s - timeout: 5s - retries: 5 - - # Redis 缓存 - redis: - image: redis:7-alpine - container_name: photography-redis - ports: - - "6379:6379" - volumes: - - redis_data:/data - - ./configs/redis.conf:/usr/local/etc/redis/redis.conf:ro - command: redis-server /usr/local/etc/redis/redis.conf - networks: - - photography-network - restart: unless-stopped - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 3s - retries: 5 - - # 后端API服务 + # 后端API服务 (仅API服务,无数据库) api: - build: - context: . - dockerfile: Dockerfile + image: crpi-b4fqtfbvv583enk2.cn-shanghai.personal.cr.aliyuncs.com/photography-backend/photography:latest container_name: photography-api environment: - # 数据库配置 - DB_HOST: db - DB_PORT: 5432 - DB_NAME: photography - DB_USER: postgres - DB_PASSWORD: postgres123 - DB_SSL_MODE: disable + # 数据库配置 (连接现有服务) + DB_HOST: ${DB_HOST:-redis_cache} + DB_PORT: ${DB_PORT:-5432} + DB_NAME: ${DB_NAME:-photography} + DB_USER: ${DB_USER:-postgres} + DB_PASSWORD: ${DB_PASSWORD} + DB_SSL_MODE: ${DB_SSL_MODE:-disable} - # Redis配置 - REDIS_HOST: redis - REDIS_PORT: 6379 - REDIS_PASSWORD: "" - REDIS_DB: 0 + # Redis配置 (连接现有服务) + REDIS_HOST: ${REDIS_HOST:-localhost} + REDIS_PORT: ${REDIS_PORT:-6379} + REDIS_PASSWORD: ${REDIS_PASSWORD:-} + REDIS_DB: ${REDIS_DB:-0} # JWT配置 - JWT_SECRET: your-super-secret-jwt-key-change-in-production - JWT_EXPIRE: 24h + JWT_SECRET: ${JWT_SECRET} + JWT_EXPIRE: ${JWT_EXPIRE:-24h} # 服务配置 - APP_ENV: development - APP_PORT: 8080 - APP_HOST: 0.0.0.0 + APP_ENV: ${APP_ENV:-production} + APP_PORT: ${APP_PORT:-8080} + APP_HOST: ${APP_HOST:-0.0.0.0} # CORS配置 - CORS_ORIGINS: "http://localhost:3000,http://localhost:3001,http://localhost:5173" + CORS_ORIGINS: ${CORS_ORIGINS:-https://photography.iriver.top} # 文件上传配置 - UPLOAD_PATH: /app/uploads - UPLOAD_MAX_SIZE: 10485760 # 10MB + UPLOAD_PATH: ${UPLOAD_PATH:-/app/uploads} + UPLOAD_MAX_SIZE: ${UPLOAD_MAX_SIZE:-10485760} # 日志配置 - LOG_LEVEL: info - LOG_FORMAT: json + LOG_LEVEL: ${LOG_LEVEL:-info} + LOG_FORMAT: ${LOG_FORMAT:-json} ports: - "8080:8080" volumes: - uploads_data:/app/uploads - logs_data:/app/logs - networks: - - photography-network - depends_on: - db: - condition: service_healthy - redis: - condition: service_healthy restart: unless-stopped healthcheck: test: ["CMD", "/photography-api", "--health-check"] @@ -114,33 +63,17 @@ services: dockerfile: Dockerfile container_name: photography-migrate environment: - DB_HOST: db - DB_PORT: 5432 - DB_NAME: photography - DB_USER: postgres - DB_PASSWORD: postgres123 - DB_SSL_MODE: disable - networks: - - photography-network - depends_on: - db: - condition: service_healthy + DB_HOST: ${DB_HOST:-localhost} + DB_PORT: ${DB_PORT:-5432} + DB_NAME: ${DB_NAME:-photography} + DB_USER: ${DB_USER:-postgres} + DB_PASSWORD: ${DB_PASSWORD} + DB_SSL_MODE: ${DB_SSL_MODE:-disable} entrypoint: ["/migrate", "up"] restart: "no" volumes: - postgres_data: - driver: local - redis_data: - driver: local uploads_data: driver: local logs_data: - driver: local - -networks: - photography-network: - driver: bridge - ipam: - config: - - subnet: 172.20.0.0/16 \ No newline at end of file + driver: local \ No newline at end of file From 052a91feb8091e05d8ffe44cd4d40743f338d4f3 Mon Sep 17 00:00:00 2001 From: xujiang Date: Tue, 15 Jul 2025 15:49:16 +0800 Subject: [PATCH 08/10] fix --- .gitea/workflows/deploy-backend.yml | 12 +++++++++--- backend/docker-compose.prod.yml | 4 +--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/deploy-backend.yml b/.gitea/workflows/deploy-backend.yml index fcf78ef..e551ee1 100644 --- a/.gitea/workflows/deploy-backend.yml +++ b/.gitea/workflows/deploy-backend.yml @@ -41,10 +41,16 @@ jobs: script: | cd /data/docker/photography/backend - # 拉取最新镜像并重启 + # 拉取最新镜像 IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" docker pull $IMAGE_TAG - docker compose down api - docker compose up -d api + + # 更新镜像标签 + docker tag $IMAGE_TAG ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + + # 使用生产环境配置部署 + docker compose -f docker-compose.prod.yml down api + docker compose -f docker-compose.prod.yml up -d api echo "✅ 后端部署完成!" \ No newline at end of file diff --git a/backend/docker-compose.prod.yml b/backend/docker-compose.prod.yml index eedfeeb..ef3e34e 100644 --- a/backend/docker-compose.prod.yml +++ b/backend/docker-compose.prod.yml @@ -58,9 +58,7 @@ services: # 数据库迁移服务 (一次性运行) migrate: - build: - context: . - dockerfile: Dockerfile + image: crpi-b4fqtfbvv583enk2.cn-shanghai.personal.cr.aliyuncs.com/photography-backend/photography:latest container_name: photography-migrate environment: DB_HOST: ${DB_HOST:-localhost} From 1782bf56544858f00ca5cc2d65264bbfcef9850c Mon Sep 17 00:00:00 2001 From: xujiang Date: Tue, 15 Jul 2025 15:55:45 +0800 Subject: [PATCH 09/10] 1 --- .gitea/workflows/deploy-backend.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/deploy-backend.yml b/.gitea/workflows/deploy-backend.yml index e551ee1..d6c90fc 100644 --- a/.gitea/workflows/deploy-backend.yml +++ b/.gitea/workflows/deploy-backend.yml @@ -40,7 +40,7 @@ jobs: port: ${{ secrets.PORT }} script: | cd /data/docker/photography/backend - + git pull origin main # 拉取最新镜像 IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" docker pull $IMAGE_TAG From 93cc1c427db7a310ea61b0478d06a5ade18feb0f Mon Sep 17 00:00:00 2001 From: xujiang Date: Tue, 15 Jul 2025 15:57:12 +0800 Subject: [PATCH 10/10] 1 --- .gitea/workflows/deploy-backend.yml | 328 +++++++++++++++++++++++++--- 1 file changed, 303 insertions(+), 25 deletions(-) diff --git a/.gitea/workflows/deploy-backend.yml b/.gitea/workflows/deploy-backend.yml index d6c90fc..5b23cf0 100644 --- a/.gitea/workflows/deploy-backend.yml +++ b/.gitea/workflows/deploy-backend.yml @@ -3,7 +3,10 @@ name: 部署后端服务 on: push: branches: [ main ] - paths: [ 'backend/**', '.env.example' ] + paths: + - 'backend/**' + - '.env.example' + - '.gitea/workflows/deploy-backend.yml' workflow_dispatch: env: @@ -11,27 +14,170 @@ env: IMAGE_NAME: photography-backend/photography jobs: - deploy: - name: 🚀 构建并部署后端 + build-and-deploy: + name: 🚀 构建并部署 runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' steps: - name: 📥 检出代码 uses: actions/checkout@v4 - - name: 🐳 构建并推送镜像 - run: | - cd backend - IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" - - # 登录镜像仓库 - echo "${{ secrets.DOCKER_PASSWORD }}" | docker login ${{ env.REGISTRY }} --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin - - # 构建并推送 - docker build -t $IMAGE_TAG . - docker push $IMAGE_TAG + - name: 🐳 设置 Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + driver-opts: | + network=host - - name: 🚀 部署到服务器 + - name: 🔧 配置 Docker 镜像代理 + run: | + # 创建 Docker daemon 配置文件 + sudo mkdir -p /etc/docker + sudo tee /etc/docker/daemon.json < ~/.docker/config.json << EOF + { + "auths": { + "${{ env.REGISTRY }}": { + "auth": "$(echo -n '${{ secrets.DOCKER_USERNAME }}:${{ secrets.DOCKER_PASSWORD }}' | base64 -w 0)" + } + } + } + EOF + + # 验证登录状态 + echo "🔍 验证登录状态..." + if docker pull ${{ env.REGISTRY }}/library/hello-world:latest 2>/dev/null; then + echo "✅ 镜像仓库认证成功" + else + echo "❌ 镜像仓库认证失败,尝试基础认证..." + # 使用基础认证 + echo "${{ secrets.DOCKER_PASSWORD }}" | docker login ${{ env.REGISTRY }} --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin || { + echo "❌ 所有认证方式都失败" + exit 1 + } + fi + + - name: 📝 提取元数据 + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=sha,prefix={{branch}}- + type=raw,value=latest,enable={{is_default_branch}} + + - name: 🏗️ 构建镜像(使用正确格式) + run: | + echo "🔨 开始构建 Docker 镜像..." + cd ./backend + + # 设置正确的镜像标签格式 + IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" + IMAGE_TAG_LATEST="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" + + echo "🏷️ 镜像标签:" + echo " - $IMAGE_TAG" + echo " - $IMAGE_TAG_LATEST" + + # 构建镜像 + docker build -t $IMAGE_TAG -t $IMAGE_TAG_LATEST . + + # 验证镜像 + echo "🔍 验证镜像构建..." + docker images | grep photography-backend + + echo "✅ 镜像构建完成" + + - name: 📤 推送镜像(使用正确路径) + run: | + IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" + IMAGE_TAG_LATEST="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" + + echo "📤 开始推送镜像..." + echo "📋 目标仓库: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" + + # 重试机制 + max_attempts=3 + attempt=1 + + while [ $attempt -le $max_attempts ]; do + echo "📤 推送尝试 $attempt/$max_attempts..." + echo "🚀 推送命令: docker push $IMAGE_TAG" + + if docker push $IMAGE_TAG; then + echo "✅ 版本标签推送成功" + + echo "🚀 推送 latest 标签: docker push $IMAGE_TAG_LATEST" + if docker push $IMAGE_TAG_LATEST; then + echo "✅ latest 标签推送成功" + break + else + echo "⚠️ latest 标签推送失败,但版本标签已成功" + break + fi + else + echo "❌ 推送失败,等待重试..." + if [ $attempt -lt $max_attempts ]; then + echo "⏳ 等待15秒后重试..." + sleep 15 + fi + fi + + attempt=$((attempt + 1)) + done + + if [ $attempt -gt $max_attempts ]; then + echo "❌ 所有推送尝试都失败" + echo "📋 请检查以下配置:" + echo " - 仓库地址: ${{ env.REGISTRY }}" + echo " - 镜像名称: ${{ env.IMAGE_NAME }}" + echo " - 认证信息: ${{ secrets.DOCKER_USERNAME }}" + exit 1 + fi + + - name: 📦 同步配置文件 + run: | + # 安装sshpass用于密码认证 + sudo apt-get update && sudo apt-get install -y sshpass + + # 同步配置文件到服务器 + echo "📋 同步配置文件到服务器..." + export SSHPASS=${{ secrets.TYY_PWD }} + sshpass -e scp -o StrictHostKeyChecking=no -P ${{ secrets.PORT }} backend/docker-compose.prod.yml ${{ secrets.TYY_USER }}@${{ secrets.HOST }}:/data/docker/photography/backend/docker-compose.yml + + # 创建生产环境配置文件 + echo "📋 创建生产环境配置..." + sed -e "s/DB_USER=.*/DB_USER=${{ secrets.POSTGRES_PHOTO_USER }}/" \ + -e "s/DB_PASSWORD=.*/DB_PASSWORD=${{ secrets.POSTGRES_PHOTO_PWD }}/" \ + -e "s/DB_HOST=.*/DB_HOST=localhost/" \ + -e "s/APP_ENV=.*/APP_ENV=production/" \ + backend/.env.example > /tmp/production.env + + sshpass -e scp -o StrictHostKeyChecking=no -P ${{ secrets.PORT }} /tmp/production.env ${{ secrets.TYY_USER }}@${{ secrets.HOST }}:/data/docker/photography/backend/.env + echo "✅ 配置文件同步完成" + + - name: 🚀 部署到生产环境 uses: appleboy/ssh-action@v1.0.0 with: host: ${{ secrets.HOST }} @@ -39,18 +185,150 @@ jobs: password: ${{ secrets.TYY_PWD }} port: ${{ secrets.PORT }} script: | + # 切换到后端项目目录 cd /data/docker/photography/backend - git pull origin main + + # 检查 Docker 服务状态 + echo "🐳 检查 Docker 服务状态..." + if ! docker info >/dev/null 2>&1; then + echo "❌ Docker 服务未运行或权限不足,尝试使用 sudo..." + echo '${{ secrets.TYY_PWD }}' | sudo -S systemctl start docker + sleep 5 + fi + + # 验证 Docker 权限 + echo "🔍 验证 Docker 权限..." + docker --version || { + echo "❌ Docker 命令不可用" + exit 1 + } + + # 登录阿里云镜像仓库 + echo "🔑 登录阿里云镜像仓库..." + echo "${{ secrets.DOCKER_PASSWORD }}" | docker login ${{ env.REGISTRY }} --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin || { + echo "❌ Docker 登录失败,检查认证信息..." + exit 1 + } + + # 备份当前运行的容器 (如果存在) + if docker ps -q -f name=photography-api; then + echo "📦 备份当前后端容器..." + docker commit photography-api photography_backend_backup_$(date +%Y%m%d_%H%M%S) + fi + + # 停止现有服务 + echo "🛑 停止现有服务..." + docker compose down api || { + echo "⚠️ 停止服务时遇到问题,继续执行..." + docker stop photography-api || true + docker rm photography-api || true + } + # 拉取最新镜像 - IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}" - docker pull $IMAGE_TAG + echo "📥 拉取最新镜像..." + docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} || { + echo "❌ 镜像拉取失败,检查网络连接..." + exit 1 + } - # 更新镜像标签 - docker tag $IMAGE_TAG ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest - docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + # 数据库迁移需要手动执行 + echo "⚠️ 数据库迁移需要手动执行,请在部署后运行:" + echo " docker compose exec api ./main migrate" - # 使用生产环境配置部署 - docker compose -f docker-compose.prod.yml down api - docker compose -f docker-compose.prod.yml up -d api + # 启动后端服务 + echo "🚀 启动后端服务..." + docker compose up -d api - echo "✅ 后端部署完成!" \ No newline at end of file + # 等待服务启动 + echo "⏳ 等待服务启动..." + sleep 30 + + # 健康检查 + echo "🔍 执行健康检查..." + for i in {1..30}; do + if curl -f http://localhost:8080/health > /dev/null 2>&1; then + echo "✅ 后端服务健康检查通过" + break + fi + echo "等待后端服务启动... ($i/30)" + sleep 10 + done + + # 检查服务状态 + echo "📊 检查服务状态..." + docker compose ps + + # 清理旧镜像 (保留最近3个) + echo "🧹 清理旧镜像..." + docker images ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} --format "table {{.Repository}}:{{.Tag}}\t{{.CreatedAt}}" | tail -n +2 | sort -k2 -r | tail -n +4 | awk '{print $1}' | xargs -r docker rmi || true + + # 清理旧备份容器 (保留最近5个) + docker images photography_backend_backup_* --format "table {{.Repository}}:{{.Tag}}\t{{.CreatedAt}}" | tail -n +2 | sort -k2 -r | tail -n +6 | awk '{print $1}' | xargs -r docker rmi || true + + echo "🎉 后端部署完成!" + echo "📋 请记住手动运行数据库迁移:" + echo " docker compose exec api ./main migrate" + + - name: 📧 发送部署通知 + if: always() + uses: appleboy/telegram-action@master + with: + to: ${{ secrets.TELEGRAM_TO }} + token: ${{ secrets.TELEGRAM_TOKEN }} + message: | + 🔧 摄影作品集后端部署 + + 📦 项目: ${{ github.repository }} + 🌿 分支: ${{ github.ref_name }} + 👤 提交者: ${{ github.actor }} + 📝 提交信息: ${{ github.event.head_commit.message }} + + ${{ job.status == 'success' && '✅ 部署成功' || '❌ 部署失败' }} + + ${{ job.status == 'success' && '⚠️ 请记住手动运行数据库迁移: docker compose exec api ./main migrate' || '' }} + + 🌐 API: https://api.photography.iriver.top/health + 📊 监控: https://admin.photography.iriver.top + + # rollback: + # name: 🔄 回滚部署 + # runs-on: ubuntu-latest + # if: failure() && github.ref == 'refs/heads/main' + # needs: build-and-deploy + + # steps: + # - name: 🔄 执行回滚 + # uses: appleboy/ssh-action@v1.0.0 + # with: + # host: ${{ secrets.HOST }} + # username: ${{ secrets.TYY_USER }} + # password: ${{ secrets.TYY_PWD }} + # port: ${{ secrets.PORT }} + # script: | + # cd /data/docker/photography/backend + + # echo "🔄 开始回滚后端服务..." + + # # 查找最新的备份容器 + # BACKUP_IMAGE=$(docker images photography_backend_backup_* --format "table {{.Repository}}:{{.Tag}}\t{{.CreatedAt}}" | tail -n +2 | sort -k2 -r | head -n 1 | awk '{print $1}') + + # if [ -n "$BACKUP_IMAGE" ]; then + # echo "📦 找到备份镜像: $BACKUP_IMAGE" + + # # 停止当前服务 + # docker compose down api + + # # 标记备份镜像为最新 + # docker tag $BACKUP_IMAGE photography_backend:rollback + + # # 修改 docker compose 使用回滚镜像 + # sed -i 's|build: .*|image: photography_backend:rollback|g' docker-compose.yml + + # # 启动回滚版本 + # docker compose up -d api + + # echo "✅ 回滚完成" + # else + # echo "❌ 未找到备份镜像,无法回滚" + # exit 1 + # fi \ No newline at end of file