Files

96 lines
3.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# pay v2 → pangolin1 专用部署脚本:交叉编译 → 传 pangolin1 → 首次装
# 用户/目录/systemd unit/config.yaml → 备份旧二进制 → daemon-reload + enable --now →
# 探活(失败自动回滚)。幂等:重复跑只刷新二进制,不覆盖 /etc/pay-v2/pay.env 或已存在的
# /etc/pay-v2/config.yaml。
#
# 用法(pay 仓根目录执行):
# ./deploy/pangolin1/deploy.sh
#
# 前提:
# - ~/.ssh/config 有 pangolin1 别名(密钥登录);pangolin1 上以 root 身份操作
# (systemctl / 装 unit / 建系统用户都需要)。
# - 首次部署前,必须已在 pangolin1 上手工创建 /etc/pay-v2/pay.env
# (参照 deploy/pangolin1/pay.env.example 填真值,真值一律走 Bitwarden/rbw)。
# 本脚本刻意不生成/不覆盖这个文件——密钥不能经这条流水线过一遍。
#
# shellcheck disable=SC2029 # 下面 ssh 命令里的 $HOST/$DIR/$SVC 等都是本脚本的本地
# 变量,故意要在客户端展开后再传给远端 shell(远端命令里没有任何"远端才存在的变量"),
# 这正是想要的行为,不是需要转义的 bug。
set -euo pipefail
HOST=pangolin1
SVC=pay-v2
SVC_USER=payv2
DIR=/opt/pay-v2
DATA_DIR=/var/lib/pay-v2
ETC_DIR=/etc/pay-v2
BIN=/tmp/pay-v2d-release
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
HERE="$REPO_ROOT/deploy/pangolin1"
log() { printf '\033[1;32m[deploy-pangolin1]\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[deploy-pangolin1]\033[0m %s\n' "$*" >&2; }
echo "[1/6] 交叉编译 linux/amd64 …"
(
cd "$REPO_ROOT"
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o "$BIN" .
)
echo "[2/6] 首次初始化(幂等):系统用户 + 目录 …"
ssh "$HOST" "
set -e
id -u '$SVC_USER' >/dev/null 2>&1 || useradd --system --no-create-home --shell /usr/sbin/nologin '$SVC_USER'
mkdir -p '$DIR' '$DATA_DIR' '$ETC_DIR'
chown -R '$SVC_USER:$SVC_USER' '$DATA_DIR'
"
echo "[3/6] 装 systemd unit + config.yaml(不覆盖已存在的 config.yaml/pay.env)…"
scp -q "$HERE/pay-v2.service" "$HOST:/etc/systemd/system/pay-v2.service"
if ssh "$HOST" "[ -f '$ETC_DIR/config.yaml' ]"; then
log "$ETC_DIR/config.yaml 已存在,跳过覆盖(改配置需手动: scp $HERE/config.yaml $HOST:$ETC_DIR/config.yaml)"
else
scp -q "$HERE/config.yaml" "$HOST:$ETC_DIR/config.yaml"
log "已写入首个 $ETC_DIR/config.yaml"
fi
if ! ssh "$HOST" "[ -f '$ETC_DIR/pay.env' ]"; then
warn "$ETC_DIR/pay.env 不存在!请先在 $HOST 上手工创建(参照 $HERE/pay.env.example,真值走 Bitwarden),"
warn "否则 systemctl start 会因缺 env 报错或以空凭证跑起来。继续执行,但服务大概率起不来。"
fi
ssh "$HOST" "
[ -f '$ETC_DIR/pay.env' ] && { chown root:'$SVC_USER' '$ETC_DIR/pay.env'; chmod 640 '$ETC_DIR/pay.env'; } || true
chown root:root '$ETC_DIR/config.yaml' 2>/dev/null || true
chmod 644 '$ETC_DIR/config.yaml' 2>/dev/null || true
"
echo "[4/6] 上传二进制 + 备份旧版 + 切换 …"
scp -q "$BIN" "$HOST:$DIR/payd-new"
ssh "$HOST" "
set -e
[ -f '$DIR/payd' ] && cp '$DIR/payd' '$DIR/payd.bak' || true
mv '$DIR/payd-new' '$DIR/payd'
chmod +x '$DIR/payd'
chown '$SVC_USER:$SVC_USER' '$DIR/payd'
"
echo "[5/6] daemon-reload + enable --now …"
ssh "$HOST" "systemctl daemon-reload && systemctl enable --now $SVC && systemctl restart $SVC"
echo "[6/6] 探活 …"
if ssh "$HOST" "curl -fsS --retry 8 --retry-delay 1 --retry-connrefused -o /dev/null -w 'health %{http_code}\n' http://127.0.0.1:8090/health"; then
echo "✅ 发布完成(上一版已备份在 $DIR/payd.bak,若存在)"
else
echo "❌ 探活失败,自动回滚 …"
ssh "$HOST" "
if [ -f '$DIR/payd.bak' ]; then
cp '$DIR/payd.bak' '$DIR/payd' && systemctl restart '$SVC'
else
systemctl stop '$SVC'
fi
"
echo "↩️ 已回滚/停止。请 ssh $HOST 'journalctl -u $SVC -n 100 --no-pager' 排查后重试。"
exit 1
fi