# CI/CD 流水线(云效,dev 合并 master 触发) ## 触发规则 - 分支触发:仅 `master`。 - 校验来源:流水线脚本内检查 `GIT_BRANCH == master` 且 `GIT_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 端口约定 - Admin:7801 - Mini:7701 - User:7901 ## 完整流水线 YAML ```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` 改为: ```yaml on: push: branches: - master ``` 其余保持不变。 - 如果云效的分支变量名与 `GIT_BRANCH` / `GIT_PREVIOUS_BRANCH` 不同,请在 Detect 步骤替换为实际变量名。 - 所有密码、密钥务必放在“密钥/凭据”类型变量中,不要写入代码库。