部署

部署

go-web 编译后是单一二进制(包含模板和静态资源),既可以裸机部署,也可以容器化运行。本章列出最常见的几种部署方式。

二进制构建

# 默认构建(包含调试符号)
go build -o bin/go-web main.go

# 生产构建(去除符号表 + 调试信息,体积更小)
go build -ldflags="-s -w" -o bin/go-web main.go

# 交叉编译到 Linux amd64
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 \
    go build -ldflags="-s -w" -o bin/go-web main.go

得到 bin/go-web 后,把它和 config.yaml 一起发到目标机器即可。模板与静态资源已通过 //go:embed 编译进二进制。

启动 / 停止

通过 gomander 暴露的子命令:

./bin/go-web start          # 前台
./bin/go-web start -d       # 守护进程模式
./bin/go-web stop
./bin/go-web restart
./bin/go-web reload         # 等价于 SIGHUP,触发热重载
./bin/go-web status

守护进程模式会把进程 PID 写入文件,后续的 stop / reload / status 都依赖它。

Docker 部署

仓库根目录提供了多阶段构建的 Dockerfile:

# 构建镜像
docker build -t go-web-app .

# 运行
docker run -d \
    --name go-web \
    -p 8080:8080 \
    -e DATABASE_DRIVER=mysql \
    -e DATABASE_HOST=mysql.internal \
    -e DATABASE_PORT=3306 \
    -e DATABASE_USERNAME=app \
    -e DATABASE_PASSWORD=secret \
    -e DATABASE_DBNAME=myapp \
    -e REDIS_HOST=redis.internal \
    go-web-app

镜像特点:

  • 多阶段构建 —— builder 用 golang:1.25.0-alpine,运行阶段用 alpine:latest,最终镜像 ~15MB
  • 非 root 用户 —— 运行用户 appuser (uid=1001)
  • 时区 —— 默认 Asia/Shanghai
  • 健康检查 —— 内置 HEALTHCHECK 调用 /health/simple
  • CGO 关闭 —— 二进制纯静态链接

环境变量映射

go-web 中所有 config.yaml 的键都可以用环境变量覆盖,规则:把 . 替换成 _,字母变成大写。

config.yaml                 → 环境变量
─────────────────────────── → ──────────────────────────
app.app_name                → APP_APP_NAME
app.mode                    → APP_MODE
database.driver             → DATABASE_DRIVER
database.host               → DATABASE_HOST
database.port               → DATABASE_PORT
database.username           → DATABASE_USERNAME
database.password           → DATABASE_PASSWORD
database.dbname             → DATABASE_DBNAME
database.migration.dir      → DATABASE_MIGRATION_DIR
redis.host                  → REDIS_HOST
redis.port                  → REDIS_PORT
redis.password              → REDIS_PASSWORD
redis.db                    → REDIS_DB
cache.driver                → CACHE_DRIVER

完整列表见「配置系统」章节。

docker-compose 示例

version: "3.9"

services:
  app:
    image: go-web-app:latest
    ports:
      - "8080:8080"
    environment:
      DATABASE_DRIVER: mysql
      DATABASE_HOST: db
      DATABASE_PORT: 3306
      DATABASE_USERNAME: app
      DATABASE_PASSWORD: secret
      DATABASE_DBNAME: myapp
      REDIS_HOST: redis
      CACHE_DRIVER: redis
    depends_on:
      - db
      - redis

  db:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: rootpw
      MYSQL_DATABASE: myapp
      MYSQL_USER: app
      MYSQL_PASSWORD: secret
    volumes:
      - db_data:/var/lib/mysql

  redis:
    image: redis:7-alpine

volumes:
  db_data:

Kubernetes 示例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-web
spec:
  replicas: 2
  selector:
    matchLabels: { app: go-web }
  template:
    metadata:
      labels: { app: go-web }
    spec:
      containers:
        - name: go-web
          image: registry/go-web-app:1.0.0
          ports:
            - containerPort: 8080
          env:
            - name: DATABASE_DRIVER
              value: postgresql
            - name: DATABASE_HOST
              value: pg.internal
            - name: DATABASE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: go-web-db
                  key: password
          livenessProbe:
            httpGet: { path: /health/simple, port: 8080 }
            periodSeconds: 10
          readinessProbe:
            httpGet: { path: /health, port: 8080 }
            periodSeconds: 10
            failureThreshold: 3

数据库迁移与部署

推荐两种模式:

  1. 启动时自动迁移 —— 在 AppProvider.Servers() 中启用 migration.Migration{},部署时无需额外步骤
  2. CI 中独立执行 —— 部署前在 CI pipeline 里跑 go run cmd/migrate/main.go up,然后再上线新版本;适合需要在迁移和上线之间做人工 verify 的场景

详见「数据库迁移」章节。

优雅关闭

go-web 在收到 SIGINT / SIGTERM 时会:

  1. 停止接收新的 HTTP 请求(HttpServer.Stop())
  2. 等待正在处理的请求结束
  3. 销毁所有实现 Destroyable 的容器实例
  4. 进程退出

Kubernetes 默认在 terminationGracePeriodSeconds(默认 30s)内允许进程优雅退出,这通常足够。

热重载

发送 SIGHUP 或调用 ./bin/go-web reload 即可不停机重载配置:

kill -HUP $(cat go-web.pid)
# 或
./bin/go-web reload

热重载会停止当前 Server,清空 DI 容器,重新执行装配链并启动 Server。这意味着所有单例都会被重新构建,可读取最新的 config.yaml 与环境变量。