deploy.sh 4.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #!/usr/bin/env bash
  2. # 构建并发布到 /srv/agent-server/app,同步技能目录,重启服务。
  3. # 用法:deploy/deploy.sh(需要 sudo 权限;首次部署前先执行 sudo deploy/install.sh)
  4. set -euo pipefail
  5. cd "$(dirname "$0")/.."
  6. ROOT=/srv/agent-server
  7. pnpm install --frozen-lockfile
  8. pnpm -r build
  9. node scripts/build-sdk.mjs
  10. # 已发布的 SDK 版本不再覆盖:同一代码打包结果逐字节相同,内容不同说明 SDK 有变化,需要先升级版本号
  11. # (packages/shared、client、chat-ui 的 version 一起改;推送工具改 packages/skills-cli)
  12. changed=()
  13. for f in dist-sdk/*.tgz; do
  14. published="$ROOT/app/sdk/$(basename "$f")"
  15. if [ -f "$published" ] && ! cmp -s "$f" "$published"; then changed+=("$(basename "$f")"); fi
  16. done
  17. if [ ${#changed[@]} -gt 0 ]; then
  18. echo "以下 SDK 包已经发布过同一版本,但内容有变化:${changed[*]}" >&2
  19. echo "请先升级版本号再部署(已发布的版本不能覆盖,否则锁定该版本的业务平台重新安装时校验值对不上)" >&2
  20. exit 1
  21. fi
  22. STAGE=$(mktemp -d)
  23. trap 'rm -rf "$STAGE"' EXIT
  24. pnpm --filter @agent-server/server deploy --prod "$STAGE/server" >/dev/null
  25. # 资料库挂载服务(Go,静态编译;同一代码编译结果逐字节相同,没有变化时不重启)
  26. (cd apps/mounter && CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o "$STAGE/agent-mounter" .)
  27. sed "s/__USER__/$(id -un)/" deploy/agent-mounter.service > "$STAGE/agent-mounter.service"
  28. # rclone(远程存储):固定版本的官方程序,下载后校验 sha256,缓存在 ~/.cache/agent-server
  29. RCLONE_VERSION=v1.75.2
  30. RCLONE_SHA256=349ac8fba6ff65d6247043f1750cdcb518ec5d500ef91463a10d37c0ccdf3702
  31. RCLONE_ZIP="$HOME/.cache/agent-server/rclone-$RCLONE_VERSION-linux-amd64.zip"
  32. if ! echo "$RCLONE_SHA256 $RCLONE_ZIP" | sha256sum -c --quiet 2>/dev/null; then
  33. mkdir -p "$(dirname "$RCLONE_ZIP")"
  34. curl -fsSL -o "$RCLONE_ZIP.part" "https://downloads.rclone.org/$RCLONE_VERSION/rclone-$RCLONE_VERSION-linux-amd64.zip"
  35. echo "$RCLONE_SHA256 $RCLONE_ZIP.part" | sha256sum -c --quiet || { echo "rclone 校验失败" >&2; rm -f "$RCLONE_ZIP.part"; exit 1; }
  36. mv "$RCLONE_ZIP.part" "$RCLONE_ZIP"
  37. fi
  38. unzip -p "$RCLONE_ZIP" "rclone-$RCLONE_VERSION-linux-amd64/rclone" > "$STAGE/rclone"
  39. sudo rsync -a --delete "$STAGE/server/" "$ROOT/app/server/"
  40. sudo rsync -a --delete apps/admin/dist/ "$ROOT/app/admin/"
  41. # SDK 包保留旧版本(业务平台可能锁定在旧版本),npm 仓库 /npm/ 按目录中的全部版本提供
  42. sudo mkdir -p "$ROOT/app/sdk"
  43. sudo rsync -a dist-sdk/ "$ROOT/app/sdk/"
  44. sudo rm -f "$ROOT/app/sdk/agent-skills.tgz" "$ROOT/app/sdk/index.json" # 旧的 /sdk/ 分发方式留下的文件
  45. sudo rsync -a --delete skills/ "$ROOT/skills/"
  46. mounter_changed=0
  47. for f in agent-mounter rclone; do
  48. if ! sudo cmp -s "$STAGE/$f" "$ROOT/app/mounter/$f"; then
  49. sudo install -D -m 0755 "$STAGE/$f" "$ROOT/app/mounter/$f"
  50. mounter_changed=1
  51. fi
  52. done
  53. sudo chown -R root:root "$ROOT/app" "$ROOT/skills"
  54. sudo chmod -R a+rX "$ROOT/app" "$ROOT/skills"
  55. # 服务可写目录与 unit 文件(新增目录或修改 unit 后,不必重跑 install.sh)
  56. sudo install -d -o agentsvc -g agentsvc -m 0700 "$ROOT/managed-skills"
  57. # 资料库:托管目录由平台写入;挂载点与挂载服务目录属于部署用户,平台(agentsvc 组)只能进入和读取
  58. sudo install -d -o agentsvc -g agentsvc -m 2770 "$ROOT/knowledge"
  59. sudo install -d -o agentsvc -g agentsvc -m 2770 "$ROOT/knowledge/files"
  60. sudo install -d -o "$(id -un)" -g agentsvc -m 0750 "$ROOT/knowledge/mnt"
  61. sudo install -d -o "$(id -un)" -g agentsvc -m 2750 "$ROOT/mounter"
  62. grep -q '^user_allow_other' /etc/fuse.conf || { echo "请先在 /etc/fuse.conf 中开启 user_allow_other(sudo deploy/install.sh 会处理)" >&2; exit 1; }
  63. reload=0
  64. if ! sudo cmp -s deploy/agent-server.service /etc/systemd/system/agent-server.service; then
  65. sudo install -m 0644 deploy/agent-server.service /etc/systemd/system/agent-server.service
  66. reload=1
  67. fi
  68. if ! sudo cmp -s "$STAGE/agent-mounter.service" /etc/systemd/system/agent-mounter.service; then
  69. sudo install -m 0644 "$STAGE/agent-mounter.service" /etc/systemd/system/agent-mounter.service
  70. reload=1
  71. mounter_changed=1
  72. fi
  73. if [ $reload = 1 ]; then sudo systemctl daemon-reload; fi
  74. sudo systemctl enable --quiet agent-mounter
  75. # 只有挂载程序、rclone 或 unit 有变化时才重启挂载服务(挂载会中断几秒后自动恢复)
  76. if [ $mounter_changed = 1 ] || ! systemctl is-active --quiet agent-mounter; then sudo systemctl restart agent-mounter; fi
  77. sudo systemctl restart agent-server
  78. for _ in $(seq 1 20); do
  79. if curl -sf http://127.0.0.1:8787/healthz >/dev/null; then
  80. echo "部署完成:http://127.0.0.1:8787/admin/"
  81. exit 0
  82. fi
  83. sleep 0.5
  84. done
  85. echo "服务没有正常启动,查看日志:journalctl -u agent-server -n 50" >&2
  86. exit 1