# gf-scaffold **Repository Path**: lin_30_0/gf-scaffold ## Basic Information - **Project Name**: gf-scaffold - **Description**: GoFrame 单体 HTTP 脚手架:PostgreSQL + Redis、商品 CRUD 示例、Docker Compose 一键部署与 Nginx 反代 | GoFrame monolith scaffold with Postgres/Redis, sample product CRUD, Docker Compose deploy & Nginx proxy - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-09-01 - **Last Updated**: 2026-09-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: Go语言, Docker, Postgresql, Redis, GoFrame ## README # GoFrame 单体脚手架(PostgreSQL + Redis) 基于 [GoFrame](https://github.com/gogf/gf) 的单体 HTTP 脚手架,内置 **商品 CRUD** 示例。目标:克隆 → 改名 → 开发 → 一条命令打包 → Linux + Nginx 上线,少在「搭架子」上浪费时间。 | 项 | 说明 | | --- | --- | | 框架 | GoFrame `v2.9.x` | | 数据 | PostgreSQL 16(必选)· Redis 7(可选,挂了也能跑) | | 本地 | `backend/docker-compose.yml` 只起依赖;`go run` 跑应用 | | 生产 | `deploy/work/` 整包拷到 `/usr/local/docker/work/`,`docker load` + `compose up` + Nginx | --- ## 架构(推荐) ```text 浏览器 / 客户端 │ ▼ Nginx :80/:443 ├─ /api/v1/* ──► 127.0.0.1:6886 (gf_app 容器,仅本机端口) └─ /files/* ──► 127.0.0.1:6886 (静态/上传预留) │ ▼ gf_app (:8000 容器内) │ docker 网络 gf_net(服务名互访) ┌────────┴────────┐ ▼ ▼ gf_postgres gf_redis (卷 gf_pg_data) (卷 gf_redis_data) 宿主机仅 127.0.0.1:5433 / 6380 供运维 ``` 要点: 1. **应用端口不对公网**:只绑 `127.0.0.1:6886`,由 Nginx 统一入口。 2. **库与缓存走容器网络**:应用配置用主机名 `postgres` / `redis`,不走宿主机映射。 3. **配置外挂**:改库密、日志级别只改 `deploy/work/config/`,不必重新打镜像。 4. **CORS 只开一处**:要么 Nginx,要么 Go;两边都开会导致重复头、浏览器报错。 --- ## 1. 本地开发 ### 1.1 准备 ```bash # 安装 Go 1.22+、Docker Desktop、gf CLI go install github.com/gogf/gf/cmd/gf/v2@latest gf version ``` ### 1.2 启动依赖与应用 ```bash cd backend docker compose up -d # Postgres :5433 · Redis :6380 cp manifest/config/config.example.yaml manifest/config/config.yaml go mod tidy go run . # HTTP :8000 ``` | 地址 | 用途 | | --- | --- | | http://localhost:8000/swagger | Swagger | | http://localhost:8000/api.json | OpenAPI | | http://localhost:8000/api/v1/health | 探活(DB/Redis) | 旧卷未跑过初始化 SQL 时: ```powershell Get-Content manifest/sql/001_init.sql | docker exec -i gf_postgres psql -U postgres -d app_db Get-Content manifest/sql/002_seed.sql | docker exec -i gf_postgres psql -U postgres -d app_db ``` ```bash # Linux / macOS docker exec -i gf_postgres psql -U postgres -d app_db < manifest/sql/001_init.sql ``` ### 1.3 Makefile ```bash make docker-up / docker-down / docker-logs make dao / ctrl / service / gen make run make image # docker build make package # build + docker save → deploy/dist/*.tar ``` --- ## 2. 商品 API(示例) | Method | Path | 说明 | | --- | --- | --- | | GET | `/api/v1/health` | DB / Redis 探活 | | POST | `/api/v1/products` | 创建 | | GET | `/api/v1/products` | 列表(`page`/`size`/`name`/`status`) | | GET | `/api/v1/products/{id}` | 详情 | | PUT | `/api/v1/products/{id}` | 更新(字段可选) | | DELETE | `/api/v1/products/{id}` | 删除 | | GET | `/files/...` | 静态文件预留(对应目录 `data/files`) | ```bash curl -X POST http://localhost:8000/api/v1/products \ -H "Content-Type: application/json" \ -d '{"name":"键盘","price":299,"stock":10}' curl "http://localhost:8000/api/v1/products?page=1&size=20" ``` --- ## 3. 新功能开发(`gf gen`) 官方:[gen](https://goframe.org/docs/cli/gen) · [dao](https://goframe.org/docs/cli/gen-dao) · [ctrl](https://goframe.org/docs/cli/gen-ctrl) · [service](https://goframe.org/docs/cli/gen-service) ```text 1. 写 SQL(manifest/sql/ 或迁移工具)并应用到库 2. gf gen dao # 表 → dao / do / entity 3. 写 api/xxx/v1/*.go 4. gf gen ctrl # → controller 骨架 5. 写 internal/logic(sXxx + Register) 6. gf gen service # → service 接口 7. internal/cmd/cmd.go 里 Bind 控制器 ``` | 命令 | 输入 | 输出 | | --- | --- | --- | | `gf gen dao` | 数据库表 | `internal/dao`、`model/do`、`model/entity` | | `gf gen ctrl` | `api/` | `internal/controller`(及 `api` 接口) | | `gf gen service` | `internal/logic` | `internal/service` | 库连接在 `backend/hack/config.yaml` → `gfcli.gen.dao`。 --- ## 4. Linux 生产部署(`/usr/local/docker/work/`) 设计目标:服务器上**不装 Go**,只装 Docker + Nginx;发布靠镜像 tar。 ### 4.1 目录约定 把仓库里的 `deploy/work/` **整目录**放到服务器: ```text /usr/local/docker/work/ ├── docker-compose.yml # app + postgres + redis ├── .env # 从 .env.example 复制 ├── config/config.yaml # 应用配置(外挂) ├── sql/ # 仅「空卷首次」自动建表 ├── nginx/gf-scaffold.conf # 给 Nginx include ├── scripts/ # backup / restore / psql ├── data/ │ ├── files/ # /files 静态与上传 │ ├── logs/ │ └── backups/ # 备份输出 └── gf-scaffold-image.tar # 可选:load 用的镜像包 ``` ```bash # 服务器示例 sudo mkdir -p /usr/local/docker sudo cp -a deploy/work /usr/local/docker/work cd /usr/local/docker/work cp .env.example .env # 编辑 .env 与 config/config.yaml(密码必须一致) chmod +x scripts/*.sh ``` ### 4.2 本机打镜像并导出 ```bash cd backend make package # 产物默认:deploy/dist/gf-scaffold-image.tar ``` 或: ```bash docker build -t gf-scaffold:latest -f Dockerfile . docker save gf-scaffold:latest -o gf-scaffold-image.tar ``` ### 4.3 上传并加载 ```bash scp deploy/dist/gf-scaffold-image.tar user@server:/usr/local/docker/work/ scp -r deploy/work/* user@server:/usr/local/docker/work/ # 首次 ssh user@server cd /usr/local/docker/work docker load -i gf-scaffold-image.tar docker images | grep gf-scaffold # 改密码后务必同步: # .env 的 POSTGRES_PASSWORD # config/config.yaml 里 link 中的密码 docker compose up -d docker compose ps curl -s http://127.0.0.1:6886/api/v1/health ``` 后续发版(只更应用、不动库): ```bash docker load -i gf-scaffold-image.tar docker compose up -d app # 或:docker compose up -d --force-recreate app ``` ### 4.4 Nginx 1. 在 `http {}` 里确保有(全局一次即可): ```nginx map $http_upgrade $connection_upgrade { default upgrade; '' close; } ``` 2. 在站点 `server {}` 中: ```nginx include /usr/local/docker/work/nginx/gf-scaffold.conf; ``` 样例已按你的思路写好:`/api/v1`、`/files/` → `http://127.0.0.1:6886`,并带 CORS / WebSocket 头。 **若 Go 里仍使用 `CORSDefault()`,请删掉 Nginx 样例里的 CORS 段,避免重复。** ```bash nginx -t && systemctl reload nginx ``` ### 4.5 生产检查清单 - [ ] `.env` 强密码;`config.yaml` 中 DB 密码一致 - [ ] `config.yaml` 里 `debug: false` - [ ] 端口仅为 `127.0.0.1:6886/5433/6380` - [ ] `curl 127.0.0.1:6886/api/v1/health` → database ok - [ ] 域名 `/api/v1/health` 经 Nginx 可访问 - [ ] 已跑通一次 `scripts/backup.sh`,确认 `data/backups/` 有文件 --- ## 5. Docker 卷里的数据:查看 · 备份 · 迁移 Postgres / Redis 数据在 **Docker 命名卷**里(不是 compose 目录下的普通文件夹)。不要指望在 `/usr/local/docker/work` 里直接看到库文件;用下面方式操作。 ### 5.1 卷在哪 ```bash docker volume ls | grep gf_ docker volume inspect work_gf_pg_data # 项目名 work 时 # Mountpoint 一般在 /var/lib/docker/volumes//_data ``` 直接拷 `_data` 可以,但 **更推荐逻辑备份**(`pg_dump` / Redis RDB),跨机、跨版本更稳。 ### 5.2 查看 / 调试 ```bash # Postgres 交互 cd /usr/local/docker/work ./scripts/psql.sh # 或:docker exec -it gf_postgres psql -U postgres -d app_db \dt SELECT * FROM products LIMIT 10; # Redis ./scripts/redis-cli.sh PING KEYS * ``` 只读跑 SQL 文件: ```bash docker exec -i gf_postgres psql -U postgres -d app_db < ./sql/001_init.sql ``` ### 5.3 备份(推荐日常) ```bash cd /usr/local/docker/work ./scripts/backup.sh # → data/backups/pg_YYYYMMDD_HHMMSS.sql.gz # → data/backups/redis_YYYYMMDD_HHMMSS.rdb ``` 原理: | 组件 | 方式 | 说明 | | --- | --- | --- | | Postgres | `pg_dump` 管道 gzip | 逻辑备份,迁移首选 | | Redis | `BGSAVE` + `docker cp` dump.rdb | 可另存 AOF | 建议:备份目录挂盘或定时 `scp`/`rsync` 到另一台机器;可配 crontab: ```bash 0 3 * * * cd /usr/local/docker/work && ./scripts/backup.sh >> data/logs/backup.log 2>&1 ``` ### 5.4 恢复 ```bash # Postgres(会写入当前库,注意覆盖风险) ./scripts/restore-pg.sh data/backups/pg_20260801_030000.sql.gz # Redis(停服替换 dump,短暂不可用) ./scripts/restore-redis.sh data/backups/redis_20260801_030000.rdb ``` ### 5.5 迁到另一台服务器 **推荐路径(逻辑备份):** ```bash # 源机 ./scripts/backup.sh scp data/backups/pg_xxx.sql.gz data/backups/redis_xxx.rdb user@new:/usr/local/docker/work/data/backups/ # 新机:先 compose up 起空库,再 ./scripts/restore-pg.sh data/backups/pg_xxx.sql.gz ./scripts/restore-redis.sh data/backups/redis_xxx.rdb ``` **物理卷迁移(同 Docker 大版本时可用):** ```bash # 源机停写 docker compose stop # 打包卷内容 docker run --rm -v work_gf_pg_data:/data -v $(pwd)/data/backups:/backup alpine \ tar czf /backup/pg_volume.tgz -C /data . docker run --rm -v work_gf_redis_data:/data -v $(pwd)/data/backups:/backup alpine \ tar czf /backup/redis_volume.tgz -C /data . # 新机创建卷后解压进 Mountpoint(或对等 alpine 挂载写入),再 compose up ``` 业务数据以 **Postgres 逻辑备份**为准;Redis 多为缓存,迁丢了通常可重建(除非你把会话/队列也放 Redis)。 ### 5.6 注意 - `sql/` 挂载的 init **只在卷第一次创建时执行**;已有数据后改表请用迁移 SQL + 手动 `psql`,不要删卷图省事。 - `docker compose down -v` 会 **删卷**,生产禁止随手加 `-v`。 - 改 `POSTGRES_PASSWORD` 不会自动改已有卷里的密码;要改需进库 `ALTER USER` 或重建卷。 --- ## 6. Redis 预留(业务代码) ```go import "gf-scaffold/utility/redisx" if redisx.Available(ctx) { _, _ = redisx.Client().Do(ctx, "SET", "key", "value", "EX", 60) } ``` 本地可不启 Redis;health 会 `degraded`,主流程不拦。 --- ## 7. 开新项目改什么 1. 全局替换模块名 `gf-scaffold`(`go.mod` + import) 2. 改库名/容器名/镜像名(`docker-compose`、`.env`、`Makefile`) 3. 同步三处连接:`backend/manifest/config`、`hack/config.yaml`、`deploy/work/config` 4. 替换 `products` 示例表与 API 5. 按第 3 节 gen 流程加业务 --- ## 8. 目录结构 ```text full-stack/ ├── README.md ├── deploy/ │ ├── dist/ # make package 输出(gitignore) │ └── work/ # 原样部署到 /usr/local/docker/work/ │ ├── docker-compose.yml │ ├── .env.example │ ├── config/ │ ├── nginx/ │ ├── scripts/ # backup / restore / psql │ ├── sql/ │ └── data/ └── backend/ # GoFrame 工程 ├── api/ ├── internal/ ├── manifest/config|sql ├── utility/redisx ├── docker-compose.yml # 仅本地依赖 ├── Dockerfile # 多阶段构建 └── Makefile ``` --- ## License [MIT](./LICENSE) © WeFode