chore: add remote deploy scripts
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
REMOTE_HOST="${REMOTE_HOST:-hey-01}"
|
||||
DEPLOY_DIR="${DEPLOY_DIR:-/root/docker/newapi-hey}"
|
||||
APP_CONTAINER="${APP_CONTAINER:-new-api-hey}"
|
||||
APP_PORT="${APP_PORT:-3001}"
|
||||
PUBLIC_URL="${PUBLIC_URL:-https://lztoken.top}"
|
||||
|
||||
NODE_IMAGE="${NODE_IMAGE:-node:22-bullseye}"
|
||||
GO_IMAGE="${GO_IMAGE:-golang:1.26.1-alpine}"
|
||||
GOPROXY_VALUE="${GOPROXY_VALUE:-https://goproxy.cn,direct}"
|
||||
FRONT_BUILD_HEAP_MB="${FRONT_BUILD_HEAP_MB:-8192}"
|
||||
|
||||
SYNC_EXCLUDES=(
|
||||
".git"
|
||||
".env"
|
||||
"docker-compose.yml"
|
||||
"data"
|
||||
"logs"
|
||||
"redis"
|
||||
"backups"
|
||||
".update_tmp"
|
||||
"web/node_modules"
|
||||
)
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
scripts/deploy-hey-01.sh
|
||||
|
||||
Optional environment variables:
|
||||
REMOTE_HOST SSH host alias, default: hey-01
|
||||
DEPLOY_DIR Remote deploy dir, default: /root/docker/newapi-hey
|
||||
APP_CONTAINER Container name, default: new-api-hey
|
||||
APP_PORT Local bind port on remote host, default: 3001
|
||||
PUBLIC_URL Public URL for final check, default: https://lztoken.top
|
||||
NODE_IMAGE Node image for frontend build, default: node:22-bullseye
|
||||
GO_IMAGE Go image for backend build, default: golang:1.26.1-alpine
|
||||
GOPROXY_VALUE GOPROXY for remote build, default: https://goproxy.cn,direct
|
||||
FRONT_BUILD_HEAP_MB Node heap limit in MB, default: 8192
|
||||
EOF
|
||||
}
|
||||
|
||||
log() {
|
||||
printf '[deploy-hey-01] %s\n' "$*"
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
printf 'Missing required command: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
remote_bash() {
|
||||
local script="$1"
|
||||
shift
|
||||
ssh "$REMOTE_HOST" 'bash -s' -- "$@" <<<"$script"
|
||||
}
|
||||
|
||||
sync_source() {
|
||||
log "Syncing source to ${REMOTE_HOST}:${DEPLOY_DIR}"
|
||||
local rsync_args=(
|
||||
-az
|
||||
--delete
|
||||
)
|
||||
local exclude
|
||||
for exclude in "${SYNC_EXCLUDES[@]}"; do
|
||||
rsync_args+=(--exclude "$exclude")
|
||||
done
|
||||
rsync "${rsync_args[@]}" "${ROOT_DIR}/" "${REMOTE_HOST}:${DEPLOY_DIR}/"
|
||||
}
|
||||
|
||||
verify_remote_layout() {
|
||||
log "Checking remote layout"
|
||||
remote_bash '
|
||||
set -euo pipefail
|
||||
deploy_dir="$1"
|
||||
test -d "$deploy_dir"
|
||||
test -f "$deploy_dir/.env"
|
||||
test -f "$deploy_dir/docker-compose.yml"
|
||||
test -f "$deploy_dir/web/package.json"
|
||||
test -f "$deploy_dir/web/package-lock.json"
|
||||
test -f "$deploy_dir/web/src/helpers/render.jsx"
|
||||
test -d "$deploy_dir/data"
|
||||
test -d "$deploy_dir/logs"
|
||||
' "$DEPLOY_DIR"
|
||||
}
|
||||
|
||||
build_frontend() {
|
||||
log "Building frontend dist on ${REMOTE_HOST}"
|
||||
remote_bash '
|
||||
set -euo pipefail
|
||||
deploy_dir="$1"
|
||||
node_image="$2"
|
||||
heap_mb="$3"
|
||||
|
||||
docker run --rm --network host \
|
||||
-v "${deploy_dir}:/src" \
|
||||
"${node_image}" \
|
||||
sh -lc "
|
||||
set -e
|
||||
rm -rf /tmp/web
|
||||
cp -a /src/web /tmp/web
|
||||
cd /tmp/web
|
||||
npm ci --legacy-peer-deps
|
||||
NODE_OPTIONS=--max-old-space-size=${heap_mb} npm run build
|
||||
rm -rf /src/web/dist
|
||||
cp -a dist /src/web/dist
|
||||
"
|
||||
' "$DEPLOY_DIR" "$NODE_IMAGE" "$FRONT_BUILD_HEAP_MB"
|
||||
}
|
||||
|
||||
build_backend() {
|
||||
log "Building backend binary on ${REMOTE_HOST}"
|
||||
remote_bash '
|
||||
set -euo pipefail
|
||||
deploy_dir="$1"
|
||||
go_image="$2"
|
||||
goproxy_value="$3"
|
||||
|
||||
docker run --rm --network host \
|
||||
-e "GOPROXY=${goproxy_value}" \
|
||||
-v "${deploy_dir}:/src" \
|
||||
-w /src \
|
||||
"${go_image}" \
|
||||
sh -lc "
|
||||
set -e
|
||||
export PATH=/usr/local/go/bin:\$PATH
|
||||
VERSION_VALUE=\$(cat VERSION 2>/dev/null || true)
|
||||
go mod download
|
||||
go build -ldflags \"-s -w -X github.com/QuantumNous/new-api/common.Version=\${VERSION_VALUE}\" -o new-api
|
||||
"
|
||||
' "$DEPLOY_DIR" "$GO_IMAGE" "$GOPROXY_VALUE"
|
||||
}
|
||||
|
||||
swap_binary() {
|
||||
log "Replacing binary in ${APP_CONTAINER}"
|
||||
remote_bash '
|
||||
set -euo pipefail
|
||||
deploy_dir="$1"
|
||||
app_container="$2"
|
||||
|
||||
backup_dir="${deploy_dir}/backups"
|
||||
mkdir -p "$backup_dir"
|
||||
ts="$(date +%Y%m%d%H%M%S)"
|
||||
|
||||
docker inspect "$app_container" >/dev/null 2>&1
|
||||
docker cp "${app_container}:/new-api" "${backup_dir}/new-api.${ts}.bak" || true
|
||||
docker cp "${deploy_dir}/new-api" "${app_container}:/new-api"
|
||||
docker restart "$app_container" >/dev/null
|
||||
' "$DEPLOY_DIR" "$APP_CONTAINER"
|
||||
}
|
||||
|
||||
verify_deploy() {
|
||||
log "Checking local health endpoint"
|
||||
remote_bash '
|
||||
set -euo pipefail
|
||||
app_container="$1"
|
||||
app_port="$2"
|
||||
public_url="$3"
|
||||
|
||||
local_url="http://127.0.0.1:${app_port}/api/status"
|
||||
ok=0
|
||||
for _ in $(seq 1 45); do
|
||||
if curl -fsS "$local_url" >/dev/null 2>&1; then
|
||||
ok=1
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [[ "$ok" != "1" ]]; then
|
||||
echo "Health check failed: ${local_url}" >&2
|
||||
docker logs --tail 120 "$app_container" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker ps --filter "name=${app_container}" --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"
|
||||
curl -fsS "$local_url" >/dev/null
|
||||
curl -I -m 20 "$public_url" | sed -n "1,12p"
|
||||
' "$APP_CONTAINER" "$APP_PORT" "$PUBLIC_URL"
|
||||
}
|
||||
|
||||
main() {
|
||||
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
require_cmd ssh
|
||||
require_cmd rsync
|
||||
|
||||
log "Starting deploy to ${REMOTE_HOST}"
|
||||
sync_source
|
||||
verify_remote_layout
|
||||
build_frontend
|
||||
build_backend
|
||||
swap_binary
|
||||
verify_deploy
|
||||
log "Deploy completed successfully"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
REMOTE_HOST="${REMOTE_HOST:-ubt}"
|
||||
DEPLOY_DIR="${DEPLOY_DIR:-/root/docker/newapi}"
|
||||
APP_CONTAINER="${APP_CONTAINER:-new-api}"
|
||||
APP_PORT="${APP_PORT:-3000}"
|
||||
PUBLIC_URL="${PUBLIC_URL:-https://leexx.site}"
|
||||
|
||||
NODE_IMAGE="${NODE_IMAGE:-node:22-bullseye}"
|
||||
GO_IMAGE="${GO_IMAGE:-golang:1.26.1-alpine}"
|
||||
GOPROXY_VALUE="${GOPROXY_VALUE:-https://goproxy.cn,direct}"
|
||||
FRONT_BUILD_HEAP_MB="${FRONT_BUILD_HEAP_MB:-8192}"
|
||||
|
||||
SYNC_EXCLUDES=(
|
||||
".git"
|
||||
".env"
|
||||
"docker-compose.yml"
|
||||
"data"
|
||||
"logs"
|
||||
"redis"
|
||||
"backups"
|
||||
".update_tmp"
|
||||
"web/node_modules"
|
||||
)
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
scripts/deploy-ubt.sh
|
||||
|
||||
Optional environment variables:
|
||||
REMOTE_HOST SSH host alias, default: ubt
|
||||
DEPLOY_DIR Remote deploy dir, default: /root/docker/newapi
|
||||
APP_CONTAINER Container name, default: new-api
|
||||
APP_PORT Local bind port on remote host, default: 3000
|
||||
PUBLIC_URL Public URL for final check, default: https://leexx.site
|
||||
NODE_IMAGE Node image for frontend build, default: node:22-bullseye
|
||||
GO_IMAGE Go image for backend build, default: golang:1.26.1-alpine
|
||||
GOPROXY_VALUE GOPROXY for remote build, default: https://goproxy.cn,direct
|
||||
FRONT_BUILD_HEAP_MB Node heap limit in MB, default: 8192
|
||||
EOF
|
||||
}
|
||||
|
||||
log() {
|
||||
printf '[deploy-ubt] %s\n' "$*"
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
printf 'Missing required command: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
remote_bash() {
|
||||
local script="$1"
|
||||
shift
|
||||
ssh "$REMOTE_HOST" 'bash -s' -- "$@" <<<"$script"
|
||||
}
|
||||
|
||||
sync_source() {
|
||||
log "Syncing source to ${REMOTE_HOST}:${DEPLOY_DIR}"
|
||||
local rsync_args=(
|
||||
-az
|
||||
--delete
|
||||
)
|
||||
local exclude
|
||||
for exclude in "${SYNC_EXCLUDES[@]}"; do
|
||||
rsync_args+=(--exclude "$exclude")
|
||||
done
|
||||
rsync "${rsync_args[@]}" "${ROOT_DIR}/" "${REMOTE_HOST}:${DEPLOY_DIR}/"
|
||||
}
|
||||
|
||||
verify_remote_layout() {
|
||||
log "Checking remote layout"
|
||||
remote_bash '
|
||||
set -euo pipefail
|
||||
deploy_dir="$1"
|
||||
test -d "$deploy_dir"
|
||||
test -f "$deploy_dir/.env"
|
||||
test -f "$deploy_dir/docker-compose.yml"
|
||||
test -f "$deploy_dir/web/package.json"
|
||||
test -f "$deploy_dir/web/package-lock.json"
|
||||
test -f "$deploy_dir/web/src/helpers/render.jsx"
|
||||
test -d "$deploy_dir/data"
|
||||
test -d "$deploy_dir/logs"
|
||||
' "$DEPLOY_DIR"
|
||||
}
|
||||
|
||||
build_frontend() {
|
||||
log "Building frontend dist on ${REMOTE_HOST}"
|
||||
remote_bash '
|
||||
set -euo pipefail
|
||||
deploy_dir="$1"
|
||||
node_image="$2"
|
||||
heap_mb="$3"
|
||||
|
||||
docker run --rm --network host \
|
||||
-v "${deploy_dir}:/src" \
|
||||
"${node_image}" \
|
||||
sh -lc "
|
||||
set -e
|
||||
rm -rf /tmp/web
|
||||
cp -a /src/web /tmp/web
|
||||
cd /tmp/web
|
||||
npm ci --legacy-peer-deps
|
||||
NODE_OPTIONS=--max-old-space-size=${heap_mb} npm run build
|
||||
rm -rf /src/web/dist
|
||||
cp -a dist /src/web/dist
|
||||
"
|
||||
' "$DEPLOY_DIR" "$NODE_IMAGE" "$FRONT_BUILD_HEAP_MB"
|
||||
}
|
||||
|
||||
build_backend() {
|
||||
log "Building backend binary on ${REMOTE_HOST}"
|
||||
remote_bash '
|
||||
set -euo pipefail
|
||||
deploy_dir="$1"
|
||||
go_image="$2"
|
||||
goproxy_value="$3"
|
||||
|
||||
docker run --rm --network host \
|
||||
-e "GOPROXY=${goproxy_value}" \
|
||||
-v "${deploy_dir}:/src" \
|
||||
-w /src \
|
||||
"${go_image}" \
|
||||
sh -lc "
|
||||
set -e
|
||||
export PATH=/usr/local/go/bin:\$PATH
|
||||
VERSION_VALUE=\$(cat VERSION 2>/dev/null || true)
|
||||
go mod download
|
||||
go build -ldflags \"-s -w -X github.com/QuantumNous/new-api/common.Version=\${VERSION_VALUE}\" -o new-api
|
||||
"
|
||||
' "$DEPLOY_DIR" "$GO_IMAGE" "$GOPROXY_VALUE"
|
||||
}
|
||||
|
||||
swap_binary() {
|
||||
log "Replacing binary in ${APP_CONTAINER}"
|
||||
remote_bash '
|
||||
set -euo pipefail
|
||||
deploy_dir="$1"
|
||||
app_container="$2"
|
||||
|
||||
backup_dir="${deploy_dir}/backups"
|
||||
mkdir -p "$backup_dir"
|
||||
ts="$(date +%Y%m%d%H%M%S)"
|
||||
|
||||
docker inspect "$app_container" >/dev/null 2>&1
|
||||
docker cp "${app_container}:/new-api" "${backup_dir}/new-api.${ts}.bak" || true
|
||||
docker cp "${deploy_dir}/new-api" "${app_container}:/new-api"
|
||||
docker restart "$app_container" >/dev/null
|
||||
' "$DEPLOY_DIR" "$APP_CONTAINER"
|
||||
}
|
||||
|
||||
verify_deploy() {
|
||||
log "Checking local health endpoint"
|
||||
remote_bash '
|
||||
set -euo pipefail
|
||||
app_container="$1"
|
||||
app_port="$2"
|
||||
public_url="$3"
|
||||
|
||||
local_url="http://127.0.0.1:${app_port}/api/status"
|
||||
ok=0
|
||||
for _ in $(seq 1 45); do
|
||||
if curl -fsS "$local_url" >/dev/null 2>&1; then
|
||||
ok=1
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [[ "$ok" != "1" ]]; then
|
||||
echo "Health check failed: ${local_url}" >&2
|
||||
docker logs --tail 120 "$app_container" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker ps --filter "name=${app_container}" --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"
|
||||
curl -fsS "$local_url" >/dev/null
|
||||
curl -I -m 20 "$public_url" | sed -n "1,12p"
|
||||
' "$APP_CONTAINER" "$APP_PORT" "$PUBLIC_URL"
|
||||
}
|
||||
|
||||
main() {
|
||||
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
require_cmd ssh
|
||||
require_cmd rsync
|
||||
|
||||
log "Starting deploy to ${REMOTE_HOST}"
|
||||
sync_source
|
||||
verify_remote_layout
|
||||
build_frontend
|
||||
build_backend
|
||||
swap_binary
|
||||
verify_deploy
|
||||
log "Deploy completed successfully"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Vendored
-1
@@ -22,5 +22,4 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.idea
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
+11887
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user