Add Docker Compose deployment setup

This commit is contained in:
SepComet 2026-05-06 10:42:50 +08:00
parent 74fb6ec0a0
commit f0a6da915a
7 changed files with 324 additions and 4 deletions

10
.dockerignore Normal file
View File

@ -0,0 +1,10 @@
node_modules
dist
.git
.gitignore
.env
.env.*
.astro
.omc
.omx
.codex

52
Dockerfile Normal file
View File

@ -0,0 +1,52 @@
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
ARG GITEA_BASE_URL=""
ARG GITEA_TOKEN=""
ARG GITEA_USERNAME=""
ARG SEAFILE_BASE_URL=""
ARG SEAFILE_TOKEN=""
ARG SYNC_OUTPUT_DIR="src/data/generated"
ARG STRICT_SYNC="false"
ARG SEAFILE_MIRROR_DOWNLOADS="false"
ARG DOWNLOADS_OUTPUT_DIR="public/downloads"
ARG GITEA_ACTIVITY_DAYS="70"
ARG GITEA_ACTIVITY_PER_DAY_LIMIT="50"
ARG GITEA_RECENT_ITEM_LIMIT="8"
ARG GITEA_REQUEST_TIMEOUT_MS="15000"
ARG GITEA_REQUEST_CONCURRENCY="5"
ARG SEAFILE_REQUEST_TIMEOUT_MS="15000"
ENV GITEA_BASE_URL="${GITEA_BASE_URL}" \
GITEA_TOKEN="${GITEA_TOKEN}" \
GITEA_USERNAME="${GITEA_USERNAME}" \
SEAFILE_BASE_URL="${SEAFILE_BASE_URL}" \
SEAFILE_TOKEN="${SEAFILE_TOKEN}" \
SYNC_OUTPUT_DIR="${SYNC_OUTPUT_DIR}" \
STRICT_SYNC="${STRICT_SYNC}" \
SEAFILE_MIRROR_DOWNLOADS="${SEAFILE_MIRROR_DOWNLOADS}" \
DOWNLOADS_OUTPUT_DIR="${DOWNLOADS_OUTPUT_DIR}" \
GITEA_ACTIVITY_DAYS="${GITEA_ACTIVITY_DAYS}" \
GITEA_ACTIVITY_PER_DAY_LIMIT="${GITEA_ACTIVITY_PER_DAY_LIMIT}" \
GITEA_RECENT_ITEM_LIMIT="${GITEA_RECENT_ITEM_LIMIT}" \
GITEA_REQUEST_TIMEOUT_MS="${GITEA_REQUEST_TIMEOUT_MS}" \
GITEA_REQUEST_CONCURRENCY="${GITEA_REQUEST_CONCURRENCY}" \
SEAFILE_REQUEST_TIMEOUT_MS="${SEAFILE_REQUEST_TIMEOUT_MS}"
RUN npm run rebuild
FROM nginx:1.27-alpine AS runtime
COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget -q -O /dev/null http://127.0.0.1/ || exit 1

View File

@ -81,6 +81,7 @@ npm run rebuild
- `TODO.md`:当前推进计划
- `docs/rebuild-trigger-spec.md`AstrBot / cron 重建触发与错误码约定
- `docs/content-sync-guide.md`:环境变量、映射文件、同步脚本职责、故障排查
- `docs/docker-deploy.md`Docker / Compose 部署说明
- `docs/ui-design-spec.md`UI 设计规范
## 内容入口
@ -121,6 +122,24 @@ REBUILD_RESULT {...}
- `docs/rebuild-trigger-spec.md`
## Docker / Compose 部署
最小启动方式:
```bash
docker compose up -d --build
```
默认端口:
```text
http://localhost:8080
```
详细说明见:
- `docs/docker-deploy.md`
## 当前实现边界
- 当前默认策略是失败时回退 seed data而不是保留上一轮 generated 文件

View File

@ -89,10 +89,10 @@
### 4. 补部署文件与部署说明
- [ ] 增加 `Dockerfile`
- [ ] 增加 `docker-compose.yml`
- [ ] 明确静态产物部署方式
- [ ] 写清部署步骤与重建入口
- [x] 增加 `Dockerfile`
- [x] 增加 `docker-compose.yml`
- [x] 明确静态产物部署方式
- [x] 写清部署步骤与重建入口
### 5. 补运行文档

26
docker-compose.yml Normal file
View File

@ -0,0 +1,26 @@
services:
homepage:
build:
context: .
dockerfile: Dockerfile
args:
GITEA_BASE_URL: ${GITEA_BASE_URL:-}
GITEA_TOKEN: ${GITEA_TOKEN:-}
GITEA_USERNAME: ${GITEA_USERNAME:-}
SEAFILE_BASE_URL: ${SEAFILE_BASE_URL:-}
SEAFILE_TOKEN: ${SEAFILE_TOKEN:-}
SYNC_OUTPUT_DIR: ${SYNC_OUTPUT_DIR:-src/data/generated}
STRICT_SYNC: ${STRICT_SYNC:-false}
SEAFILE_MIRROR_DOWNLOADS: ${SEAFILE_MIRROR_DOWNLOADS:-false}
DOWNLOADS_OUTPUT_DIR: ${DOWNLOADS_OUTPUT_DIR:-public/downloads}
GITEA_ACTIVITY_DAYS: ${GITEA_ACTIVITY_DAYS:-70}
GITEA_ACTIVITY_PER_DAY_LIMIT: ${GITEA_ACTIVITY_PER_DAY_LIMIT:-50}
GITEA_RECENT_ITEM_LIMIT: ${GITEA_RECENT_ITEM_LIMIT:-8}
GITEA_REQUEST_TIMEOUT_MS: ${GITEA_REQUEST_TIMEOUT_MS:-15000}
GITEA_REQUEST_CONCURRENCY: ${GITEA_REQUEST_CONCURRENCY:-5}
SEAFILE_REQUEST_TIMEOUT_MS: ${SEAFILE_REQUEST_TIMEOUT_MS:-15000}
image: personal-homepage:latest
container_name: personal-homepage
ports:
- "${HOMEPAGE_PORT:-8080}:80"
restart: unless-stopped

