ci: switch prod deploy to server-side git pull and go build
This commit is contained in:
@@ -19,21 +19,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23.x'
|
||||
|
||||
- name: Download modules
|
||||
run: go mod download
|
||||
|
||||
- name: Build linux binary
|
||||
run: |
|
||||
mkdir -p tmp
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags "-s -w" -o tmp/wx_service ./cmd/api
|
||||
gzip -9 -c tmp/wx_service > tmp/wx_service.gz
|
||||
ls -lh tmp/wx_service tmp/wx_service.gz
|
||||
|
||||
- name: Prepare SSH
|
||||
env:
|
||||
SSH_KEY: ${{ secrets.PROD_SSH_KEY }}
|
||||
@@ -51,36 +36,22 @@ jobs:
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
ssh-keyscan -p "${PORT:-22}" "$HOST" >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Upload binary to server
|
||||
- name: Deploy on server (git pull + go build)
|
||||
env:
|
||||
HOST: ${{ secrets.PROD_HOST }}
|
||||
PORT: ${{ secrets.PROD_PORT }}
|
||||
USER: ${{ secrets.PROD_USER }}
|
||||
run: |
|
||||
set -e
|
||||
REMOTE_BIN_GZ="/tmp/wx_service-${GITHUB_SHA}.gz"
|
||||
SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=15 -o ServerAliveInterval=10 -o ServerAliveCountMax=3"
|
||||
scp -O ${SSH_OPTS} -P "${PORT:-22}" tmp/wx_service.gz "${USER:-root}@${HOST}:${REMOTE_BIN_GZ}"
|
||||
|
||||
- name: Deploy on server
|
||||
env:
|
||||
HOST: ${{ secrets.PROD_HOST }}
|
||||
PORT: ${{ secrets.PROD_PORT }}
|
||||
USER: ${{ secrets.PROD_USER }}
|
||||
run: |
|
||||
set -e
|
||||
REMOTE_BIN_GZ="/tmp/wx_service-${GITHUB_SHA}.gz"
|
||||
SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=15 -o ServerAliveInterval=10 -o ServerAliveCountMax=3"
|
||||
SSH_OPTS="-o BatchMode=yes -o ConnectTimeout=15 -o ServerAliveInterval=10 -o ServerAliveCountMax=6"
|
||||
ssh ${SSH_OPTS} -p "${PORT:-22}" "${USER:-root}@${HOST}" \
|
||||
"APP_DIR='/www/wwwroot/wx_service' \
|
||||
DIST_DIR='/www/wwwroot/wx_service/dist' \
|
||||
SOURCE_BIN='${REMOTE_BIN_GZ}' \
|
||||
DEPLOY_REF='${GITHUB_SHA}' \
|
||||
RELEASE_ID='${GITHUB_SHA}' \
|
||||
GO_VERSION='1.23.6' \
|
||||
SERVICE_NAME='wx_service' \
|
||||
RUN_USER='www' \
|
||||
RUN_GROUP='www' \
|
||||
PORT='8080' \
|
||||
SYNC_CODE='true' \
|
||||
DEPLOY_REF='${GITHUB_SHA}' \
|
||||
INSTALL_SERVICE='true' \
|
||||
bash -s" < scripts/ops/deploy_binary.sh
|
||||
bash -s" < scripts/ops/deploy_from_source.sh
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
本文档用于 `wx_service` 在宝塔服务器上的自动化发布:
|
||||
- 触发:`main` 分支 push 或手动触发
|
||||
- 流程:GitHub Actions 构建二进制 -> SSH 上传到服务器 -> 远程发布脚本重启并健康检查
|
||||
- 流程:GitHub Actions SSH 触发服务器发布脚本 -> 服务器 git pull + go build -> 重启并健康检查
|
||||
- 特点:不依赖 Docker
|
||||
|
||||
## 1. 服务器约定
|
||||
@@ -13,7 +13,7 @@
|
||||
- 进程端口:`8080`
|
||||
- 反向代理:宝塔 Nginx -> `127.0.0.1:8080`
|
||||
|
||||
> 远程脚本:`scripts/ops/deploy_binary.sh`
|
||||
> 远程脚本:`scripts/ops/deploy_from_source.sh`(内部调用 `scripts/ops/deploy_binary.sh`)
|
||||
|
||||
## 2. GitHub Secrets
|
||||
|
||||
@@ -37,16 +37,18 @@
|
||||
- `/www/wwwroot/wx_service/.env`
|
||||
- `/www/wwwroot/wx_service/dist/.env`
|
||||
3. 开放 `8080` 本地监听,并由 Nginx 反代
|
||||
4. 第一次执行会自动尝试创建 `systemd` 服务 `wx_service`
|
||||
4. 服务器无需 Docker;第一次执行会自动安装 Go 1.23.6(若缺失)并尝试创建 `systemd` 服务 `wx_service`
|
||||
|
||||
## 5. 发布行为
|
||||
|
||||
每次发布会执行:
|
||||
|
||||
1. GitHub Actions 构建 Linux 二进制
|
||||
2. 上传到服务器 `/tmp/wx_service-<commit_sha>`
|
||||
3. 远程脚本执行:
|
||||
1. GitHub Actions 通过 SSH 调用服务器发布脚本
|
||||
2. 服务器执行:
|
||||
- `git fetch` + `git reset --hard <commit_sha>`(同步代码)
|
||||
- 安装/校验 Go 1.23.6
|
||||
- `go mod download` + `go build`
|
||||
3. 远程发布脚本继续执行:
|
||||
- 备份旧二进制到 `/www/wwwroot/wx_service/backups/`
|
||||
- 原子替换 `dist/wx_service`
|
||||
- 重启服务
|
||||
@@ -55,7 +57,7 @@
|
||||
|
||||
## 6. 手动发布(应急)
|
||||
|
||||
在服务器执行:
|
||||
在服务器执行(仅二进制手动发布场景):
|
||||
|
||||
```bash
|
||||
cd /www/wwwroot/wx_service
|
||||
@@ -86,3 +88,19 @@ systemctl restart wx_service
|
||||
pkill -f /www/wwwroot/wx_service/dist/wx_service
|
||||
su -s /bin/bash - www -c "cd /www/wwwroot/wx_service/dist && nohup ./wx_service >> /www/wwwlogs/wx_service.stdout.log 2>&1 &"
|
||||
```
|
||||
|
||||
|
||||
## 8. 手动发布(从源码构建)
|
||||
|
||||
```bash
|
||||
cd /www/wwwroot/wx_service
|
||||
APP_DIR=/www/wwwroot/wx_service \
|
||||
DIST_DIR=/www/wwwroot/wx_service/dist \
|
||||
DEPLOY_REF=main \
|
||||
RELEASE_ID=manual-$(date +%Y%m%d%H%M%S) \
|
||||
GO_VERSION=1.23.6 \
|
||||
SERVICE_NAME=wx_service \
|
||||
RUN_USER=www RUN_GROUP=www \
|
||||
PORT=8080 \
|
||||
bash scripts/ops/deploy_from_source.sh
|
||||
```
|
||||
|
||||
@@ -39,7 +39,7 @@ health_check() {
|
||||
}
|
||||
|
||||
restart_service() {
|
||||
if command -v systemctl >/dev/null 2>&1 && systemctl list-unit-files | grep -q "^${SERVICE_NAME}.service"; then
|
||||
if command -v systemctl >/dev/null 2>&1 && systemctl cat "${SERVICE_NAME}.service" >/dev/null 2>&1; then
|
||||
log "restarting systemd service: ${SERVICE_NAME}"
|
||||
systemctl restart "$SERVICE_NAME"
|
||||
else
|
||||
@@ -58,7 +58,7 @@ create_service_if_needed() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
if systemctl list-unit-files | grep -q "^${SERVICE_NAME}.service"; then
|
||||
if systemctl cat "${SERVICE_NAME}.service" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
APP_DIR="${APP_DIR:-/www/wwwroot/wx_service}"
|
||||
DEPLOY_REF="${DEPLOY_REF:-main}"
|
||||
GO_VERSION="${GO_VERSION:-1.23.6}"
|
||||
GO_ROOT="${GO_ROOT:-/usr/local/go}"
|
||||
GO_BIN="${GO_BIN:-${GO_ROOT}/bin/go}"
|
||||
TMP_BUILD_BIN="${TMP_BUILD_BIN:-/tmp/wx_service-${DEPLOY_REF:0:12}}"
|
||||
|
||||
DIST_DIR="${DIST_DIR:-${APP_DIR}/dist}"
|
||||
SERVICE_NAME="${SERVICE_NAME:-wx_service}"
|
||||
RUN_USER="${RUN_USER:-www}"
|
||||
RUN_GROUP="${RUN_GROUP:-www}"
|
||||
PORT="${PORT:-8080}"
|
||||
RELEASE_ID="${RELEASE_ID:-${DEPLOY_REF}}"
|
||||
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
||||
}
|
||||
|
||||
install_go_if_needed() {
|
||||
local need_install="false"
|
||||
|
||||
if [ ! -x "$GO_BIN" ]; then
|
||||
need_install="true"
|
||||
else
|
||||
local current
|
||||
current="$($GO_BIN version 2>/dev/null | awk '{print $3}' | sed 's/^go//')"
|
||||
if [ -z "$current" ] || [ "$current" != "$GO_VERSION" ]; then
|
||||
need_install="true"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$need_install" = "false" ]; then
|
||||
log "go toolchain ok: $($GO_BIN version)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "installing go ${GO_VERSION}"
|
||||
local pkg="/tmp/go${GO_VERSION}.linux-amd64.tar.gz"
|
||||
curl -fL "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz" -o "$pkg"
|
||||
rm -rf "$GO_ROOT"
|
||||
tar -C /usr/local -xzf "$pkg"
|
||||
rm -f "$pkg"
|
||||
log "go installed: $($GO_BIN version)"
|
||||
}
|
||||
|
||||
if [ ! -d "$APP_DIR/.git" ]; then
|
||||
echo "invalid app repo: $APP_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
install_go_if_needed
|
||||
|
||||
log "syncing repo to ${DEPLOY_REF}"
|
||||
git -C "$APP_DIR" fetch --all --prune
|
||||
git -C "$APP_DIR" reset --hard "$DEPLOY_REF"
|
||||
|
||||
export PATH="$GO_ROOT/bin:$PATH"
|
||||
export GOPROXY="${GOPROXY:-https://goproxy.cn,direct}"
|
||||
|
||||
log "downloading go modules"
|
||||
cd "$APP_DIR"
|
||||
"$GO_BIN" mod download
|
||||
|
||||
log "building binary"
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 "$GO_BIN" build -trimpath -ldflags "-s -w" -o "$TMP_BUILD_BIN" ./cmd/api
|
||||
chmod 755 "$TMP_BUILD_BIN"
|
||||
|
||||
log "publishing binary via deploy_binary.sh"
|
||||
APP_DIR="$APP_DIR" \
|
||||
DIST_DIR="$DIST_DIR" \
|
||||
SOURCE_BIN="$TMP_BUILD_BIN" \
|
||||
SERVICE_NAME="$SERVICE_NAME" \
|
||||
RUN_USER="$RUN_USER" \
|
||||
RUN_GROUP="$RUN_GROUP" \
|
||||
PORT="$PORT" \
|
||||
RELEASE_ID="$RELEASE_ID" \
|
||||
SYNC_CODE="false" \
|
||||
INSTALL_SERVICE="true" \
|
||||
bash "$APP_DIR/scripts/ops/deploy_binary.sh"
|
||||
|
||||
log "source deploy done"
|
||||
Reference in New Issue
Block a user