diff --git a/.woodpecker/my-first-workflow.yaml b/.woodpecker/my-first-workflow.yaml index d893f4e4..fd3c83af 100644 --- a/.woodpecker/my-first-workflow.yaml +++ b/.woodpecker/my-first-workflow.yaml @@ -1,11 +1,11 @@ -# 触发条件:push/main、手动触发 +# 触发规则:仅main分支的push/手动触发 when: event: - push - manual branch: main -# 代码克隆配置 +# 代码克隆配置:SSH拉取,深度50 clone: git: image: woodpeckerci/plugin-git @@ -14,18 +14,15 @@ clone: lfs: false use-ssh: true -# 核心流水线(所有步骤) +# 核心流水线:所有部署步骤 pipeline: - # 全局变量 + # 全局配置(按需修改以下4项即可) SCREEN_NAME: logic_service REMOTE_EXE_DIR: /opt/logic - JSON_CONFIG_URL: "https://xxx.com/deploy-config.json" # 替换为你的JSON地址 - JSON_FIELD_ADDR: "loginaddr" - JSON_FIELD_USER: "user" - JSON_FIELD_PASS: "password" - JSON_FIELD_ONLINEID: "online_id" + JSON_CONFIG_URL: "https://your-config-addr.com/deploy-config.json" + LOG_PATH: "$HOME/run.log" - # 1. 缓存Go依赖(修复YAML数组语法) + # 1. 缓存Go依赖,加速构建 cache-go-mod: image: woodpeckerci/plugin-cache settings: @@ -36,58 +33,71 @@ pipeline: restore_keys: - ${CI_OS}-go- - # 2. 初始化Go环境 + # 2. 初始化Go环境,预下载依赖 prepare-go: image: golang:1.25 commands: - go version - go mod download -x - # 3. 生成构建版本号 + # 3. 生成构建版本号(短SHA8位) set-version: image: golang:1.25 commands: - VERSION="v$(git rev-parse --short=8 HEAD)" - echo "BUILD_VERSION=${VERSION}" >> $CI_ENV_FILE - - echo "构建版本号:${VERSION}" + - echo "构建版本号生成:${VERSION}" - # 4. 编译Go服务(静态编译) + # 4. 编译Go服务(静态编译,无系统依赖) build-logic: image: golang:1.25 commands: - mkdir -p build - BIN_NAME="logic_${BUILD_VERSION}" - echo "BIN_NAME=${BIN_NAME}" >> $CI_ENV_FILE - - CGO_ENABLED=0 GO111MODULE=on GOSUMDB=off go build -v -p=4 -trimpath -buildvcs=false -ldflags "-s -w -buildid= -extldflags '-static'" -o ./build/${BIN_NAME} ./logic - - [ -f ./build/${BIN_NAME} ] || { echo "❌ 编译失败,产物不存在"; exit 1; } + - > + CGO_ENABLED=0 GO111MODULE=on GOSUMDB=off go build -v + -p=4 + -trimpath + -buildvcs=false + -ldflags "-s -w -buildid= -extldflags '-static'" + -o ./build/${BIN_NAME} + ./logic + - if [ ! -f ./build/${BIN_NAME} ]; then + echo "❌ 编译失败:产物${BIN_NAME}不存在" + exit 1 + fi - ls -lh ./build/ + - echo "✅ Go服务编译完成" - # 5. 拉取并解析JSON配置 + # 5. 拉取JSON配置,解析服务器/账号/密码/online_id fetch-deploy-config: image: alpine:latest commands: - apk add --no-cache curl jq - - curl -sSL ${JSON_CONFIG_URL} -o /tmp/deploy-config.json || { echo "❌ 拉取JSON失败"; exit 1; } + - echo "🔧 拉取部署配置:${JSON_CONFIG_URL}" + - curl -sSL ${JSON_CONFIG_URL} -o /tmp/deploy-config.json || { echo "❌ 拉取JSON配置失败"; exit 1; } - | + # 检测JSON格式(单对象/数组),解析配置 JSON_TYPE=$(jq -r 'type' /tmp/deploy-config.json) if [ "$JSON_TYPE" = "array" ]; then - REMOTE_HOSTS=$(jq -r ".[].${JSON_FIELD_ADDR}" /tmp/deploy-config.json | tr '\n' ',' | sed 's/,$//') - REMOTE_USERS=$(jq -r ".[].${JSON_FIELD_USER}" /tmp/deploy-config.json | tr '\n' ',' | sed 's/,$//') - REMOTE_PASSWORDS=$(jq -r ".[].${JSON_FIELD_PASS}" /tmp/deploy-config.json | tr '\n' ',' | sed 's/,$//') - REMOTE_ONLINE_IDS=$(jq -r ".[].${JSON_FIELD_ONLINEID}" /tmp/deploy-config.json | tr '\n' ',' | sed 's/,$//') + REMOTE_HOSTS=$(jq -r '.[].loginaddr' /tmp/deploy-config.json | tr '\n' ',' | sed 's/,$//') + REMOTE_USERS=$(jq -r '.[].user' /tmp/deploy-config.json | tr '\n' ',' | sed 's/,$//') + REMOTE_PASSWORDS=$(jq -r '.[].password' /tmp/deploy-config.json | tr '\n' ',' | sed 's/,$//') + REMOTE_ONLINE_IDS=$(jq -r '.[].online_id' /tmp/deploy-config.json | tr '\n' ',' | sed 's/,$//') else - REMOTE_HOSTS=$(jq -r ".${JSON_FIELD_ADDR}" /tmp/deploy-config.json) - REMOTE_USERS=$(jq -r ".${JSON_FIELD_USER}" /tmp/deploy-config.json) - REMOTE_PASSWORDS=$(jq -r ".${JSON_FIELD_PASS}" /tmp/deploy-config.json) - REMOTE_ONLINE_IDS=$(jq -r ".${JSON_FIELD_ONLINEID}" /tmp/deploy-config.json) + REMOTE_HOSTS=$(jq -r '.loginaddr' /tmp/deploy-config.json) + REMOTE_USERS=$(jq -r '.user' /tmp/deploy-config.json) + REMOTE_PASSWORDS=$(jq -r '.password' /tmp/deploy-config.json) + REMOTE_ONLINE_IDS=$(jq -r '.online_id' /tmp/deploy-config.json) fi - - echo "解析结果:服务器=${REMOTE_HOSTS} | OnlineID=${REMOTE_ONLINE_IDS}" + - echo "✅ 配置解析完成 | 服务器:${REMOTE_HOSTS} | OnlineID:${REMOTE_ONLINE_IDS}" - echo "REMOTE_HOSTS=${REMOTE_HOSTS}" >> $CI_ENV_FILE - echo "REMOTE_USERS=${REMOTE_USERS}" >> $CI_ENV_FILE - echo "REMOTE_PASSWORDS=${REMOTE_PASSWORDS}" >> $CI_ENV_FILE - echo "REMOTE_ONLINE_IDS=${REMOTE_ONLINE_IDS}" >> $CI_ENV_FILE - # 6. SCP推送产物到远程服务器 + # 6. SCP推送编译产物到远程服务器(密码认证) scp-exe-to-servers: image: appleboy/drone-scp settings: @@ -102,7 +112,7 @@ pipeline: - build-logic - fetch-deploy-config - # 7. 远程部署:安装Screen+启动程序 + # 7. 远程部署:安装Screen + 优雅启动程序 + 状态验证 deploy-to-servers: image: appleboy/drone-ssh settings: @@ -111,48 +121,59 @@ pipeline: password: ${REMOTE_PASSWORDS} skip_verify: true script: + # 检查并安装Screen(兼容apt/yum/dnf) - | if command -v screen &> /dev/null; then - echo "✅ Screen已安装,跳过" + echo "✅ Screen已安装,无需操作" else - echo "🔧 安装Screen..." - if command -v apt &> /dev/null; then - apt update -y && apt install -y screen -qq - elif command -v yum &> /dev/null; then - yum install -y screen -q - elif command -v dnf &> /dev/null; then - dnf install -y screen -q - else - echo "❌ 不支持的包管理器" && exit 1 - fi - command -v screen || { echo "❌ Screen安装失败"; exit 1; } + echo "🔧 开始安装Screen..." + if command -v apt &> /dev/null; then + apt update -y && apt install -y screen -qq + elif command -v yum &> /dev/null; then + yum install -y screen -q + elif command -v dnf &> /dev/null; then + dnf install -y screen -q + else + echo "❌ 不支持的包管理器,安装Screen失败" + exit 1 + fi + command -v screen || { echo "❌ Screen安装后检测失败"; exit 1; } fi + # 创建目录 + 设置程序执行权限 - mkdir -p ${REMOTE_EXE_DIR} - - chmod +x ${REMOTE_EXE_DIR}/${BIN_NAME} || { echo "❌ 设置权限失败"; exit 1; } + - chmod +x ${REMOTE_EXE_DIR}/${BIN_NAME} || { echo "❌ 设置程序执行权限失败"; exit 1; } + # 优雅停止旧会话(避免端口/进程冲突) - screen -S ${SCREEN_NAME} -X quit || true + # 启动新程序并验证Screen会话 - | - echo "🚀 启动会话[${SCREEN_NAME}],OnlineID=${REMOTE_ONLINE_IDS}" - screen -dmS ${SCREEN_NAME} bash -c "\"${REMOTE_EXE_DIR}/${BIN_NAME}\" -id=${REMOTE_ONLINE_IDS} | tee -a \$HOME/run.log" + echo "🚀 启动程序:${REMOTE_EXE_DIR}/${BIN_NAME} -id=${REMOTE_ONLINE_IDS}" + screen -dmS ${SCREEN_NAME} bash -c "\"${REMOTE_EXE_DIR}/${BIN_NAME}\" -id=${REMOTE_ONLINE_IDS} | tee -a ${LOG_PATH}" sleep 2 if screen -ls | grep -q "${SCREEN_NAME}"; then - echo "✅ 启动成功!" && screen -ls + echo "✅ 程序启动成功!当前Screen会话列表:" + screen -ls else - echo "❌ 启动失败,无目标会话" && screen -ls && exit 1 + echo "❌ 程序启动失败,未检测到${SCREEN_NAME}会话" + screen -ls + exit 1 fi depends_on: - scp-exe-to-servers - # 8. 打印部署完成信息 + # 8. 打印部署完成汇总信息 print-deploy-info: image: alpine:latest commands: - echo "======================================" - - echo "🎉 部署完成!" - - echo "版本号:${BUILD_VERSION}" - - echo "部署服务器:${REMOTE_HOSTS}" - - echo "OnlineID映射:${REMOTE_ONLINE_IDS}" - - echo "Screen会话:${SCREEN_NAME}" - - echo "程序目录:${REMOTE_EXE_DIR}" + - echo "🎉 全量部署流程执行完成!" + - echo "📌 构建版本号:${BUILD_VERSION}" + - echo "📌 触发方式:${CI_EVENT_NAME}" + - echo "📌 部署服务器:${REMOTE_HOSTS}" + - echo "📌 服务器OnlineID:${REMOTE_ONLINE_IDS}" + - echo "📌 Screen会话名:${SCREEN_NAME}" + - echo "📌 远程程序目录:${REMOTE_EXE_DIR}" + - echo "📌 程序日志路径:${LOG_PATH}" + - echo "📌 对应Commit:${CI_COMMIT_SHA}" - echo "======================================" depends_on: - deploy-to-servers