用www用户成个ssh key
sudo -u www ssh-keygen -t rsa -C "your_email@example.com"
自动部署shell脚本
#!/bin/bash
set -euo pipefail
exec > >(tee -a /tmp/deploy.log) 2>&1
#项目要放在宝塔的文件夹路径
APP_DIR=""
#GitHub ssh链接
REPO_SSH=""
# 仓库分支名称
BRANCH="master"
# 要运行的用户
RUN_USER="www"
#sshkey pub文件路径
SSH_KEY=""
# 钉钉机器人通知配置
DINGTALK_WEBHOOK=""
# ========= 输出美化 =========
if [[ -t 1 ]] && command -v tput >/dev/null 2>&1; then
C_RESET="$(tput sgr0)"
C_DIM="$(tput dim)"
C_BOLD="$(tput bold)"
C_RED="$(tput setaf 1)"
C_GREEN="$(tput setaf 2)"
C_YELLOW="$(tput setaf 3)"
C_BLUE="$(tput setaf 4)"
C_CYAN="$(tput setaf 6)"
else
C_RESET=""; C_DIM=""; C_BOLD=""
C_RED=""; C_GREEN=""; C_YELLOW=""; C_BLUE=""; C_CYAN=""
fi
hr() { echo -e "${C_DIM}────────────────────────────────────────────────────────${C_RESET}"; }
ts() { date "+%Y-%m-%d %H:%M:%S"; }
log_title() {
hr
echo -e "${C_BOLD}${C_CYAN}🚀 Deploy${C_RESET} $(ts)"
hr
}
log_kv() { printf " ${C_DIM}%-10s${C_RESET} %s\n" "$1" "$2"; }
log_step() {
STEP_NAME="$1"
STEP_START="$(date +%s)"
hr
echo -e "${C_BOLD}${C_BLUE}▶ ${STEP_NAME}${C_RESET}"
}
log_ok() { echo -e " ${C_GREEN}✔${C_RESET} $*"; }
log_warn() { echo -e " ${C_YELLOW}⚠${C_RESET} $*"; }
log_err() { echo -e " ${C_RED}✘${C_RESET} $*"; }
log_done_step() {
local end
end="$(date +%s)"
local cost=$(( end - STEP_START ))
echo -e " ${C_GREEN}✓ 完成${C_RESET} (${cost}s)"
}
DEPLOY_STATUS="success"
DEPLOY_START_TIME=$(date +%s)
trap 'log_err "发生错误:第 ${LINENO} 行执行失败"; echo -e " ${C_DIM}命令:${BASH_COMMAND}${C_RESET}"; hr; DEPLOY_STATUS="failed"; exit 1' ERR
# ========= 业务函数 =========
run_as_user() {
sudo -n -u "${RUN_USER}" -H bash -c "$*"
}
git_as_user() {
sudo -n -u "${RUN_USER}" -H bash -c \
"GIT_SSH_COMMAND='ssh -i ${SSH_KEY} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new' git $*"
}
send_dingtalk_notification() {
local status="$1"
local message="$2"
local duration="$3"
if [[ -z "${DINGTALK_WEBHOOK}" ]] || [[ "${DINGTALK_WEBHOOK}" == *"YOUR_ACCESS_TOKEN"* ]]; then
log_warn "未配置钉钉 Webhook,跳过通知"
return 0
fi
local title="✅ 部署成功"
if [[ "${status}" == "failed" ]]; then
title="❌ 部署失败"
fi
local markdown_text="#### ${title}
> **项目**: python_ani_search
> **分支**: ${BRANCH}
> **状态**: ${status}
> **耗时**: ${duration}s
> **时间**: $(date '+%Y-%m-%d %H:%M:%S')
${message}"
local response
response=$(curl -s -w "\n%{http_code}" -X POST "${DINGTALK_WEBHOOK}" \
-H 'Content-Type: application/json' \
-d "{
\"msgtype\": \"markdown\",
\"markdown\": {
\"title\": \"${title}\",
\"text\": \"${markdown_text}\"
},
\"at\": {
\"isAtAll\": true
}
}" 2>/dev/null)
local http_code
http_code=$(echo "$response" | tail -n1)
local body
body=$(echo "$response" | sed '$d')
if [[ "${http_code}" == "200" ]]; then
local errcode
errcode=$(echo "$body" | python3 -c "import sys,json;print(json.load(sys.stdin).get('errcode',-1))" 2>/dev/null || echo "-1")
if [[ "${errcode}" == "0" ]]; then
log_ok "钉钉通知已发送"
else
log_warn "钉钉通知发送失败:errcode=${errcode}"
fi
else
log_warn "钉钉通知发送失败:http_code=${http_code}"
fi
}
# ========= 主流程 =========
log_title
echo -e "${C_BOLD}Start${C_RESET}"
log_kv "项目目录:" "${APP_DIR}"
log_kv "仓库地址:" "${REPO_SSH}"
log_kv "分支:" "${BRANCH}"
log_kv "执行用户:" "${RUN_USER}"
log_kv "SSH Key:" "${SSH_KEY}"
log_step "Step0: 检查 SSH Key"
if [ ! -f "${SSH_KEY}" ]; then
log_err "SSH Key 不存在 -> ${SSH_KEY}"
exit 1
fi
chown "${RUN_USER}:${RUN_USER}" "${SSH_KEY}"
chmod 600 "${SSH_KEY}"
log_ok "SSH Key 存在并已修正权限"
log_done_step
log_step "Step1: 检查项目目录"
if [ ! -d "${APP_DIR}" ]; then
log_warn "项目目录不存在,开始创建 -> ${APP_DIR}"
mkdir -p "${APP_DIR}"
chown -R "${RUN_USER}:${RUN_USER}" "${APP_DIR}"
fi
log_ok "目录存在"
log_done_step
log_step "Step2: 拉取/更新代码"
cd "${APP_DIR}"
if [ ! -d "${APP_DIR}/.git" ]; then
log_warn "未初始化 git,开始初始化..."
git_as_user "init"
git_as_user "remote add origin ${REPO_SSH}"
git_as_user "fetch origin ${BRANCH}"
git_as_user "checkout -b ${BRANCH} origin/${BRANCH}"
log_ok "初始化并检出 ${BRANCH}"
else
log_ok "已存在 git 仓库,开始更新..."
git_as_user "remote set-url origin ${REPO_SSH}"
git_as_user "checkout ${BRANCH}"
git_as_user "pull origin ${BRANCH}"
log_ok "已拉取最新代码"
fi
log_done_step
log_step "Step3: 清理不需要的文件/目录"
if [ -f "${APP_DIR}/test" ]; then
rm -f "${APP_DIR}/test"
log_ok "移除 test"
else
log_kv "跳过:" "test 不存在"
fi
if [ -f "${APP_DIR}/README.md" ]; then
rm -f "${APP_DIR}/README.md"
log_ok "移除 README.md"
else
log_kv "跳过:" "README.md 不存在"
fi
if [ -f "${APP_DIR}/.gitignore" ]; then
rm -f "${APP_DIR}/.gitignore"
log_ok "移除 .gitignore"
else
log_kv "跳过:" ".gitignore 不存在"
fi
if [ -d "${APP_DIR}/.github" ]; then
rm -rf "${APP_DIR}/.github"
log_ok "移除 .github/"
else
log_kv "跳过:" ".github/ 不存在"
fi
log_done_step
log_step "Step4: 修正权限"
chown -R "${RUN_USER}:${RUN_USER}" "${APP_DIR}"
log_ok "chown -R ${RUN_USER}:${RUN_USER} ${APP_DIR}"
log_done_step
DEPLOY_END_TIME=$(date +%s)
DEPLOY_DURATION=$((DEPLOY_END_TIME - DEPLOY_START_TIME))
hr
echo -e "${C_BOLD}${C_GREEN}✅ 部署完成${C_RESET}"
echo -e " ${C_DIM}总耗时:${DEPLOY_DURATION}s${C_RESET}"
echo "End"
hr
send_dingtalk_notification "${DEPLOY_STATUS}" "部署任务已完成" "${DEPLOY_DURATION}"
THE END






暂无评论内容