From bb27566e385a0bda4fbe6537656175019d9f50e7 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 8 May 2026 07:53:27 +0800 Subject: [PATCH] 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 --- scripts/deploy-remote.sh | 149 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100755 scripts/deploy-remote.sh diff --git a/scripts/deploy-remote.sh b/scripts/deploy-remote.sh new file mode 100755 index 0000000..87dc910 --- /dev/null +++ b/scripts/deploy-remote.sh @@ -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" < 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"