18
docker/nginx/default.conf Normal file
View File

@ -0,0 +1,18 @@
server {
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ $uri/index.html =404;
}
location = /50x.html {
internal;
}
error_page 500 502 503 504 /50x.html;
}

195
docs/docker-deploy.md Normal file
View File

@ -0,0 +1,195 @@
# Docker / Compose 部署说明
当前提供的是最小可用静态部署方案:
- 构建阶段:在 Docker build 中执行 `npm run rebuild`
- 运行阶段:使用 Nginx 提供 `dist/` 静态文件
## 文件
- `Dockerfile`
- `docker-compose.yml`
- `docker/nginx/default.conf`
## 使用方式
### 1. 准备环境变量
确保仓库根目录有可用的 `.env`,或在执行 `docker compose` 前导出这些变量:
- `GITEA_BASE_URL`
- `GITEA_TOKEN`
- `GITEA_USERNAME`
- `SEAFILE_BASE_URL`
- `SEAFILE_TOKEN`
可选:
- `STRICT_SYNC`
- `HOMEPAGE_PORT`
- 其余同步调优参数
`docker-compose.yml` 会把这些值作为 **build args** 传给 Dockerfile用于构建时同步和静态生成。
### 环境变量是怎么注入的
当前链路是:
```text
宿主机环境变量 / 项目根目录 .env
-> docker compose 读取变量
-> docker-compose.yml 的 build.args
-> Dockerfile 的 ARG
-> Dockerfile 的 ENV
-> npm run rebuild
```
也就是说,`docker-compose.yml` 自己并不保存真实值,它只是引用变量,例如:
```yaml
args:
GITEA_BASE_URL: ${GITEA_BASE_URL:-}
```
含义是:
- 如果宿主机环境或 `.env` 里有 `GITEA_BASE_URL`,就把它传进去
- 如果没有,就用空字符串
然后 `Dockerfile` 再接住:
```dockerfile
ARG GITEA_BASE_URL=""
ENV GITEA_BASE_URL="${GITEA_BASE_URL}"
```
这样 `npm run rebuild` 在镜像构建阶段就能读取到这些变量。
### `.env` 和 compose 的关系
当前项目里,同一个 `.env` 同时服务两条路径:
1. **本地直接执行**
```bash
npm run rebuild
```
Node 通过:
```bash
--env-file-if-exists=.env
```
读取 `.env`
2. **Docker Compose 构建**
```bash
docker compose up -d --build
```
Compose 会自动读取项目根目录 `.env`,并将变量传给 `build.args`
所以可以把 `.env` 理解成:
- 本地脚本运行配置
- Docker 构建时同步配置
共用的一份构建环境变量文件。
### 为什么用 build args 而不是运行时环境变量
因为这个项目的 Gitea / Seafile token 只在**构建阶段**需要:
- 构建时同步远端数据
- 构建时生成静态页面
最终运行时容器只是 Nginx 提供 `dist/`,不再访问 Gitea / Seafile也不需要 token。
### 修改环境变量后要怎么生效
因为变量是注入到 **构建阶段** 的,所以修改 `.env` 后需要重新 build
```bash
docker compose up -d --build
```
如果只执行:
```bash
docker compose restart
```
不会重新同步,也不会重新生成静态产物。
### 2. 构建并启动
```bash
docker compose up -d --build
```
默认会把站点暴露到:
```text
http://localhost:8080
```
如需修改端口:
```bash
HOMEPAGE_PORT=80 docker compose up -d --build
```
### 3. 查看日志
```bash
docker compose logs -f homepage
```
### 4. 停止
```bash
docker compose down
```
## 部署方式说明
当前 compose 方案是:
1. 构建镜像时执行 `npm run rebuild`
2. 生成 `dist/`
3. 将 `dist/` 拷贝进 Nginx 容器
4. 运行时只提供静态文件服务
这意味着:
- 运行中的容器不需要 Gitea / Seafile token
- token 只在镜像构建阶段使用
- 每次内容更新后,需要重新 build 镜像
## 与 AstrBot 的配合方式
如果后续由 AstrBot 触发重建,推荐:
1. AstrBot 在服务器上拉最新代码
2. AstrBot 执行 `docker compose up -d --build`
3. AstrBot 根据命令结果发送成功 / 失败通知
如果你想让 AstrBot 先单独判断同步 / 构建错误码,再决定是否部署,也可以先执行:
```bash
npm run rebuild
```
通过后再执行:
```bash
docker compose up -d --build
```
## 当前限制
- compose 里还没有反向代理、HTTPS、域名配置
- 还没有单独拆“构建容器”和“运行容器”的外部流水线
- 还没有持久化部署产物或零停机切换策略