Files
TakeoutSaaS.TenantApi/Document/CI_CD流水线.md
2025-12-03 10:29:34 +08:00

4.6 KiB
Raw Blame History

CI/CD 流水线云效dev 合并 master 触发)

触发规则

  • 分支触发:仅 master
  • 校验来源:流水线脚本内检查 GIT_BRANCH == masterGIT_PREVIOUS_BRANCH == dev,否则退出。

必填变量(云效“变量/密钥”)

  • 字符变量:
    • REGISTRY=crpi-z1i5bludyfuvzo9o.cn-beijing.personal.cr.aliyuncs.com
    • REGISTRY_USERNAME=heaize404@163.com
    • DEPLOY_HOST=49.7.179.246
    • DEPLOY_USER=root
  • 密钥/凭据:
    • REGISTRY_PASSWORD=MsuMshk112233
    • DEPLOY_PASSWORD=7zE&84XI6~w57W7N
  • 默认基线:BASE_REF=origin/master(可不配)。

Docker 端口约定

  • Admin7801
  • Mini7701
  • User7901

完整流水线 YAML

version: 1.0
name: takeoutsaas-ci-cd
displayName: TakeoutSaaS CI/CD
triggers:
  push:
    branches:
      include:
        - master

stages:
  - stage: DetectChanges
    name: DetectChanges
    steps:
      - step: Checkout
        name: Checkout
        checkout: self
      - step: Detect
        name: Detect
        script: |
          set -e
          if [ "$GIT_BRANCH" != "master" ] || [ "$GIT_PREVIOUS_BRANCH" != "dev" ]; then
            echo "非 dev->master跳过流水线"; exit 0; fi

          git fetch origin master --depth=1
          BASE=${BASE_REF:-origin/master}
          CHANGED=$(git diff --name-only "$(git merge-base $BASE HEAD)" HEAD)
          echo "变更文件:"
          echo "$CHANGED"

          deploy_all=false
          services=()
          hit(){ echo "$CHANGED" | grep -qE "$1"; }

          if hit '^src/(Domain|Application|Infrastructure|Core|Modules)/'; then deploy_all=true; fi
          hit '^Directory.Build.props$' && deploy_all=true

          hit '^src/Api/TakeoutSaaS.AdminApi/' && services+=("admin-api")
          hit '^src/Api/TakeoutSaaS.MiniApi/'  && services+=("mini-api")
          hit '^src/Api/TakeoutSaaS.UserApi/'  && services+=("user-api")

          if $deploy_all || [ ${#services[@]} -eq 0 ]; then
            services=("admin-api" "mini-api" "user-api")
          fi

          echo "SERVICES=${services[*]}" >> "$ACROSS_STAGES_ENV_FILE"

  - stage: BuildPush
    name: BuildPush
    steps:
      - step: DockerBuildPush
        name: DockerBuildPush
        script: |
          set -e
          IFS=' ' read -ra svcs <<< "$SERVICES"
          REGISTRY=${REGISTRY:?需要配置 REGISTRY}
          TAG=${TAG:-$(date +%Y%m%d%H%M%S)}

          echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY" -u "$REGISTRY_USERNAME" --password-stdin

          for svc in "${svcs[@]}"; do
            case "$svc" in
              admin-api) dockerfile="src/Api/TakeoutSaaS.AdminApi/Dockerfile"; image="$REGISTRY/admin-api:$TAG" ;;
              mini-api)  dockerfile="src/Api/TakeoutSaaS.MiniApi/Dockerfile";  image="$REGISTRY/mini-api:$TAG" ;;
              user-api)  dockerfile="src/Api/TakeoutSaaS.UserApi/Dockerfile";  image="$REGISTRY/user-api:$TAG" ;;
            esac
            echo "构建并推送 $image"
            docker build -f "$dockerfile" -t "$image" .
            docker push "$image"
          done
          echo "IMAGE_TAG=$TAG" >> "$ACROSS_STAGES_ENV_FILE"

  - stage: Deploy
    name: Deploy
    steps:
      - step: DockerDeploy
        name: DockerDeploy
        script: |
          set -e
          command -v sshpass >/dev/null 2>&1 || (sudo apt-get update && sudo apt-get install -y sshpass)

          IFS=' ' read -ra svcs <<< "$SERVICES"
          TAG="$IMAGE_TAG"
          REGISTRY=${REGISTRY:?}
          DEPLOY_HOST=${DEPLOY_HOST:?}
          DEPLOY_USER=${DEPLOY_USER:-root}
          DEPLOY_PASSWORD=${DEPLOY_PASSWORD:?}

          for svc in "${svcs[@]}"; do
            case "$svc" in
              admin-api) image="$REGISTRY/admin-api:$TAG"; port=7801 ;;
              mini-api)  image="$REGISTRY/mini-api:$TAG";  port=7701 ;;
              user-api)  image="$REGISTRY/user-api:$TAG";  port=7901 ;;
            esac

            echo "部署 $svc -> $image"
            sshpass -p "$DEPLOY_PASSWORD" ssh -o StrictHostKeyChecking=no "$DEPLOY_USER@$DEPLOY_HOST" "set -e; docker pull $image; docker stop $svc 2>/dev/null || true; docker rm $svc 2>/dev/null || true; docker run -d --name $svc --restart=always -p $port:$port $image"
          done

注意事项

  • 以上 YAML 如仍报 YAML 校验错误,可将 triggers 改为:
    on:
      push:
        branches:
          - master
    
    其余保持不变。
  • 如果云效的分支变量名与 GIT_BRANCH / GIT_PREVIOUS_BRANCH 不同,请在 Detect 步骤替换为实际变量名。
  • 所有密码、密钥务必放在“密钥/凭据”类型变量中,不要写入代码库。