部署准备:交叉编译、嵌入静态资源(embed)思路
部署前把「环境差异」提前解决:交叉编译出目标平台的二进制、把模板与静态资源 embed 进单个可执行文件,服务器上就只剩一个文件加配置。embed 用法以 pkg.go.dev 的 embed 包文档为准。
1. 交叉编译
Go 交叉编译很简单——只要不开 CGO:设置 GOOS/GOARCH/CGO_ENABLED 三个环境变量即可:
# 在 Windows/Mac 上编译出 Linux amd64 的二进制
$env:GOOS = "linux"; $env:GOARCH = "amd64"; $env:CGO_ENABLED = "0"
go build -trimpath -ldflags="-s -w" -o bin/app ./cmd/server
CGO_ENABLED=0:纯静态编译,不依赖目标机 glibc,才能跨平台;-ldflags="-s -w":去掉调试符号,减小体积;- 依赖 cgo 的库(部分 SQLite 驱动)无法这样静态跨编,要么换纯 Go 驱动,要么在目标平台构建。
2. embed 嵌入静态资源
embed 指令把文件编译进二进制,路径以 //go:embed 所在源文件为基准:
package web
import "embed"
//go:embed all:static
var StaticFS embed.FS // 整个 static/ 目录编译进二进制
//go:embed all:templates
var TemplateFS embed.FS
all: 前缀会把以 .、_ 开头的文件也包含进来;不加 all: 会跳过它们。
3. 交给 Gin 使用
import (
"html/template"
"io/fs"
"net/http"
"github.com/gin-gonic/gin"
"myapp/web" // 上一步定义的包
)
// 模板:embed.FS 实现了 fs.FS,可直接 ParseFS
tmpl := template.Must(template.ParseFS(web.TemplateFS, "templates/*.html"))
engine.SetHTMLTemplate(tmpl)
// 静态文件:fs.Sub 去掉前缀目录,http.FS 包装成 http.FileSystem
sub, _ := fs.Sub(web.StaticFS, "static")
engine.StaticFS("/assets", http.FS(sub))
4. embed 的取舍
- 优点:单文件交付、版本随二进制走、不怕漏文件;
- 代价:改模板/前端要重新编译,模板不便热更新。
- 折中:开发模式读磁盘、生产模式读 embed,用
fs.FS接口统一:
var templateFS fs.FS = os.DirFS("./templates") // 开发
// 生产:templateFS = web.TemplateFS(embed)
注意点
//go:embed必须紧跟var声明,且被嵌文件必须真实存在,否则编译报错。- embed 的路径在 Windows 上同样用
/分隔。 - 产物到目标机后可用
file bin/app验证确实是静态链接。 - 用
-ldflags "-X main.version=..."注入版本与构建时间,便于线上定位。
小结
交叉编译解决「在哪编、在哪跑」,embed 解决「文件会不会丢」。二者组合让部署退化成「拷一个文件 + 配一份环境」,为 nginx/systemd 与 Docker 部署铺路。