From 07f55e0139a47a31af61c9b6072cb9f854b8fb96 Mon Sep 17 00:00:00 2001 From: whm <973418690@qq.com> Date: Wed, 18 Mar 2026 18:11:54 +0800 Subject: [PATCH] 1 --- README.md | 4 ++-- pull-and-restart.sh | 11 +++++++--- restart.sh | 50 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 52 insertions(+), 13 deletions(-) mode change 100644 => 100755 pull-and-restart.sh mode change 100644 => 100755 restart.sh diff --git a/README.md b/README.md index 39083d2..ce0a193 100644 --- a/README.md +++ b/README.md @@ -97,10 +97,10 @@ docker compose up -d --build 2. **服务器**:进入项目目录,**以 Gitea 为准**,直接执行拉取并重启脚本(脚本内会 `git fetch` + `git reset --hard origin/master`,本地修改会被覆盖)。 ```bash cd /www/yh_web # 或你的项目路径 - export REGISTRY_MIRROR=docker.m.daocloud.io/library/ # 可选,脚本有默认 ./pull-and-restart.sh ``` - 若你已手动执行过 `git pull` 且报错 `Your local changes would be overwritten`,先以远程为准:`git fetch origin && git reset --hard origin/master`,再执行 `./pull-and-restart.sh`。脚本内已含默认 `REGISTRY_MIRROR`,一般直接 `./pull-and-restart.sh` 即可。 + **重要**:`deploy/` 下构建产物(web/admin 静态文件、api 二进制)**不在仓库里**,仅靠 `git pull` 不会生成。拉取后**必须执行** `./pull-and-restart.sh`(或 `./restart.sh`)才会构建并启动,否则访问会 403/404。脚本已记录可执行权限,拉取后可直接 `./pull-and-restart.sh`,无需 chmod。 + 若你已手动执行过 `git pull` 且报错 `Your local changes would be overwritten`,先以远程为准:`git fetch origin && git reset --hard origin/master`,再执行 `./pull-and-restart.sh`。 采用**挂目录 + 替换文件**部署:脚本将 web/admin 构建到 `deploy/web/dist`、`deploy/admin/dist`,api 二进制到 `deploy/api/server`,容器挂载这些目录;更新时只重新构建产物并重启,无需重建前端镜像,仅 api 使用轻量运行时镜像。详见 `deploy/README.md`。构建会从 DaoCloud 等镜像拉取 node、nginx、golang、alpine、mongo,启动后**对外仅 443**,由 compose 内 Nginx 反代到 api/web/admin,证书按脚本自动处理。 diff --git a/pull-and-restart.sh b/pull-and-restart.sh old mode 100644 new mode 100755 index ffe3862..a70c3cf --- a/pull-and-restart.sh +++ b/pull-and-restart.sh @@ -1,12 +1,10 @@ #!/usr/bin/env bash # 拉取代码并重启:缺什么自动安装(curl、Git、Docker、Docker Compose),再 git 拉取 + docker compose 构建启动 -# 用法:cd 项目根 && ./pull-and-restart.sh(若 Permission denied 则先执行 bash pull-and-restart.sh 或 chmod +x pull-and-restart.sh restart.sh) +# 用法:cd 项目根 && ./pull-and-restart.sh(仓库中已记录可执行权限,拉取后可直接执行) # 行尾:LF set -e ROOT="${PROJECT_ROOT:-$(cd "$(dirname "$0")" && pwd)}" cd "$ROOT" -# 拉取后可能无可执行权限,先自修复以便下次可直接 ./ 执行 -chmod +x "$ROOT/pull-and-restart.sh" "$ROOT/restart.sh" 2>/dev/null || true run_sudo() { sudo "$@"; } @@ -298,6 +296,13 @@ echo "构建 api 二进制 -> deploy/api/server ..." run_sudo docker run --rm -v "$ROOT/server:/src" -v "$ROOT/deploy/api:/out" -w /src -e GOPROXY="${GOPROXY}" \ "${REGISTRY_MIRROR}golang:1.21-alpine" sh -c "go build -mod=vendor -o /out/server ." +# 确保容器内 nginx 可读(拉取后直接执行时权限一致) +run_sudo chmod -R a+rX "$ROOT/deploy/web/dist" "$ROOT/deploy/admin/dist" 2>/dev/null || true +if [ ! -f "$ROOT/deploy/web/dist/index.html" ] || [ ! -f "$ROOT/deploy/admin/dist/index.html" ]; then + echo "错误: 构建产物不完整(缺少 index.html)。若仅做了 git pull 未执行本脚本,请完整执行: ./pull-and-restart.sh" >&2 + exit 1 +fi + # 仅构建 api 运行时镜像(轻量,无业务代码);web/admin 使用官方 nginx 镜像无需构建 compose_cmd build api diff --git a/restart.sh b/restart.sh old mode 100644 new mode 100755 index 6487083..fc2308a --- a/restart.sh +++ b/restart.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# 直接重启:缺什么自动安装(curl、Docker、Docker Compose),再 docker compose 重启,不拉代码 -# 用法:cd 项目根 && chmod +x restart.sh && ./restart.sh +# 仅不拉代码,其余与 pull-and-restart.sh 一致:构建到 deploy/ 并重启 +# 用法:cd 项目根 && ./restart.sh(拉取后可直接执行,无需 chmod) # 行尾:LF set -e ROOT="${PROJECT_ROOT:-$(cd "$(dirname "$0")" && pwd)}" @@ -166,7 +166,7 @@ compose_cmd() { run_sudo env REGISTRY_MIRROR="${REGISTRY_MIRROR}" GOPROXY="${GOPROXY}" $COMPOSE_CMD "$@" } -echo "重启 yh_web ($ROOT)..." +echo "重启 yh_web ($ROOT)(不拉代码,仅构建并启动)..." # 环境配置:缺失时从 server/.env.example 复制 if [ ! -f server/.env ]; then @@ -176,14 +176,48 @@ if [ ! -f server/.env ]; then else mkdir -p server ND="${NGINX_DOMAIN:-yuheng.yuxindazhineng.com}" - printf 'MONGODB_URI=mongodb://mongo:27017\nMONGODB_DB=yxd-agent-testing\nPORT=9527\nGIN_MODE=release\nALLOWED_ORIGINS=https://%s\n' "$ND" > server/.env + printf 'MONGODB_URI=mongodb://mongo:27017\nMONGODB_DB=yxd-agent-testing\nPORT=8088\nGIN_MODE=release\nALLOWED_ORIGINS=https://%s\n' "$ND" > server/.env echo "已创建默认 server/.env" fi fi -[ -f server/.env ] && sed -i 's/\r$//' server/.env +[ -f server/.env ] && sed -i 's/\r$//' server/.env 2>/dev/null || true [ -f server/.env ] && set -a && source server/.env && set +a +export GOPROXY="${GOPROXY:-https://goproxy.cn,direct}" export REGISTRY_MIRROR="${REGISTRY_MIRROR:-docker.m.daocloud.io/library/}" + +# 与 pull-and-restart 一致:宿主机 9527 检查 +if grep -q '9527' "$ROOT/docker-compose.yml" 2>/dev/null; then + echo "错误: docker-compose.yml 仍含 9527,会与 sshd 冲突。请拉取最新代码后再执行。" >&2 + exit 1 +fi + +# 构建到 deploy/(与 pull-and-restart.sh 相同,仅无 git 拉取) +mkdir -p "$ROOT/deploy/web/dist" "$ROOT/deploy/admin/dist" "$ROOT/deploy/api" +echo "构建 web 前端 -> deploy/web/dist ..." +run_sudo docker run --rm -v "$ROOT/web:/app" -v "$ROOT/deploy/web/dist:/out" -w /app \ + "${REGISTRY_MIRROR}node:20-alpine" sh -c "rm -rf /out/* 2>/dev/null; (npm ci --legacy-peer-deps 2>/dev/null || npm install --legacy-peer-deps) && npm run build && cp -r dist/. /out/" +echo "构建 admin 前端 -> deploy/admin/dist ..." +run_sudo docker run --rm -v "$ROOT/admin:/app" -v "$ROOT/deploy/admin/dist:/out" -w /app \ + "${REGISTRY_MIRROR}node:20-alpine" sh -c "rm -rf /out/* 2>/dev/null; (npm ci --legacy-peer-deps 2>/dev/null || npm install --legacy-peer-deps) && npm run build && cp -r dist/. /out/" +echo "构建 api 二进制 -> deploy/api/server ..." +run_sudo docker run --rm -v "$ROOT/server:/src" -v "$ROOT/deploy/api:/out" -w /src -e GOPROXY="${GOPROXY}" \ + "${REGISTRY_MIRROR}golang:1.21-alpine" sh -c "go build -mod=vendor -o /out/server ." +run_sudo chmod -R a+rX "$ROOT/deploy/web/dist" "$ROOT/deploy/admin/dist" 2>/dev/null || true +if [ ! -f "$ROOT/deploy/web/dist/index.html" ] || [ ! -f "$ROOT/deploy/admin/dist/index.html" ]; then + echo "错误: 构建产物不完整(缺少 index.html),请检查上方构建日志。" >&2 + exit 1 +fi +compose_cmd build api + +MONGO_IMAGE="${REGISTRY_MIRROR}mongo:7" +if ! run_sudo docker image inspect "$MONGO_IMAGE" >/dev/null 2>&1; then + echo "拉取 mongo 镜像(仅首次或镜像缺失时)..." + run_sudo docker pull "$MONGO_IMAGE" || true +else + echo "mongo 镜像已存在,跳过拉取." +fi + NGINX_DOMAIN="${NGINX_DOMAIN:-yuheng.yuxindazhineng.com}" NGINX_SSL_DIR="/etc/ssl/yh_web/$NGINX_DOMAIN" NGINX_CONF_NAME="${NGINX_DOMAIN}.conf" @@ -195,15 +229,15 @@ if [ -f "$ROOT/nginx/$NGINX_DOMAIN.pem" ] && [ -f "$ROOT/nginx/$NGINX_DOMAIN.key run_sudo chmod 600 "$NGINX_SSL_DIR/privkey.pem" elif [ -f "$ROOT/nginx/fullchain.pem" ] && [ -f "$ROOT/nginx/privkey.pem" ]; then run_sudo cp -f "$ROOT/nginx/fullchain.pem" "$ROOT/nginx/privkey.pem" "$NGINX_SSL_DIR/" + run_sudo chmod 644 "$NGINX_SSL_DIR/fullchain.pem" run_sudo chmod 600 "$NGINX_SSL_DIR/privkey.pem" 2>/dev/null || true elif [ -f "$ROOT/nginx/$NGINX_DOMAIN/fullchain.pem" ] && [ -f "$ROOT/nginx/$NGINX_DOMAIN/privkey.pem" ]; then run_sudo cp -f "$ROOT/nginx/$NGINX_DOMAIN/fullchain.pem" "$ROOT/nginx/$NGINX_DOMAIN/privkey.pem" "$NGINX_SSL_DIR/" + run_sudo chmod 644 "$NGINX_SSL_DIR/fullchain.pem" run_sudo chmod 600 "$NGINX_SSL_DIR/privkey.pem" 2>/dev/null || true fi -[ -f "$NGINX_SSL_DIR/fullchain.pem" ] && [ -f "$NGINX_SSL_DIR/privkey.pem" ] && echo "已同步证书到 $NGINX_SSL_DIR" compose_cmd down 2>/dev/null || true -run_sudo docker pull "${REGISTRY_MIRROR}mongo:7" 2>/dev/null || true -compose_cmd up -d +compose_cmd up -d --force-recreate if [ -f "$ROOT/nginx/$NGINX_CONF_NAME" ]; then run_sudo cp -f "$ROOT/nginx/$NGINX_CONF_NAME" /etc/nginx/conf.d/ 2>/dev/null || true