部署准备:交叉编译、嵌入静态资源(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 部署铺路。

笔记加载中…