docs: add cron deploy script and ignore local runtime artifacts
This commit is contained in:
parent
df4afe8a57
commit
31796260cc
|
|
@ -35,9 +35,19 @@ Desktop.ini
|
||||||
# local runtime artifacts
|
# local runtime artifacts
|
||||||
*.pid
|
*.pid
|
||||||
*.seed
|
*.seed
|
||||||
|
.omc/
|
||||||
|
.omx/
|
||||||
|
scripts/.omx/
|
||||||
|
.codex/skills/ui-ux-pro-max/scripts/__pycache__/
|
||||||
|
|
||||||
public/images/gallery
|
public/images/gallery
|
||||||
|
|
||||||
# generated sync data
|
# generated sync data
|
||||||
src/data/generated/*.json
|
src/data/generated/*.json
|
||||||
!src/data/generated/.gitkeep
|
!src/data/generated/.gitkeep
|
||||||
|
|
||||||
|
# generated logs under content/logs, keep tracked templates
|
||||||
|
src/content/logs/*.md
|
||||||
|
!src/content/logs/homepage-design-system.md
|
||||||
|
!src/content/logs/homepage-landing-build.md
|
||||||
|
!src/content/logs/homepage-requirements.md
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ npm run rebuild
|
||||||
- `docs/rebuild-trigger-spec.md`:AstrBot / cron 重建触发与错误码约定
|
- `docs/rebuild-trigger-spec.md`:AstrBot / cron 重建触发与错误码约定
|
||||||
- `docs/content-sync-guide.md`:环境变量、映射文件、同步脚本职责、故障排查
|
- `docs/content-sync-guide.md`:环境变量、映射文件、同步脚本职责、故障排查
|
||||||
- `docs/docker-deploy.md`:Docker / Compose 部署说明
|
- `docs/docker-deploy.md`:Docker / Compose 部署说明
|
||||||
|
- `docs/linux-cron-deploy.md`:宿主机定时同步 log、重建 homepage、刷新 Docker 的脚本说明
|
||||||
- `docs/ui-design-spec.md`:UI 设计规范
|
- `docs/ui-design-spec.md`:UI 设计规范
|
||||||
|
|
||||||
## 内容入口
|
## 内容入口
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
# Linux 定时部署脚本说明
|
||||||
|
|
||||||
|
适用于当前这套流程:
|
||||||
|
|
||||||
|
- log 由另一个服务生成
|
||||||
|
- log 落到宿主机目录
|
||||||
|
- 宿主机定时任务复制 log 到 homepage 仓库
|
||||||
|
- 宿主机执行 `npm run rebuild`
|
||||||
|
- 宿主机执行 `docker compose up -d --build homepage`
|
||||||
|
|
||||||
|
统一脚本:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scripts/deploy-homepage.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 当前默认值
|
||||||
|
|
||||||
|
脚本里的默认值已经按当前主页项目直接写死:
|
||||||
|
|
||||||
|
| 变量 | 默认值 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `LOG_SOURCE_DIR` | `/home/basil/bot/data/git-summary` | 日志生成服务写入的源目录 |
|
||||||
|
| `SITE_DIR` | `/home/basil/source/personal-homepage` | 个人主页仓库根目录 |
|
||||||
|
| `LOG_TARGET_DIR` | `$SITE_DIR/src/content/logs` | 复制后的日志目标目录 |
|
||||||
|
| `DOCKER_COMPOSE_FILE` | `$SITE_DIR/docker-compose.yml` | Compose 文件 |
|
||||||
|
| `DOCKER_SERVICE_NAME` | `homepage` | 要重建/重启的服务名 |
|
||||||
|
| `RSYNC_DELETE` | `false` | 同步时默认不删除旧日志 |
|
||||||
|
| `RUN_LOCAL_REBUILD` | `true` | 默认先在宿主机执行 `npm run rebuild` |
|
||||||
|
| `LOCK_FILE` | `/tmp/personal-homepage-deploy.lock` | 防止重复执行的锁文件 |
|
||||||
|
|
||||||
|
如果你的机器目录不同,可以通过环境变量覆盖。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 脚本实际执行内容
|
||||||
|
|
||||||
|
脚本默认顺序如下:
|
||||||
|
|
||||||
|
1. 检查目录与命令是否存在
|
||||||
|
2. 获取锁文件,避免重复执行
|
||||||
|
3. 把 `LOG_SOURCE_DIR` 同步到 `LOG_TARGET_DIR`
|
||||||
|
4. 进入 `SITE_DIR` 执行 `npm run rebuild`
|
||||||
|
5. 进入 `SITE_DIR` 执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f "$DOCKER_COMPOSE_FILE" up -d --build "$DOCKER_SERVICE_NAME"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 直接执行
|
||||||
|
|
||||||
|
使用默认值:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/deploy-homepage.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
覆盖部分变量:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LOG_SOURCE_DIR=/data/logs \
|
||||||
|
SITE_DIR=/srv/personal-homepage \
|
||||||
|
RSYNC_DELETE=true \
|
||||||
|
./scripts/deploy-homepage.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
如果你只想做 log 同步 + Docker 重建,不想先在宿主机跑一次 `npm run rebuild`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
RUN_LOCAL_REBUILD=false ./scripts/deploy-homepage.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 推荐的 cron 配置
|
||||||
|
|
||||||
|
例如每天 00:00 执行一次:
|
||||||
|
|
||||||
|
```cron
|
||||||
|
0 0 * * * /home/basil/source/personal-homepage/scripts/deploy-homepage.sh >> /var/log/personal-homepage-deploy.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
例如每 30 分钟执行一次:
|
||||||
|
|
||||||
|
```cron
|
||||||
|
*/30 * * * * /home/basil/source/personal-homepage/scripts/deploy-homepage.sh >> /var/log/personal-homepage-deploy.log 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
因为脚本内部已经带了 `LOCK_FILE` 锁,所以 cron 不一定还要额外再包一层 `flock`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 推荐前提
|
||||||
|
|
||||||
|
宿主机应具备:
|
||||||
|
|
||||||
|
- `docker`
|
||||||
|
- `docker compose`
|
||||||
|
- `npm`
|
||||||
|
- `rsync`(推荐,有则优先使用)
|
||||||
|
- `flock`(推荐,用于避免重入)
|
||||||
|
|
||||||
|
如果没有 `rsync`,脚本会自动退回到 `cp -a`。
|
||||||
|
|
||||||
|
如果没有 `flock`,脚本也能跑,只是没有并发保护。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 建议
|
||||||
|
|
||||||
|
当前建议:
|
||||||
|
|
||||||
|
- `LOG_SOURCE_DIR` 作为日志服务的宿主机挂载目录
|
||||||
|
- `SITE_DIR` 直接指向 homepage 仓库根目录
|
||||||
|
- 优先先手动跑通一次:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/deploy-homepage.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
确认没问题后再挂 cron。
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
# 日志源目录:由日志生产服务写入
|
||||||
|
# 默认值:/home/basil/bot/data/git-summary
|
||||||
|
LOG_SOURCE_DIR="${LOG_SOURCE_DIR:-/home/basil/bot/data/git-summary}"
|
||||||
|
|
||||||
|
# 个人主页仓库目录
|
||||||
|
# 默认值:/home/basil/source/personal-homepage
|
||||||
|
SITE_DIR="${SITE_DIR:-/home/basil/source/personal-homepage}"
|
||||||
|
|
||||||
|
# 日志目标目录:复制到 homepage 仓库内
|
||||||
|
# 默认值:$SITE_DIR/src/content/logs
|
||||||
|
LOG_TARGET_DIR="${LOG_TARGET_DIR:-${SITE_DIR}/src/content/logs}"
|
||||||
|
|
||||||
|
# Docker Compose 配置与服务名
|
||||||
|
# 默认 compose 文件:$SITE_DIR/docker-compose.yml
|
||||||
|
# 默认服务名:homepage
|
||||||
|
DOCKER_COMPOSE_FILE="${DOCKER_COMPOSE_FILE:-${SITE_DIR}/docker-compose.yml}"
|
||||||
|
DOCKER_SERVICE_NAME="${DOCKER_SERVICE_NAME:-homepage}"
|
||||||
|
|
||||||
|
# 是否在同步时删除目标目录中源目录已不存在的文件
|
||||||
|
# 默认值:false
|
||||||
|
RSYNC_DELETE="${RSYNC_DELETE:-false}"
|
||||||
|
|
||||||
|
# 是否先在宿主机执行一次 npm run rebuild
|
||||||
|
# 默认值:true
|
||||||
|
RUN_LOCAL_REBUILD="${RUN_LOCAL_REBUILD:-true}"
|
||||||
|
|
||||||
|
# 锁文件路径,避免定时任务重入
|
||||||
|
# 默认值:/tmp/personal-homepage-deploy.lock
|
||||||
|
LOCK_FILE="${LOCK_FILE:-/tmp/personal-homepage-deploy.lock}"
|
||||||
|
|
||||||
|
timestamp() {
|
||||||
|
date '+%Y-%m-%d %H:%M:%S'
|
||||||
|
}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '[%s] %s\n' "$(timestamp)" "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
log "ERROR: $*"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
require_command() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || fail "缺少命令: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
is_true() {
|
||||||
|
case "${1,,}" in
|
||||||
|
1|true|yes|on) return 0 ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
sync_logs() {
|
||||||
|
mkdir -p "$LOG_TARGET_DIR"
|
||||||
|
|
||||||
|
if command -v rsync >/dev/null 2>&1; then
|
||||||
|
local -a rsync_args=(-av)
|
||||||
|
if is_true "$RSYNC_DELETE"; then
|
||||||
|
rsync_args+=(--delete)
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "同步日志: $LOG_SOURCE_DIR -> $LOG_TARGET_DIR"
|
||||||
|
rsync "${rsync_args[@]}" "${LOG_SOURCE_DIR}/" "${LOG_TARGET_DIR}/"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "未找到 rsync,改用 cp -a 复制日志"
|
||||||
|
|
||||||
|
if is_true "$RSYNC_DELETE"; then
|
||||||
|
find "$LOG_TARGET_DIR" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp -a "${LOG_SOURCE_DIR}/." "$LOG_TARGET_DIR/"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_local_rebuild() {
|
||||||
|
log "开始宿主机构建校验: npm run rebuild"
|
||||||
|
(
|
||||||
|
cd "$SITE_DIR"
|
||||||
|
npm run rebuild
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh_docker_service() {
|
||||||
|
log "刷新 Docker 服务: $DOCKER_SERVICE_NAME"
|
||||||
|
(
|
||||||
|
cd "$SITE_DIR"
|
||||||
|
docker compose -f "$DOCKER_COMPOSE_FILE" up -d --build "$DOCKER_SERVICE_NAME"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
main_impl() {
|
||||||
|
require_command docker
|
||||||
|
if is_true "$RUN_LOCAL_REBUILD"; then
|
||||||
|
require_command npm
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker compose version >/dev/null 2>&1 || fail "当前环境不可用 docker compose"
|
||||||
|
|
||||||
|
[[ -d "$LOG_SOURCE_DIR" ]] || fail "日志源目录不存在: $LOG_SOURCE_DIR"
|
||||||
|
[[ -d "$SITE_DIR" ]] || fail "站点目录不存在: $SITE_DIR"
|
||||||
|
[[ -f "$DOCKER_COMPOSE_FILE" ]] || fail "docker compose 文件不存在: $DOCKER_COMPOSE_FILE"
|
||||||
|
|
||||||
|
log "部署开始"
|
||||||
|
log "LOG_SOURCE_DIR=$LOG_SOURCE_DIR"
|
||||||
|
log "LOG_TARGET_DIR=$LOG_TARGET_DIR"
|
||||||
|
log "SITE_DIR=$SITE_DIR"
|
||||||
|
log "DOCKER_COMPOSE_FILE=$DOCKER_COMPOSE_FILE"
|
||||||
|
log "DOCKER_SERVICE_NAME=$DOCKER_SERVICE_NAME"
|
||||||
|
log "RSYNC_DELETE=$RSYNC_DELETE"
|
||||||
|
log "RUN_LOCAL_REBUILD=$RUN_LOCAL_REBUILD"
|
||||||
|
log "LOCK_FILE=$LOCK_FILE"
|
||||||
|
|
||||||
|
sync_logs
|
||||||
|
|
||||||
|
if is_true "$RUN_LOCAL_REBUILD"; then
|
||||||
|
run_local_rebuild
|
||||||
|
else
|
||||||
|
log "跳过宿主机 npm run rebuild(RUN_LOCAL_REBUILD=false)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
refresh_docker_service
|
||||||
|
|
||||||
|
log "部署完成"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
if ! command -v flock >/dev/null 2>&1; then
|
||||||
|
log "未找到 flock,跳过锁保护"
|
||||||
|
main_impl "$@"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$LOCK_FILE")"
|
||||||
|
exec 9>"$LOCK_FILE"
|
||||||
|
|
||||||
|
if ! flock -n 9; then
|
||||||
|
fail "已有部署任务在执行中,锁文件: $LOCK_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "已获取部署锁: $LOCK_FILE"
|
||||||
|
main_impl "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
{
|
{
|
||||||
"name": "personal-homepage",
|
"name": "personal-homepage",
|
||||||
"description": "一个由 Markdown 与 JSON 驱动的公开个人主页,用于展示项目、开发日志与外部分享。",
|
"description": "一个由 Markdown 与 JSON 驱动的公开个人主页,用于展示项目、开发日志与外部分享。",
|
||||||
"gitea_repo": "sepcomet/personal-homepage",
|
"gitea_repo": "basil/personal-homepage",
|
||||||
"cover_image": "/images/projects/personal-homepage.svg",
|
"cover_image": "/images/projects/personal-homepage.svg",
|
||||||
"demo_video": "",
|
"demo_video": "",
|
||||||
"download_link": "",
|
"download_link": "",
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
{
|
{
|
||||||
"name": "devlog-pipeline",
|
"name": "devlog-pipeline",
|
||||||
"description": "规划中的开发日志生成与写入链路,用于把日常开发过程沉淀为结构化 Markdown 内容。",
|
"description": "规划中的开发日志生成与写入链路,用于把日常开发过程沉淀为结构化 Markdown 内容。",
|
||||||
"gitea_repo": "sepcomet/devlog-pipeline",
|
"gitea_repo": "basil/devlog-pipeline",
|
||||||
"cover_image": "/images/projects/devlog-pipeline.svg",
|
"cover_image": "/images/projects/devlog-pipeline.svg",
|
||||||
"demo_video": "",
|
"demo_video": "",
|
||||||
"download_link": "",
|
"download_link": "",
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
{
|
{
|
||||||
"name": "gitea-activity-panel",
|
"name": "gitea-activity-panel",
|
||||||
"description": "面向个人主页的 Gitea 活动概览模块,计划提供贡献热力图与近期活动列表。",
|
"description": "面向个人主页的 Gitea 活动概览模块,计划提供贡献热力图与近期活动列表。",
|
||||||
"gitea_repo": "sepcomet/gitea-activity-panel",
|
"gitea_repo": "basil/gitea-activity-panel",
|
||||||
"cover_image": "/images/projects/gitea-activity-panel.svg",
|
"cover_image": "/images/projects/gitea-activity-panel.svg",
|
||||||
"demo_video": "",
|
"demo_video": "",
|
||||||
"download_link": "",
|
"download_link": "",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue