Files
bl/.woodpecker/my-first-workflow.yaml
2026-01-27 07:11:15 +00:00

251 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 触发条件仅pushmanual手动触发分支限定main
when:
event:
- push
- manual
branch: main
skip_clone: true
# 全局配置变量替换占位符即可使用
variables:
SCREEN_NAME: "logic_service"
REMOTE_EXE_DIR: "/opt/logic"
JSON_CONFIG_URL: "https://你的JSON配置地址.com/deploy.json"
LOG_PATH: "$HOME/run.log"
# 流水线核心步骤理顺依赖链确保各步骤依赖正确
steps:
# ========== 1. 替代clone拉取代码核心依赖 ==========
prepare:
image: debian:bookworm
environment:
# 修正变量传递语法
WOODPECKER_SSH_KEY:
from_secret: WOODPECKER_SSH_KEY
commands:
# 调试验证变量是否传递
- echo "🔍 调试WOODPECKER_SSH_KEY变量长度 = $${WOODPECKER_SSH_KEY}"
- echo "🔍 调试当前环境变量列表筛选SSH相关"
- apt update -y
# 安装完整依赖解决SSH/libcrypto问题
- apt install -y --no-install-recommends ca-certificates curl git openssh-client openssl libssl-dev
# 清理旧SSH文件严格配置权限
- rm -rf /root/.ssh/*
- mkdir -p /root/.ssh && chmod 700 /root/.ssh
# ========== 关键修复SSH密钥写入逻辑删除外层chmod优化格式 ==========
- |
if [ -n "$WOODPECKER_SSH_KEY" ]; then
# 写入ED25519密钥保留原始换行避免格式损坏
cat > /root/.ssh/id_ed25519 << EOF
$WOODPECKER_SSH_KEY
EOF
chmod 600 /root/.ssh/id_ed25519
echo "✅ ED25519密钥写入完成"
else
echo "⚠️ WOODPECKER_SSH_KEY变量为空未写入SSH密钥"
exit 1 # 密钥为空时终止流程避免后续无效操作
fi
# 添加GitHub主机密钥完整覆盖避免重复
- ssh-keyscan -H github.com > /root/.ssh/known_hosts
- chmod 600 /root/.ssh/known_hosts
# 检查私钥是否能被解析关键测试
- ssh-keygen -lf /root/.ssh/id_ed25519 || { echo "❌ SSH密钥解析失败"; exit 1; }
- echo "🔍 尝试SSH连接GitHub详细日志..."
# 重新执行命令取消输出屏蔽查看具体错误
- ssh -vvv -i /root/.ssh/id_ed25519 -o StrictHostKeyChecking=accept-new git@github.com 2>&1
# 拉取代码拆分命令添加错误处理避免静默失败
- git init || { echo "❌ git init失败"; exit 1; }
- git remote add origin "$$CI_REPO_CLONE_SSH_URL" || { echo "❌ 添加远程仓库失败"; exit 1; }
- git config core.sshCommand 'ssh -i /root/.ssh/id_ed25519'
- git fetch origin "$CI_REPO_DEFAULT_BRANCH" || { echo "❌ git fetch失败"; exit 1; }
- git checkout "$CI_REPO_DEFAULT_BRANCH" || { echo "❌ git checkout失败"; exit 1; }
- echo "✅ 代码拉取完成"
# ========== 2. 初始化Go环境依赖prepare代码拉取完成 ==========
prepare-go:
image: golang:1.25
depends_on: [prepare]
commands:
- go version
- go mod download -x || { echo "❌ 下载Go依赖失败"; exit 1; }
- go mod verify || { echo "❌ 验证Go依赖失败"; exit 1; }
- echo "✅ Go环境初始化完成"
# ========== 3. 生成版本号依赖prepare-goGo环境就绪 ==========
set-version:
image: golang:1.25
depends_on: [prepare-go]
commands:
- |
if [ -n "${CI_COMMIT_TAG}" ]; then
VERSION="${CI_COMMIT_TAG}"
else
# 确保git能获取到提交信息依赖prepare拉取的代码
VERSION="v$(git rev-parse --short=8 HEAD 2>/dev/null || echo "unknown")"
fi
# 确保CI_ENV_FILE目录存在
mkdir -p "$(dirname "$CI_ENV_FILE")"
echo "BUILD_VERSION=${VERSION}" >> "$CI_ENV_FILE"
echo "✅ 生成版本号:${VERSION}"
# ========== 4. 编译Go服务核心依赖prepare+prepare-go+set-version ==========
build_logic:
image: golang:1.25
depends_on: [set-version]
environment:
CGO_ENABLED: 0
GO111MODULE: on
GOSUMDB: off
commands:
- mkdir -p build
- BIN_NAME="logic_${BUILD_VERSION}"
- echo "BIN_NAME=${BIN_NAME}" >> "$CI_ENV_FILE"
- |
go build -v \
-p=4 \
-trimpath \
-buildvcs=false \
-ldflags "-s -w -buildid= -extldflags '-static' -X main.version=${BUILD_VERSION}" \
-o ./build/${BIN_NAME} \
./logic
- |
if [ ! -f ./build/${BIN_NAME} ]; then
echo "❌ 编译失败:产物${BIN_NAME}不存在"
exit 1
fi
- ls -lh ./build/
- ./build/${BIN_NAME} -v || true
- echo "✅ Go服务编译完成"
# ========== 5. 拉取部署配置可并行依赖prepare确保代码拉取完成 ==========
fetch-deploy-config:
image: alpine:latest
depends_on: [prepare]
commands:
- apk add --no-cache curl jq
- echo "🔧 拉取部署配置:${JSON_CONFIG_URL}"
- |
# 重试机制最多3次
for i in 1 2 3; do
curl -sSL --connect-timeout 10 --max-time 30 "${JSON_CONFIG_URL}" -o /tmp/deploy-config.json && break
echo "⚠️ 第${i}次拉取失败,重试中..."
sleep 2
done
if [ ! -f /tmp/deploy-config.json ]; then
echo "❌ 拉取JSON配置失败"
exit 1
fi
- |
# 安全解析JSON避免jq报错终止流程
JSON_TYPE=$(jq -r 'type' /tmp/deploy-config.json 2>/dev/null || echo "invalid")
if [ "$JSON_TYPE" = "array" ]; then
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/,$//')
elif [ "$JSON_TYPE" = "object" ]; then
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)
else
echo "❌ JSON配置格式错误非数组/对象)"
cat /tmp/deploy-config.json
exit 1
fi
- |
if [ -z "$REMOTE_HOSTS" ] || [ -z "$REMOTE_USERS" ]; then
echo "❌ 解析配置失败:服务器/用户名为空"
cat /tmp/deploy-config.json
exit 1
fi
- 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推送产物依赖编译+配置解析 ==========
scp-exe-to-servers:
image: appleboy/drone-scp:1.6.2
settings:
host: ${REMOTE_HOSTS}
username: ${REMOTE_USERS}
password: ${REMOTE_PASSWORDS}
source: ./build/${BIN_NAME}
target: ${REMOTE_EXE_DIR}/
strip_components: 1
skip_verify: true
timeout: 30s
depends_on:
- build_logic
- fetch-deploy-config
# ========== 7. 远程部署依赖SCP推送 ==========
deploy-to-servers:
image: appleboy/drone-ssh:1.7.0
settings:
host: ${REMOTE_HOSTS}
username: ${REMOTE_USERS}
password: ${REMOTE_PASSWORDS}
skip_verify: true
timeout: 60s
script:
- |
# 安装Screen增强容错
if ! command -v screen &> /dev/null; then
echo "🔧 安装Screen..."
if command -v apt &> /dev/null; then
apt update -y && apt install -y --no-install-recommends 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
fi
# 验证Screen安装
if ! command -v screen &> /dev/null; then
echo "❌ Screen安装后检测失败"
exit 1
fi
echo "✅ Screen已安装/存在"
- mkdir -p ${REMOTE_EXE_DIR}
- chmod +x ${REMOTE_EXE_DIR}/${BIN_NAME} || { echo "❌ 设置执行权限失败"; exit 1; }
# 停止旧会话容错不存在则忽略
- screen -S ${SCREEN_NAME} -X quit 2>/dev/null || true
- |
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} 2>&1 | tee -a ${LOG_PATH}"
sleep 3 # 延长等待时间确保会话启动
# 验证会话是否启动
if screen -ls | grep -q "${SCREEN_NAME}"; then
echo "✅ 启动成功Screen会话"
screen -ls | grep ${SCREEN_NAME}
else
echo "❌ 启动失败,无${SCREEN_NAME}会话"
screen -ls
exit 1
fi
# ========== 8. 打印部署汇总依赖部署完成 ==========
print-deploy-info:
image: alpine:latest
depends_on: [deploy-to-servers]
commands:
- echo "======================================"
- 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 "======================================"