Add reusable remote deploy script
Automate the Linux binary upload, remote container rebuild, and health checks so the proxy can be redeployed to the server with a single command. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
149
scripts/deploy-remote.sh
Executable file
149
scripts/deploy-remote.sh
Executable file
@@ -0,0 +1,149 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
REMOTE_HOST=150.158.105.6 \
|
||||||
|
REMOTE_USER=root \
|
||||||
|
REMOTE_PASSWORD='your-password' \
|
||||||
|
./scripts/deploy-remote.sh
|
||||||
|
|
||||||
|
Optional environment variables:
|
||||||
|
REMOTE_PORT=22
|
||||||
|
REMOTE_DIR=/root/lingma-proxy-compose
|
||||||
|
REMOTE_PUBLIC_PORT=13123
|
||||||
|
REMOTE_CONTAINER_NAME=lingma-proxy-uploaded
|
||||||
|
REMOTE_IMAGE_NAME=lingma-proxy-uploaded
|
||||||
|
REMOTE_SESSION_BUNDLE_PATH=/root/lingma-proxy-compose/secrets/lingma-session.b64
|
||||||
|
LINGMA_REMOTE_BASE_URL=https://lingma.alibabacloud.com
|
||||||
|
LINGMA_SOURCE_TYPE=vsix
|
||||||
|
LINGMA_VSIX_URL=https://tongyi-code.oss-cn-hangzhou.aliyuncs.com/vscode/tongyi-lingma-latest.vsix
|
||||||
|
LINGMA_MARKETPLACE_PUBLISHER=Alibaba-Cloud
|
||||||
|
LINGMA_MARKETPLACE_EXTENSION=tongyi-lingma
|
||||||
|
LINGMA_PROXY_MODEL=org_auto
|
||||||
|
VERIFY_PUBLIC=false
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
require_env() {
|
||||||
|
local name="$1"
|
||||||
|
if [ -z "${!name:-}" ]; then
|
||||||
|
echo "Missing required environment variable: $name" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || {
|
||||||
|
echo "Required command not found: $1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
require_cmd go
|
||||||
|
require_cmd sshpass
|
||||||
|
require_cmd ssh
|
||||||
|
require_cmd scp
|
||||||
|
require_cmd curl
|
||||||
|
|
||||||
|
require_env REMOTE_HOST
|
||||||
|
require_env REMOTE_USER
|
||||||
|
require_env REMOTE_PASSWORD
|
||||||
|
|
||||||
|
REMOTE_PORT="${REMOTE_PORT:-22}"
|
||||||
|
REMOTE_DIR="${REMOTE_DIR:-/root/lingma-proxy-compose}"
|
||||||
|
REMOTE_PUBLIC_PORT="${REMOTE_PUBLIC_PORT:-13123}"
|
||||||
|
REMOTE_CONTAINER_NAME="${REMOTE_CONTAINER_NAME:-lingma-proxy-uploaded}"
|
||||||
|
REMOTE_IMAGE_NAME="${REMOTE_IMAGE_NAME:-lingma-proxy-uploaded}"
|
||||||
|
REMOTE_SESSION_BUNDLE_PATH="${REMOTE_SESSION_BUNDLE_PATH:-$REMOTE_DIR/secrets/lingma-session.b64}"
|
||||||
|
LINGMA_REMOTE_BASE_URL="${LINGMA_REMOTE_BASE_URL:-https://lingma.alibabacloud.com}"
|
||||||
|
LINGMA_SOURCE_TYPE="${LINGMA_SOURCE_TYPE:-vsix}"
|
||||||
|
LINGMA_VSIX_URL="${LINGMA_VSIX_URL:-https://tongyi-code.oss-cn-hangzhou.aliyuncs.com/vscode/tongyi-lingma-latest.vsix}"
|
||||||
|
LINGMA_MARKETPLACE_PUBLISHER="${LINGMA_MARKETPLACE_PUBLISHER:-Alibaba-Cloud}"
|
||||||
|
LINGMA_MARKETPLACE_EXTENSION="${LINGMA_MARKETPLACE_EXTENSION:-tongyi-lingma}"
|
||||||
|
LINGMA_PROXY_MODEL="${LINGMA_PROXY_MODEL:-org_auto}"
|
||||||
|
VERIFY_PUBLIC="${VERIFY_PUBLIC:-false}"
|
||||||
|
|
||||||
|
SSH_BASE=(sshpass -p "$REMOTE_PASSWORD" ssh -o StrictHostKeyChecking=no -p "$REMOTE_PORT" "$REMOTE_USER@$REMOTE_HOST")
|
||||||
|
SCP_BASE=(sshpass -p "$REMOTE_PASSWORD" scp -o StrictHostKeyChecking=no -P "$REMOTE_PORT")
|
||||||
|
|
||||||
|
work_dir="$(mktemp -d)"
|
||||||
|
trap 'rm -rf "$work_dir"' EXIT
|
||||||
|
|
||||||
|
binary_path="$work_dir/lingma-proxy"
|
||||||
|
dockerfile_path="$work_dir/Dockerfile.uploaded"
|
||||||
|
env_path="$work_dir/.env.container"
|
||||||
|
|
||||||
|
cat >"$dockerfile_path" <<'EOF'
|
||||||
|
FROM debian:bookworm-slim
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/*
|
||||||
|
WORKDIR /app
|
||||||
|
COPY lingma-proxy /usr/local/bin/lingma-proxy
|
||||||
|
EXPOSE 8095
|
||||||
|
CMD ["lingma-proxy", "--host", "0.0.0.0", "--port", "8095", "--backend", "remote"]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >"$env_path" <<EOF
|
||||||
|
LINGMA_REMOTE_BASE_URL=$LINGMA_REMOTE_BASE_URL
|
||||||
|
LINGMA_REMOTE_AUTH_FILE=
|
||||||
|
LINGMA_BOOTSTRAP_ENABLED=true
|
||||||
|
LINGMA_SOURCE_TYPE=$LINGMA_SOURCE_TYPE
|
||||||
|
LINGMA_VSIX_URL=$LINGMA_VSIX_URL
|
||||||
|
LINGMA_MARKETPLACE_PUBLISHER=$LINGMA_MARKETPLACE_PUBLISHER
|
||||||
|
LINGMA_MARKETPLACE_EXTENSION=$LINGMA_MARKETPLACE_EXTENSION
|
||||||
|
LINGMA_BIN=/app/data/bin/Lingma
|
||||||
|
LINGMA_BOOTSTRAP_OUTPUT_DIR=/app/data/bin/release
|
||||||
|
LINGMA_BOOTSTRAP_ALWAYS=true
|
||||||
|
LINGMA_FORCE_REFRESH=false
|
||||||
|
LINGMA_WORK_DIR=/app/data/.lingma/vscode/sharedClientCache
|
||||||
|
LINGMA_SESSION_BUNDLE=
|
||||||
|
LINGMA_SESSION_BUNDLE_FILE=/secrets/lingma-session.b64
|
||||||
|
LINGMA_PROXY_BACKEND=remote
|
||||||
|
LINGMA_PROXY_SESSION_MODE=auto
|
||||||
|
LINGMA_PROXY_MODEL=$LINGMA_PROXY_MODEL
|
||||||
|
LINGMA_PROXY_TIMEOUT_SECONDS=0
|
||||||
|
LINGMA_REMOTE_FALLBACK_ENABLED=true
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "==> Building Linux amd64 binary locally"
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o "$binary_path" ./cmd/lingma-ipc-proxy
|
||||||
|
|
||||||
|
echo "==> Ensuring remote deploy directory exists"
|
||||||
|
"${SSH_BASE[@]}" "mkdir -p '$REMOTE_DIR' '$REMOTE_DIR/data' '$REMOTE_DIR/secrets'"
|
||||||
|
|
||||||
|
echo "==> Checking remote session bundle"
|
||||||
|
"${SSH_BASE[@]}" "test -f '$REMOTE_SESSION_BUNDLE_PATH'"
|
||||||
|
|
||||||
|
echo "==> Uploading binary and runtime files"
|
||||||
|
"${SCP_BASE[@]}" "$binary_path" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/lingma-proxy"
|
||||||
|
"${SCP_BASE[@]}" "$dockerfile_path" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/Dockerfile.uploaded"
|
||||||
|
"${SCP_BASE[@]}" "$env_path" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/.env.container"
|
||||||
|
|
||||||
|
echo "==> Rebuilding remote runtime image"
|
||||||
|
"${SSH_BASE[@]}" "cd '$REMOTE_DIR' && docker build -f Dockerfile.uploaded -t '$REMOTE_IMAGE_NAME' ."
|
||||||
|
|
||||||
|
echo "==> Recreating remote container"
|
||||||
|
"${SSH_BASE[@]}" "cd '$REMOTE_DIR' && docker rm -f '$REMOTE_CONTAINER_NAME' >/dev/null 2>&1 || true && docker run -d --name '$REMOTE_CONTAINER_NAME' --restart unless-stopped --env-file .env.container -p '$REMOTE_PUBLIC_PORT:8095' -v '$REMOTE_DIR/data:/app/data' -v '$REMOTE_DIR/secrets:/secrets:ro' '$REMOTE_IMAGE_NAME' >/dev/null"
|
||||||
|
|
||||||
|
echo "==> Waiting for remote health endpoint"
|
||||||
|
"${SSH_BASE[@]}" 'for i in $(seq 1 24); do curl -fsS "http://127.0.0.1:'"$REMOTE_PUBLIC_PORT"'/runtime/status" && exit 0; sleep 5; done; docker logs --tail 120 '"$REMOTE_CONTAINER_NAME"' >&2; exit 1'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "==> Remote models"
|
||||||
|
"${SSH_BASE[@]}" "curl -fsS http://127.0.0.1:$REMOTE_PUBLIC_PORT/v1/models"
|
||||||
|
|
||||||
|
if [ "$VERIFY_PUBLIC" = "true" ]; then
|
||||||
|
echo
|
||||||
|
echo "==> Public runtime check"
|
||||||
|
curl -fsS "http://$REMOTE_HOST:$REMOTE_PUBLIC_PORT/runtime/status"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Deploy complete: http://$REMOTE_HOST:$REMOTE_PUBLIC_PORT"
|
||||||
Reference in New Issue
Block a user