补充说明
本教程介绍 fan-image-tr 从源码编译、交叉编译、发布 GitHub Release 到目标服务器安装、卸载、升级的完整流程,适用于个人设备自建发布链路。
项目:fan-image-tr|基于 FFmpeg 的图片批量处理 Web 工具 仓库:https://github.com/meimolihan/fan-image-tr 编译发布主机:fnOS(Debian,本机 Go / make / ffmpeg 环境齐全) 部署测试主机:Debian Linux(amd64 / arm64)
项目目录结构
fan-image-tr/
├── main.go # 入口:命令分发
├── server.go # 启动 Web 服务、优雅关闭
├── check_cmd.go # check 子命令:FFmpeg 能力自检
├── status_cmd.go # status 子命令:运行状态与目录占用
├── scripts/fan-image-tr.service# systemd 服务单元模板
├── Dockerfile # 多阶段构建(golang → debian-slim + ffmpeg)
├── docker-compose.yml # 本地构建 + 运行的 compose
├── Makefile # build / test / build-all / docker 等目标
├── internal/
│ ├── config/ # viper 配置(默认值 → config.yaml → FIT_ 环境变量)
│ ├── embedded/web/ # 前端源码,直接 go:embed 进二进制(无需 Node)
│ ├── ffmpeg/ # 格式字典、硬件加速探测、转码与缩略图
│ ├── handler/ # HTTP 路由与处理器
│ ├── service/ # 媒体浏览、任务队列、预设
│ ├── logger/ # zap 日志
│ └── version/ # Version / Commit / BuildTime 注入
└── .github/workflows/ci.yml # 测试 + 镜像构建 + 打 tag 自动发布
重要规则
- GitHub 不允许直接覆盖已发布 Release,正式环境版本号单向递增;内测可删除重建同名 tag。
- 仓库已内置
.github/workflows/ci.yml,推送v*tag 即自动交叉编译并创建 Release,无需手工gh release create。- 编译机器 ≠ 业务运行机器;fnOS 只做编译发布,业务跑在目标主机。
- 二进制默认
CGO_ENABLED=0(纯 Go,静态可移植);FFmpeg 是外部进程依赖,靠ffmpeg/ffprobe命令或FIT_FFMPEG_PATH定位,不做内嵌。
一、编译发布机(fnOS)环境准备
1.1 安装依赖
apt update
apt install git curl make ffmpeg build-essential
Go 1.25+(本机 /usr/local/go/bin/go,Makefile 已把它加进 PATH,确保 go version 正常)。不需要 Node——前端源码在 internal/embedded/web/,通过 go:embed 直接打进二进制。
1.2 拉取源码
git clone git@github.com:meimolihan/fan-image-tr.git
cd fan-image-tr
go mod download
1.3 安装 gh 命令行工具并授权 GitHub(仅手工发版时需要)
gh auth login
选择 GitHub.com → SSH → 网页授权登录,务必勾选 repo 权限。
校验授权结果
gh auth status
输出必须包含:Token scopes: admin:public_key, gist, read:org, repo
二、Makefile 目标速览
make help # 所有目标
make build # 编译到 bin/fan-image-tr(版本号取 git describe)
make build-all # 交叉编译 linux/darwin/windows amd64+arm64 到 dist/
make test # go vet + 单元测试(会跑真实转码用例,需要 ffmpeg)
make race # 竞态检测
make cover # 覆盖率报告 coverage.html
make fmt # gofmt 格式化
make tidy # go mod tidy
make check # 编译并执行 fan-image-tr check(FFmpeg 能力自检)
make run # 本地启动(make run PORT=8792 MEDIA=/path/to/photos)
make docker # 构建 Docker 镜像
make clean # 清理构建产物
三、构建与发布
3.1 本地构建
make build # → bin/fan-image-tr,版本号 = git describe --tags --always --dirty
./bin/fan-image-tr version
./bin/fan-image-tr check # 输出格式支持情况与 QSV / NVENC / VAAPI 实测结果
3.2 方式一:推送 tag 触发自动发布(推荐)
CI 会在 refs/tags/v* 上依次完成:单元测试与竞态检测 → 镜像构建与冒烟测试 → 交叉编译 → 创建 Release。
cd /vol1/1000/compose/opencode/workspace/fan-image-tr
git add -A
git commit -m "feat: ..."
git push origin main
git tag v1.0.1
git push origin v1.0.1
查看进度与产物
gh run list --workflow=ci.yml --limit 1
gh release view v1.0.1
产物命名(softprops/action-gh-release 上传):
fan-image-tr-linux-amd64
fan-image-tr-linux-arm64
fan-image-tr-darwin-amd64
fan-image-tr-darwin-arm64
fan-image-tr-windows-amd64.exe
fan-image-tr-src.tar.gz
3.3 方式二:手工交叉编译 + 手工发版
cd /vol1/1000/compose/opencode/workspace/fan-image-tr
export VERSION=1.0.1
rm -rf dist && mkdir -p dist
make build-all
ls -lh dist
gh release create "v${VERSION}" \
dist/fan-image-tr-linux-amd64 \
dist/fan-image-tr-linux-arm64 \
dist/fan-image-tr-darwin-amd64 \
dist/fan-image-tr-darwin-arm64 \
dist/fan-image-tr-windows-amd64.exe \
--title "v${VERSION}" \
--notes "fan-image-tr - Image Batch Processing Tool"
想注入 commit 与构建时间(
fan-image-tr version会一起打印),把LDFLAGS换成下面这组变量再手工构建:
cd /vol1/1000/compose/opencode/workspace/fan-image-tr
export VERSION=1.0.1
export LDFLAGS="-s -w \
-X github.com/meimolihan/fan-image-tr/internal/version.Version=${VERSION} \
-X github.com/meimolihan/fan-image-tr/internal/version.Commit=$(git rev-parse --short HEAD) \
-X github.com/meimolihan/fan-image-tr/internal/version.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
CGO_ENABLED=0 go build -trimpath -ldflags "$LDFLAGS" -o dist/fan-image-tr-linux-amd64 .
3.4 校验 Release
访问:https://github.com/meimolihan/fan-image-tr/releases/tag/v1.0.1
- 状态:Published,不是 Draft 草稿
- Assets 内必须存在编译二进制,不要只看源码 zip/tar.gz。
测试下载链接有效性
curl -I https://github.com/meimolihan/fan-image-tr/releases/latest/download/fan-image-tr-linux-amd64
返回 302 Found 正常;返回 404 代表附件缺失。
3.5 构建 Docker 镜像
# 单架构(默认本机架构)
make docker
# → fan-image-tr:<git describe>
# 双架构推送(需要 buildx)
docker buildx create --name mybuilder --use
docker buildx inspect mybuilder --bootstrap
docker buildx build \
--platform linux/amd64,linux/arm64 \
--build-arg VERSION=1.0.1 \
-t mobufan/fan-image-tr:latest \
-t mobufan/fan-image-tr:1.0.1 \
--push .
发布公共镜像后,可把
dc_inst_fan-image-tr.sh顶部DEFAULT_IMAGE填成mobufan/fan-image-tr:latest, 部署脚本就会跳过源码构建直接拉取运行。
四、目标服务器远程一键安装
目标服务器需要 root 权限,已安装 curl。
4.1 预检查国内网络
curl -sSL https://raw.githubusercontent.com/meimolihan/fan-image-tr/main/README.md | head -5
输出内容 = 网络正常;卡住超时需要网络代理。
4.2 方式一:Release 二进制 + systemd
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
curl -fsSL -o /usr/local/bin/fan-image-tr "https://github.com/meimolihan/fan-image-tr/releases/latest/download/fan-image-tr-linux-${ARCH}"
chmod +x /usr/local/bin/fan-image-tr
fan-image-tr version
fan-image-tr check
useradd -r -s /sbin/nologin -d /var/lib/fan-image-tr fit
mkdir -p /var/lib/fan-image-tr /srv/photos
curl -fsSL https://raw.githubusercontent.com/meimolihan/fan-image-tr/main/scripts/fan-image-tr.service -o /etc/systemd/system/fan-image-tr.service
systemctl daemon-reload
systemctl enable --now fan-image-tr
systemctl status fan-image-tr
想省事可以直接用菜单脚本:选
66一键安装 / 升级。
bash <(curl -sL gitee.com/meimolihan/cmdbox/raw/master/sh/fan-image-tr_menu.sh)
4.3 方式二:Docker Compose
bash <(curl -sL gitee.com/meimolihan/cmdbox/raw/master/sh/dc_inst_fan-image-tr.sh) 8791 /vol1/1000/compose/fan-image-tr
或手工:
git clone --depth 1 https://github.com/meimolihan/fan-image-tr.git
cd fan-image-tr
# 修改 docker-compose.yml 里的 ./photos 为你的图片库目录
docker compose up -d --build
docker exec fan-image-tr fan-image-tr check
4.4 部署后运维命令
systemctl status fan-image-tr
journalctl -u fan-image-tr -f
systemctl restart fan-image-tr
fan-image-tr status
fan-image-tr check
访问示例:http://10.10.10.251:8791
- 无账号体系,浏览器打开即用
- 对外暴露请自行加反向代理与鉴权
五、一键卸载
systemd 方式
systemctl disable --now fan-image-tr
rm -f /etc/systemd/system/fan-image-tr.service /usr/local/bin/fan-image-tr
systemctl daemon-reload && systemctl reset-failed fan-image-tr
# 交互确认是否删除数据目录
rm -rf /var/lib/fan-image-tr
Docker 方式
cd /vol1/1000/compose/fan-image-tr && docker-compose down --rmi all && rm -rf /vol1/1000/compose/fan-image-tr
菜单方式
菜单内选 99 卸载。
六、新版本发布两种模式
模式 1:递增新版本(正式环境,推荐)
不要复用旧 tag,版本号向上迭代,例如 v1.0.1 → v1.0.2;
make build的版本号取自git describe,打 tag 后二进制里的版本会变成1.0.2。
cd /vol1/1000/compose/opencode/workspace/fan-image-tr
make test
git add -A && git commit -m "release v1.0.2"
git push origin main
git tag v1.0.2 && git push origin v1.0.2
# 等待 CI 自动发版,或本地 make build-all + gh release create
目标服务器升级:重新下载 latest 二进制覆盖并重启,或直接重跑菜单选项
66。
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
systemctl stop fan-image-tr
curl -fsSL -o /usr/local/bin/fan-image-tr "https://github.com/meimolihan/fan-image-tr/releases/latest/download/fan-image-tr-linux-${ARCH}"
chmod +x /usr/local/bin/fan-image-tr
systemctl start fan-image-tr
fan-image-tr version
Docker 方式则重跑 dc_inst_fan-image-tr.sh,脚本会 git pull --ff-only 更新源码并 --build 重建镜像。
模式 2:删除重建同名 Release(仅限内测,无线上用户)
⚠️ 已有服务器依赖该版本绝对禁止执行,会造成旧版本下载 404。
cd /vol1/1000/compose/opencode/workspace/fan-image-tr
# 删除github release
gh release delete v1.0.2 --yes
# 删除本地与远端git tag
git tag -d v1.0.2
git push origin --delete v1.0.2
# 重新编译并重建release上传附件
export VERSION=1.0.2
make build-all
gh release create "v${VERSION}" \
dist/fan-image-tr-linux-amd64 \
dist/fan-image-tr-linux-arm64 \
dist/fan-image-tr-darwin-amd64 \
dist/fan-image-tr-darwin-arm64 \
dist/fan-image-tr-windows-amd64.exe \
--title "v${VERSION}" \
--notes "fan-image-tr - Image Batch Processing Tool"
七、故障排查表
| 现象 | 排查方案 |
|---|---|
FFmpeg 环境检查失败 |
运行 fan-image-tr check 确认 ffmpeg 与 ffprobe 都在 PATH,或用 FIT_FFMPEG_PATH / FIT_FFMPEG_FFPROBE_PATH 指定绝对路径 |
某格式在 check 里显示不可用 |
通常是当前 FFmpeg 编译时缺少对应编码器(AVIF 需 libsvtav1/libaom、JPEG 2000 需 libjxl/openjpeg、HEIC 需 libheif) |
硬件加速显示 △(编码器存在但无实测可用格式) |
该加速缺少目标格式的像素格式转换器,换格式或改用 FIT_FFMPEG_ACCEL=none |
容器内看不到 /dev/dri |
compose 未挂载设备;Intel/AMD 需 - /dev/dri:/dev/dri,NVIDIA 需 nvidia-container-toolkit + --gpus all |
| 服务启动即退出 | journalctl -u fan-image-tr -n 100 看日志;常见原因是数据目录 / 图片目录不存在或属主不是 fit |
| 访问 API 返回 403 | 请求路径不在浏览根、数据、上传、输出目录内,属正常的路径越界保护 |
| 上传大文件失败 | 单文件上限默认 64MB,调 app.max_upload_mb 或 FIT_APP_MAX_UPLOAD_MB |
go build 报 Go 版本过低 |
需要 Go 1.25+(go.mod 已声明 go 1.25.0) |
go test ./... 失败 |
测试会跑真实转码用例,必须先装 ffmpeg |
gh release create 返回 401 Unauthorized |
执行 gh auth login 重新授权,确保 token 具备 repo 权限 |
| raw.githubusercontent.com 卡住超时 | 国内网络限制,配置代理,或将脚本镜像到 Gitee 中转 |
八、前端 UI 修改流程
前端为纯静态资源(internal/embedded/web/),构建产物通过 go:embed 内嵌进二进制:
- 修改
internal/embedded/web/下的前端代码 - 重新构建:
make build - 本地调试:
-web ./internal/embedded/web指向源码目录,改完刷新即可,无需重新编译 - 重新走发布流程:提交代码 → 构建 → 打 tag → 创建 Release
- 目标服务器重跑安装 / 升级生效
九、极简速查复制块
本地开发
cd /vol1/1000/compose/opencode/workspace/fan-image-tr
go mod download
make fmt && make test && make build
./bin/fan-image-tr check
./bin/fan-image-tr -data ./data -media /path/to/photos -port 8791
发布新版本(CI 自动)
cd /vol1/1000/compose/opencode/workspace/fan-image-tr
make test
git add -A && git commit -m "release v1.0.2"
git push origin main
git tag v1.0.2 && git push origin v1.0.2
gh run list --workflow=ci.yml --limit 1
gh release view v1.0.2
目标服务器升级
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
systemctl stop fan-image-tr
curl -fsSL -o /usr/local/bin/fan-image-tr "https://github.com/meimolihan/fan-image-tr/releases/latest/download/fan-image-tr-linux-${ARCH}"
chmod +x /usr/local/bin/fan-image-tr
systemctl start fan-image-tr && fan-image-tr version