15 KiB
AGENTS.md — deploy.stack
这是一个个人 Docker Compose Stack 集合,用于自托管服务部署。每个子目录是一个独立可部署的服务(即一个"栈")。仓库以中文为主,混用英文;文档文件名使用小写。
架构与组织
<service>/
├── stack.yml / compose.yml / <env>.stack.yml / <env>.yml # Docker Compose 文件
├── env.cfg.example # 环境变量(含敏感信息,应 gitignore)
├── readme.md # 服务说明文档(可选)
└── config/ # 服务配置文件(可选)
顶层目录按职责划分:
| 目录 | 用途 |
|---|---|
<service>/(如 haproxy/、ntfy/、rustfs/) |
每个可部署服务一个子目录 |
builder/ |
开发容器镜像(golang、alpine、nodejs、debian)— 用于容器内编译构建 |
base/ |
基础设施(cadvisor、mongo) |
dbSer/ |
数据库服务栈(MySQL/Percona、Redis、PostgreSQL、MongoDB、etcd),带独立网络 |
webout/ |
Caddy 反向代理配置,面向外部服务 |
crontab/ |
定时任务脚本(硬盘巡检、apt 更新、时间同步) |
apt.list/ |
国内镜像 APT 源配置(阿里云、中科大、华为)及 Docker 安装脚本 |
etc/ |
系统级配置(sysctl 内核调优) |
config/ |
共享配置片段(haproxy、gitea、proxy) |
shell/ |
辅助 Shell 脚本 |
i2c.py/ |
树莓派 I2C OLED 显示屏脚本 |
部署服务
每个 compose 文件顶部有标准部署命令注释:
# 拉取镜像
docker compose -p <项目名> --env-file ./<service>/env.cfg -f ./<service>/stack.yml pull
# 部署
docker compose -p <项目名> --env-file ./<service>/env.cfg -f ./<service>/stack.yml up -d
-p <项目名>设置 Docker Compose 项目名(通常与服务目录名一致)--env-file加载变量,如IMAGE_TAG、Volumes_Path、端口、密码等-f指向具体的 compose YAML 文件
部分服务有多环境 compose 文件(如 gitea/lky-prod.yml vs gitea/rpi-prod.yml、memos/local.stack.yml vs memos/prod.stack.yml、dbSer/dbs-dev.stack.yaml vs dbSer/dbs.stack.yaml)。
部分服务需要多个 env 文件以支持多环境(如 memos 使用 --env-file env.cfg --env-file db-184.cnf)。
命名规范
| 项目 | 规范 | 说明 |
|---|---|---|
| 环境变量文件 | env.cfg |
统一使用 .cfg 扩展名 |
| Compose 文件(主文件) | stack.yml |
Docker Swarm 风格,适用于独立服务 |
| Compose 文件(开发/构建) | compose.yml |
Docker Compose V2 风格,用于 builder 等开发容器 |
| Compose 文件(环境区分) | <env>.stack.yml |
如 prod.stack.yml、local.stack.yml、dbs-dev.stack.yaml |
| Compose 文件(主机+环境) | <host>-<env>.yml |
如 lky-prod.yml、rpi-prod.yml |
| Compose 文件(Harbor) | compose.yaml |
Harbor 安装器生成的文件,不要手动修改 |
| 卷路径变量名 | Volumes_Path |
统一使用驼峰命名,不要使用 Volumes_PATH |
关键约定
env.cfg 格式
IMAGE_TAG_VER= 版本号字符串(如3.3.0)IMAGE_TAG= 完整镜像引用,常用变量插值(如haproxy:${IMAGE_TAG_VER})Volumes_Path= 宿主机持久化数据路径- 敏感值(密码、密钥)放在
env.cfg中
Compose 文件顶部注释
几乎所有 compose 文件顶部都有内联命令提示:
# path:: mkdir -pv /data/volumes/... ← 部署前需创建的目录
# pull:: docker compose ... pull ← 拉取镜像命令
# run:: / RUN:: docker compose ... up -d ← 部署命令
# disc:: ... ← 说明/警告
镜像仓库
使用了多个私有仓库:
hub.tp229.com:3500— 主私有仓库hub.wesais.cn— 备用私有仓库hub.node:3500— 节点本地仓库hub.6t7.net— 另一个私有仓库- 也直接使用公共镜像(如
caddy:2.10.0、gitea/gitea:1.25.2-rootless)
宿主机卷路径
- 生产数据:
/data/volumes/<service>/ - 配置数据:
/data/configs/<service>/(Caddy、HAProxy 等配置) - 备份数据:
/data/backups/<service>/ - Harbor 特殊:
/data/harbor/(使用 Harbor 安装器目录结构)
时区
所有服务设置 TZ=Asia/Shanghai,并只读挂载 /etc/timezone 和 /etc/localtime。
网络模式
dbSer/服务使用固定 IP,网络为DevNet(172.22.10.0/24)或dbs-net(172.25.0.0/24)- 需要主机网络访问的服务(如 netdata)使用
network_mode: host - 独立服务使用默认 bridge 或自定义命名网络
构建系统(builder/)
builder/ 目录包含开发容器的 compose 文件。每个 env.cfg 有 IMAGE_TAG_BASH 和 IMAGE_TAG_ASH 变体。使用示例:
docker compose -p <名称> --env-file ./builder/golang/env.cfg -f ./builder/golang/compose.yml up -d
自定义镜像(如 Ansible)有 Dockerfile,构建命令写在注释中:
# BUILD:: docker buildx build --platform linux/amd64 -t hub.tp229.com:3500/ansible-alpine:py3.13-rootless .
定时任务(crontab/)
| 文件 | 建议周期 | 用途 |
|---|---|---|
smartctl.job |
手动/外部 cron | megaraid 控制器原始 smartctl 输出 |
disk_inspection.py |
每天 02:00 | 解析 SMART 报告 → Markdown + MCP 提交 |
autoApt.job |
每周一 01:05 | apt update && upgrade && autoremove |
timeUpdate.job |
每天 01:00 | NTP 时间同步(ntpdate 或 timedatectl) |
所有 .job 文件需要 chmod +x(由 shell/up.bash 处理)。
重要注意事项
- Harbor 是特殊情况:通过官方 Harbor 安装器部署,不是简单的 compose 文件。
harbor/compose.yaml是./prepare生成的输出文件,非手写,不要修改。 - Gitea 备份:
gitea/backup.job在 rsync 前停止容器、完成后重启——不适用于零停机场景。 - 端口冲突:多个服务默认使用相同端口(如 Grafana 和 Gitea 都默认 3000,多个服务默认 8080)。通过 env 文件或不同 compose 文件区分环境。
- 私有仓库镜像:很多
IMAGE_TAG引用私有仓库(hub.tp229.com:3500、hub.wesais.cn),无访问权限时无法拉取。 - 国内镜像源:Dockerfile 和 apt 配置默认使用国内 CDN 镜像(中科大、阿里云、华为),部署在其他地区需修改。
- Portainer Docker 兼容性:Portainer CE LTS < 2.36.0 不兼容 Docker >= 29.0.0,需设置
DOCKER_MIN_API_VERSION=1.24。详见portainer-ce/readme.md。 - i2c.py 需要硬件:OLED 显示脚本需要树莓派 I2C 硬件、
adafruit_ssd1306库和中文字体(fonts-wqy-microhei)。
系统配置(etc/)
etc/sysctl.conf 包含内核调优参数:
- 桥接 netfilter(容器需要)
- TCP 性能调优(keepalive、TIME_WAIT、窗口缩放、Fast Open)
- 连接队列大小(somaxconn、syn backlog)
- 内存管理(swappiness、脏页阈值)
- 安全加固(ICMP 重定向拒绝、反向路径过滤、kptr_restrict)
Git 提交规范
Commit Message 格式
本仓库 commit message 优先使用 Conventional Commits 规范,与历史风格保持一致。格式:
<type>(<scope>): <subject> # 中文
<type>(<scope>): <subject> # 英文
Type 类型
| Type | 用途 | 示例 |
|---|---|---|
feat |
新增服务/新功能 | feat: add adminer docker deployment files |
fix |
修复 bug | fix(gitea): 修复备份脚本权限问题 |
docs |
文档变更(readme、AGENTS.md 等) | docs: 添加git提交信息规则文件 |
refactor |
重构(不改功能) | refactor(status.py): 重构OLED状态显示代码 |
perf |
性能优化 | perf(redis): 调整内存淘汰策略 |
build |
构建相关(Dockerfile、compose、依赖) | build(moltbot): 添加生产环境docker compose |
chore |
杂项(版本号、配置、镜像标签) | chore: 更新 Joplin 服务器镜像版本至 3.6.1 |
style |
格式调整(不影响代码逻辑) | style: 统一 yaml 缩进为 2 空格 |
test |
测试相关 | test: 添加 memos 部署验证脚本 |
Scope 范围(可选)
- 服务名(目录名小写):
gitea、memos、haproxy、postgres、portainer-ce等 - 顶层目录:
builder、crontab、etc、shell、i2c.py - 省略:当改动跨多个服务或为全局性变更
Subject 主题规则
- 中文项目用中文描述,英文项目用英文,统一保持
- 首字母小写(中文不受影响)
- 不超过 50 个字符,尽量精炼
- 不要句末加句号
- 动词开头:添加/更新/修复/重构/删除 或 add/update/fix/refactor/remove
- 写明对象:要让人一眼看出改了什么
Body 与 Footer(可选)
需要时换行后空一行写正文:
feat(gitea): 添加 lfs 存储后端配置
- 使用 minio 作为 lfs 对象存储
- 调整 gitea app.ini 路径映射
- 备份脚本需同步调整
Refs: #123
提交前自检
# 1. 查看变更文件
git status
# 2. 检查 diff 大小(避免误提交敏感文件)
git diff --stat
# 3. 确认无 env.cfg / 凭据被误提交
git diff | grep -iE "password|secret|token|key" # 应无敏感输出
# 4. 暂存并提交
git add <files>
git commit -m "<type>(<scope>): <subject>"
# 5. 推送
git push origin main
提交粒度
- 一个 commit 只做一件事:不要把无关改动混在一起
- 服务级别独立提交:新增一个服务(如
gitea/)应该是独立 commit - 版本号更新单独 commit:
chore(<service>): bump image tag to x.y.z - 不要 commit 内容:
env.cfg(含敏感信息,已 gitignore)- 编译产物(
*.bin、main、__pycache__/等) - IDE 配置(
.vscode/、.idea/) - 系统级配置(
/data/volumes/下的实际数据)
历史风格兼容性
仓库早期 commit 有少量非 Conventional 风格(如 Add lsd config and color theme),
新增 commit 一律遵循本规范,历史风格不强制改写。
AI 生成 commit message 的硬约束
当 AI 助手(或 IDE agent)被要求生成 commit message 时,只输出 commit text 本身,严禁夹带任何元评论、解释或代码块包裹。
输出黑名单(出现即视为违规):
- 前置说明:
我看了你的改动…、建议使用下面的 commit message:、以下为 commit: - 元评论词汇:
分析、考虑、由于、因为、建议、注意、这里、本次、因为需要 - 复述 diff:把
git diff的关键行直接放进 commit - 解释"为什么改":commit 只描述"改了什么",不写动机
- 多版本候选/对比:不要
Option 1 / Option 2或---begin--- / ---end--- - markdown 代码块包裹:直接给纯文本,除非用户明确要求
输出前自检清单:
- 只包含 commit text,无任何前后缀
- subject ≤ 50 字符、无句末标点、动词开头、首字母小写
- type 在
{feat, fix, docs, refactor, perf, build, chore, style, test}内 - scope 准确(服务名小写或顶层目录名)
- body 每行 ≤ 72 字符、不重复 subject
- 中英文不混用、保持与项目历史一致
- 未泄露
password|secret|token|key等敏感词
正确示例:
feat(gitea): bump image to 1.25.2
错误示例(AI 常见错误):
我看了你的改动,主要是更新了镜像版本,建议使用:
feat(gitea): bump image to 1.25.2
这次改动把版本从 1.24 升到 1.25.2,主要修复了…
注意:thinking 块属于模型内部推理,无法在 commit 场景关闭,但它对最终 commit 输出无污染。用户的关注点应放在"最终输出是否干净"。
AGENTS.md 维护规则
AGENTS.md 是给 AI 助手(Claude Code、Codex、Hermes 等)和协作者阅读的项目宪法。 它不是写完就不动的文档,而是要跟着仓库演进持续更新。
何时更新 AGENTS.md
出现以下情况之一,必须同步更新本文件(在同一个 PR/commit 或紧随其后):
- 新增/删除服务:增减顶层服务目录(如新增
gitea/、下线flame/) - 架构变更:目录结构、命名约定、文件组织方式发生调整
- 新增通用约定:跨多个服务复用的规则(如新的环境变量命名、新的备份策略)
- 重大操作变更:升级 Docker 版本、Compose 规范变更、镜像源切换
- AI 助手踩坑:发现 AI 反复犯同样的错误(如改 Harbor compose.yaml、提交 env.cfg)
- 私有仓库/凭据变动:新增私有镜像仓库、凭据管理方式变化
何时不更新 AGENTS.md
- 单个服务的局部配置变更(写到该服务的
readme.md) - 镜像版本小版本号 bump(写到该服务
chorecommit) - 一次性的 bug 修复
- 与项目规范无关的个人偏好
内容质量要求
写给 AI 看的规则必须明确、可执行、有上下文:
- ✅ 好的写法:
harbor/compose.yaml是./prepare生成的输出文件,不要手动修改。 - ❌ 差的写法:
注意 Harbor 的 compose 文件。
好的写法具备三要素:
- 是什么(明确对象/文件/命令)
- 为什么(背景/原因,让 AI 理解)
- 怎么办(具体操作/替代方案)
章节组织
新增章节时遵循现有结构:
# 标题 + 简介
## 架构与组织
## 服务规范
## 部署与运维
## 重要注意事项
## 系统配置(etc/)
## Git 提交规范
## AGENTS.md 维护规则 ← 新章节放在最后
- 章节顺序按 "项目结构 → 规范 → 注意事项 → 工具/脚本 → 治理" 排列
- 新章节优先放在文档末尾,避免大改章节编号
- 章节标题用
##一级章节,保持中文(与全文风格一致)
更新流程建议
# 1. 修改 AGENTS.md
$EDITOR AGENTS.md
# 2. 单独提交(不要和服务代码改动混在一起)
git add AGENTS.md
git commit -m "docs: <本次更新的内容>"
# 3. 推送到远程
git push origin main
典型 commit 消息:
docs: 补充 git 提交规范章节docs: 新增 postgres 服务的部署注意事项docs: 更新 AGENTS.md 维护规则docs: 修正 harbor compose.yaml 描述
验证清单
每次更新后过一遍:
- 章节顺序合理,编号未乱
- 链接、命令路径、文件名拼写正确
- 中英文混用风格与现有章节一致
- 没有把敏感信息(密码、token)写进文档
- 涉及 AI 助手的提醒具体到文件/命令,不空泛
- 改动反映在
git status中只包含AGENTS.md
同步与传播
- 复制到其他 stack 仓库时只复制骨架(章节标题),不要直接复制内容
- 不同 stack 的"重要注意事项"差异很大,混用会导致 AI 误判
- 如果有 fork/PR 流程,AGENTS.md 变更要在 PR 描述里说明理由