Skip to content

配置管理与多环境部署

本篇讲解 go-zero 的配置管理体系和多环境部署实践。我们将介绍 YAML 配置文件、配置结构体、环境变量覆盖机制;详解 API 和 RPC 服务的配置项;讲解多环境(开发、测试、生产)的配置隔离方案;介绍配置中心(etcd)集成与热更新;最后演示 Docker 化部署和 Kubernetes 部署的完整流程。

一、go-zero 配置体系

go-zero 采用「YAML 配置文件 + Go 结构体」的配置模式,简洁直观且类型安全。

1. YAML 配置文件

go-zero 使用 YAML 作为配置文件格式。一个典型的 API 服务配置:

yaml
# etc/user-api.yaml
Name: user-api
Host: 0.0.0.0
Port: 8888

Auth:
  AccessSecret: "your-secret-key"
  AccessExpire: 86400

MySQL:
  DataSource: root:123456@tcp(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=true&loc=Local

CacheRedis:
  - Host: 127.0.0.1:6379
    Type: node

UserRpc:
  Etcd:
    Hosts:
      - 127.0.0.1:2379
    Key: user.rpc
  NonBlock: true
  Timeout: 2000

Log:
  ServiceName: user-api
  Mode: file
  Path: logs
  Level: info
  KeepDays: 7

Prometheus:
  Host: 0.0.0.0
  Port: 9100
  Path: /metrics

Telemetry:
  Name: user-api
  Endpoint: http://127.0.0.1:14268/api/traces
  Sampler: 1.0
  Batcher: jaeger

2. 配置结构体

YAML 文件对应一个 Go 结构体,通过 tag 声明字段映射:

go
// internal/config/config.go
package config

import (
    "github.com/zeromicro/go-zero/core/logx"
    "github.com/zeromicro/go-zero/core/stores/cache"
    "github.com/zeromicro/go-zero/core/stores/redis"
    "github.com/zeromicro/go-zero/rest"
    "github.com/zeromicro/go-zero/zrpc"
)

type Config struct {
    rest.RestConf            // 嵌入 HTTP 服务配置
    Auth struct {
        AccessSecret string
        AccessExpire int64
    }
    MySQL struct {
        DataSource string
    }
    CacheRedis cache.ClusterConf
    Redis      redis.RedisConf
    UserRpc    zrpc.RpcClientConf
}

rest.RestConfzrpc.RpcServerConf 等是 go-zero 预定义的配置结构体,包含常用字段(Host、Port、Log、Prometheus、Telemetry 等),通过结构体嵌入复用。

3. 配置加载

通过 conf.MustLoad 加载配置:

go
// main.go
var configFile = flag.String("f", "etc/user-api.yaml", "the config file")

func main() {
    flag.Parse()
    var c config.Config
    conf.MustLoad(*configFile, &c)
    // 使用 c 初始化服务
}

conf.MustLoad 的特点:

  • 支持 YAML 和 JSON 格式(按文件扩展名判断)
  • 支持环境变量覆盖
  • 加载失败会 panic(适合启动时配置校验)

4. 环境变量覆盖

go-zero 支持用环境变量覆盖配置项,规则:

  • 环境变量名 = 配置项路径,用 _ 连接,全大写
  • 嵌套结构用 _ 分隔

例如配置:

yaml
MySQL:
  DataSource: "local-dsn"

对应环境变量:

bash
# 覆盖 MySQL.DataSource
export MYSQL_DATASOURCE="prod-dsn"

多层嵌套:

yaml
UserRpc:
  Etcd:
    Hosts:
      - 127.0.0.1:2379
bash
# 覆盖 UserRpc.Etcd.Hosts(数组用逗号分隔)
export USERRPC_ETCD_HOSTS="10.0.0.1:2379,10.0.0.2:2379"

这个机制在容器化部署时非常有用:用同一份配置文件,通过环境变量区分环境。

5. 配置校验

可以在结构体上加 tag 做校验(需要第三方库),或者在 NewServiceContext 里手动校验:

go
func NewServiceContext(c config.Config) *svc.ServiceContext {
    // 校验必填项
    if c.MySQL.DataSource == "" {
        logx.Must(fmt.Errorf("MySQL.DataSource is required"))
    }
    if c.Auth.AccessSecret == "" {
        logx.Must(fmt.Errorf("Auth.AccessSecret is required"))
    }
    // ...
}

更优雅的方式是用 conf.LoadConfig 并配合校验库:

go
import "github.com/go-playground/validator/v10"

var validate = validator.New()

func main() {
    var c config.Config
    conf.MustLoad(*configFile, &c)
    if err := validate.Struct(&c); err != nil {
        logx.Must(fmt.Errorf("config invalid: %v", err))
    }
}

// 在结构体上加校验 tag
type Config struct {
    MySQL struct {
        DataSource string `validate:"required"`
    }
}

二、API 服务配置

1. RestConf:HTTP 配置

rest.RestConf 是 API 服务的核心配置,定义在 core/rest/config.go

go
type RestConf struct {
    service.ServiceConf   // 嵌入通用服务配置(Log、Prometheus、Telemetry 等)
    Host     string `json:",default=0.0.0.0"`
    Port     int
    CertFile string `json:",optional"`
    KeyFile  string `json:",optional"`
    Verbose  bool   `json:",optional"`
    MaxConns int    `json:",default=10000"`
    MaxBytes int64  `json:",default=1048576"`
    Timeout  int64  `json:",default=3000"`  // 毫秒
    CpuThreshold int64 `json:",default=900,range=[0:1000]"`
    HealthCheckPath string `json:",default=/health"`
    Middlewares   MiddlewaresConf
    MaxWaitDuration time.Duration `json:",default=60s"`
}

字段说明:

字段说明默认值
Host监听地址0.0.0.0
Port监听端口必填
CertFile/KeyFileHTTPS 证书(可选)
Verbose是否打印详细日志false
MaxConns最大并发连接数10000
MaxBytes请求体最大字节数1MB
Timeout请求超时(毫秒)3000
CpuThresholdCPU 使用率阈值(千分位)900(90%)
HealthCheckPath健康检查路径/health

Middlewares 控制内置中间件开关:

go
type MiddlewaresConf struct {
    Trace      bool `json:",default=true"`     // 链路追踪
    Recover    bool `json:",default=true"`     // panic 恢复
    Stat       bool `json:",default=true"`     // 统计
    Prometheus bool `json:",default=true"`     // Prometheus 指标
    MaxCpu     int  `json:",default=0"`        // CPU 限制
}

2. 完整 API 配置示例

yaml
Name: user-api
Host: 0.0.0.0
Port: 8888
Verbose: false
MaxConns: 10000
MaxBytes: 1048576
Timeout: 3000
CpuThreshold: 900
HealthCheckPath: /health

Middlewares:
  Trace: true
  Recover: true
  Stat: true
  Prometheus: true

Auth:
  AccessSecret: "your-256-bit-secret-key"
  AccessExpire: 86400

MySQL:
  DataSource: root:123456@tcp(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=true&loc=Local

CacheRedis:
  - Host: 127.0.0.1:6379
    Type: node

UserRpc:
  Etcd:
    Hosts:
      - 127.0.0.1:2379
    Key: user.rpc
  NonBlock: true
  Timeout: 2000

Log:
  ServiceName: user-api
  Mode: file
  Path: logs
  Level: info
  KeepDays: 7
  Compress: true

Prometheus:
  Host: 0.0.0.0
  Port: 9100
  Path: /metrics

Telemetry:
  Name: user-api
  Endpoint: http://127.0.0.1:14268/api/traces
  Sampler: 1.0
  Batcher: jaeger

三、RPC 服务配置

1. RpcServerConf

RPC 服务端配置:

go
type RpcServerConf struct {
    service.ServiceConf
    ListenOn      string
    Etcd          discov.EtcdConf   `json:",optional"`
    Auth          bool               `json:",optional"`
    Redis         redis.RedisKeyConf `json:",optional"`
    StrictCtrl    bool               `json:",optional"`
    Timeout       int64              `json:",default=2000"`
    CpuThreshold  int64              `json:",default=900,range=[0:1000]"`
    Health        bool               `json:",default=true"`
    Middlewares   ServerMiddlewaresConf
}

字段说明:

字段说明
ListenOn服务监听地址(ip:port
Etcdetcd 服务注册配置(可选,不配则直连模式)
Auth是否启用 gRPC 认证
RedisgRPC 认证用的 Redis(存储 token)
Timeout调用超时(毫秒)
Health是否启用健康检查

2. RpcClientConf

RPC 客户端配置:

go
type RpcClientConf struct {
    Etcd          discov.EtcdConf `json:",optional"`
    Endpoints     []string        `json:",optional"`
    Target        string          `json:",optional"`
    App           string          `json:",optional"`
    Token         string          `json:",optional"`
    NonBlock      bool            `json:",optional"`
    Timeout       int64           `json:",default=2000"`
    KeepaliveTime time.Duration   `json:",default=20s"`
    Middlewares   ClientMiddlewaresConf
}

三种服务发现方式(三选一):

  • Etcd:通过 etcd 服务发现(推荐)
  • Endpoints:直连多个实例(goctl 自动负载均衡)
  • Target:gRPC 标准 target(如 dns:///user.rpc:8080

3. 完整 RPC 配置示例

服务端 etc/user.yaml

yaml
Name: user.rpc
ListenOn: 0.0.0.0:8080
Timeout: 2000
CpuThreshold: 900
Health: true

Etcd:
  Hosts:
    - 127.0.0.1:2379
  Key: user.rpc

# gRPC 认证(可选)
Auth: true
Redis:
  Host: 127.0.0.1:6379
  Type: node
  Key: rpc:auth

MySQL:
  DataSource: root:123456@tcp(127.0.0.1:3306)/demo?charset=utf8mb4&parseTime=true&loc=Local

CacheRedis:
  - Host: 127.0.0.1:6379
    Type: node

Log:
  ServiceName: user.rpc
  Mode: file
  Path: logs
  Level: info
  KeepDays: 7

Prometheus:
  Host: 0.0.0.0
  Port: 9101
  Path: /metrics

Telemetry:
  Name: user.rpc
  Endpoint: http://127.0.0.1:14268/api/traces
  Sampler: 1.0
  Batcher: jaeger

四、多环境配置

1. 配置隔离方案

常见做法:每个环境一份配置文件,启动时通过 -f 指定。

etc/
├── user-api-dev.yaml      # 开发环境
├── user-api-test.yaml     # 测试环境
├── user-api-pre.yaml      # 预发环境
└── user-api-prod.yaml     # 生产环境

启动命令:

bash
# 开发环境
go run user.go -f etc/user-api-dev.yaml

# 生产环境
./user-api -f etc/user-api-prod.yaml

2. 配置差异

不同环境的配置差异主要体现在:

yaml
# dev:本地调试,详细日志
Log:
  Level: debug
  Mode: console
MySQL:
  DataSource: root:123456@tcp(127.0.0.1:3306)/demo_dev
CacheRedis:
  - Host: 127.0.0.1:6379
    Type: node
Etcd:
  Hosts:
    - 127.0.0.1:2379

# test:测试环境
Log:
  Level: info
  Mode: file
MySQL:
  DataSource: test:test@tcp(10.0.0.1:3306)/demo_test
CacheRedis:
  - Host: 10.0.0.2:6379
    Type: node
Etcd:
  Hosts:
    - 10.0.0.3:2379

# prod:生产环境
Log:
  Level: error
  Mode: file
  KeepDays: 30
MySQL:
  DataSource: prod:strong-pass@tcp(mysql-master:3306)/demo?charset=utf8mb4&parseTime=true&loc=Local
CacheRedis:
  - Host: redis-master:6379
    Type: node
    Pass: prod-redis-pass
Etcd:
  Hosts:
    - etcd-1:2379
    - etcd-2:2379
    - etcd-3:2379

3. 敏感信息管理

敏感信息(密码、密钥)不应放在配置文件中,建议:

  • 用环境变量覆盖
  • 用配置中心管理
  • 用 K8s Secret

环境变量覆盖示例:

bash
# 启动时注入环境变量
export MYSQL_DATASOURCE="prod:strong-pass@tcp(mysql:3306)/demo"
export AUTH_ACCESSSECRET="prod-secret-key"
./user-api -f etc/user-api-prod.yaml

4. 配置模板化

如果多环境差异较大,可以用模板生成配置:

bash
# 用 envsubst 替换占位符
envsubst < etc/user-api.yaml.tmpl > etc/user-api-prod.yaml

模板文件 user-api.yaml.tmpl

yaml
Name: user-api
Host: 0.0.0.0
Port: ${API_PORT}
MySQL:
  DataSource: ${MYSQL_DSN}
Auth:
  AccessSecret: ${JWT_SECRET}

启动时:

bash
export API_PORT=8888
export MYSQL_DSN="prod:pass@tcp(mysql:3306)/demo"
export JWT_SECRET="prod-secret"
envsubst < etc/user-api.yaml.tmpl > /tmp/user-api.yaml
./user-api -f /tmp/user-api.yaml

五、配置中心集成

1. 从 etcd 读取配置

go-zero 支持把配置存到 etcd,启动时从 etcd 拉取:

go
// main.go
import "github.com/zeromicro/go-zero/core/conf"

var (
    configFile = flag.String("f", "etc/user-api.yaml", "local config")
    configKey  = flag.String("k", "", "etcd config key")
    etcdHosts  = flag.String("e", "", "etcd hosts, comma separated")
)

func main() {
    flag.Parse()
    var c config.Config

    if *configKey != "" {
        // 从 etcd 读取配置
        conf.MustLoadFromEtcd(*etcdHosts, *configKey, &c)
    } else {
        // 从本地文件读取
        conf.MustLoad(*configFile, &c)
    }
    // ...
}

在 etcd 中存储配置:

bash
# 写入配置到 etcd
etcdctl --endpoints=127.0.0.1:2379 put /config/user-api/prod < etc/user-api-prod.yaml

# 读取验证
etcdctl --endpoints=127.0.0.1:2379 get /config/user-api/prod

启动服务:

bash
./user-api -k /config/user-api/prod -e 127.0.0.1:2379

2. 热更新配置

go-zero 内置的配置加载是「一次性」的(启动时加载),不支持自动热更新。如果需要热更新,可以监听 etcd 变更:

go
import (
    "github.com/zeromicro/go-zero/core/discov"
    "github.com/zeromicro/go-zero/core/stores/etcd"
)

func watchConfig(etcdHosts []string, key string, onChange func(content string)) {
    client := etcd.NewEtcd(etcdHosts)
    ch := client.Watch(key)
    go func() {
        for event := range ch {
            if event.Type == etcd.EventTypePut {
                onChange(string(event.Kv.Value))
            }
        }
    }()
}

// 使用
watchConfig([]string{"127.0.0.1:2379"}, "/config/user-api/prod", func(content string) {
    logx.Info("config changed, reloading...")
    var c config.Config
    if err := conf.LoadFromYamlBytes([]byte(content), &c); err != nil {
        logx.Errorf("reload config failed: %v", err)
        return
    }
    // 更新运行时配置(需要服务支持)
    // 注意:不是所有配置都支持热更新,如 Port、Host 等
})

支持热更新的配置项通常有限,比如:

  • 日志级别
  • 限流阈值
  • 功能开关
  • 黑白名单

而端口、数据库连接、etcd 地址等不适合热更新(需要重启服务)。

3. 配置中心选型

除了 etcd,也可以用其他配置中心:

  • Apollo(携程开源):功能丰富,支持灰度发布、权限管理
  • Nacos(阿里开源):配置 + 注册中心一体
  • Consul:服务发现 + 配置
  • etcd:go-zero 原生支持,简单轻量

go-zero 与 etcd 集成最自然,推荐中小项目用 etcd;大型团队可以考虑 Apollo/Nacos。

六、Docker 化部署

1. Dockerfile

go-zero 服务的 Dockerfile 推荐用多阶段构建:

dockerfile
# 构建阶段
FROM golang:1.20-alpine AS builder

# 安装必要工具
RUN apk add --no-cache git

WORKDIR /app

# 缓存依赖
COPY go.mod go.sum ./
RUN go mod download

# 复制源码并构建
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/user-api user.go

# 运行阶段
FROM alpine:3.18

# 安装 CA 证书(HTTPS 调用需要)
RUN apk --no-cache add ca-certificates tzdata
ENV TZ=Asia/Shanghai

WORKDIR /app

# 复制二进制和配置
COPY --from=builder /app/user-api /app/user-api
COPY --from=builder /app/etc /app/etc

EXPOSE 8888

ENTRYPOINT ["/app/user-api", "-f", "/app/etc/user-api.yaml"]

构建和运行:

bash
# 构建镜像
docker build -t user-api:v1 .

# 运行
docker run -d --name user-api \
  -p 8888:8888 \
  -e MYSQL_DATASOURCE="prod:pass@tcp(mysql:3306)/demo" \
  user-api:v1

2. 用 goctl 生成 Dockerfile

goctl 可以自动生成 Dockerfile:

bash
goctl docker -go user.go -port 8888 -exe user-api

生成的 Dockerfile 与上面的类似,可以根据需要调整。

3. docker-compose 编排

开发环境用 docker-compose 编排所有服务:

yaml
# docker-compose.yml
version: "3.8"

services:
  # 基础设施
  mysql:
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
      MYSQL_DATABASE: "demo"
    volumes:
      - mysql-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  etcd:
    image: bitnami/etcd:3.5
    ports:
      - "2379:2379"
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd:2379

  jaeger:
    image: jaegertracing/all-in-one:1.45
    ports:
      - "16686:16686"
      - "4318:4318"

  # 业务服务
  user-rpc:
    build: ./user-rpc
    ports:
      - "8080:8080"
    depends_on:
      - mysql
      - redis
      - etcd
    environment:
      - MYSQL_DATASOURCE=root:123456@tcp(mysql:3306)/demo?charset=utf8mb4&parseTime=true&loc=Local
    restart: on-failure

  user-api:
    build: ./user-api
    ports:
      - "8888:8888"
    depends_on:
      - user-rpc
      - redis
      - etcd
    environment:
      - MYSQL_DATASOURCE=root:123456@tcp(mysql:3306)/demo?charset=utf8mb4&parseTime=true&loc=Local
    restart: on-failure

volumes:
  mysql-data:

注意:docker-compose 中服务间用服务名互访(如 mysql:3306),配置文件中也要用服务名。

4. 镜像优化

减小镜像大小:

dockerfile
# 用 scratch 作为基础镜像(最小)
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
COPY --from=builder /app/user-api /user-api
COPY --from=builder /app/etc /etc
ENTRYPOINT ["/user-api", "-f", "/etc/user-api.yaml"]

scratch 镜像约 10-20MB,但缺少 shell,调试不便。生产环境可以用 alpine(约 5-10MB 基础 + 业务)。

构建参数优化:

bash
# 去除调试信息
go build -ldflags="-s -w" -o user-api user.go

# UPX 压缩(可选,进一步减小体积)
upx --best --lzma user-api

七、Kubernetes 部署

1. Deployment

yaml
# k8s/user-api-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-api
  namespace: production
  labels:
    app: user-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-api
  template:
    metadata:
      labels:
        app: user-api
    spec:
      containers:
        - name: user-api
          image: registry.cn-hangzhou.aliyuncs.com/myrepo/user-api:v1
          ports:
            - containerPort: 8888
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"
          env:
            - name: MYSQL_DATASOURCE
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: mysql-dsn
            - name: AUTH_ACCESSSECRET
              valueFrom:
                secretKeyRef:
                  name: jwt-secret
                  key: access-secret
          volumeMounts:
            - name: config
              mountPath: /app/etc
          readinessProbe:
            httpGet:
              path: /health
              port: 8888
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /health
              port: 8888
            initialDelaySeconds: 30
            periodSeconds: 30
      volumes:
        - name: config
          configMap:
            name: user-api-config

2. ConfigMap

把非敏感配置放 ConfigMap:

yaml
# k8s/user-api-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: user-api-config
  namespace: production
data:
  user-api.yaml: |
    Name: user-api
    Host: 0.0.0.0
    Port: 8888
    Timeout: 3000

    MySQL:
      DataSource: root:123456@tcp(mysql:3306)/demo?charset=utf8mb4&parseTime=true&loc=Local

    CacheRedis:
      - Host: redis:6379
        Type: node

    UserRpc:
      Etcd:
        Hosts:
          - etcd:2379
        Key: user.rpc
      NonBlock: true
      Timeout: 2000

    Log:
      ServiceName: user-api
      Mode: file
      Path: logs
      Level: info
      KeepDays: 7

    Prometheus:
      Host: 0.0.0.0
      Port: 9100
      Path: /metrics

敏感信息放 Secret:

yaml
# k8s/user-api-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
  namespace: production
type: Opaque
stringData:
  mysql-dsn: "prod:strong-pass@tcp(mysql-master:3306)/demo"
---
apiVersion: v1
kind: Secret
metadata:
  name: jwt-secret
  namespace: production
type: Opaque
stringData:
  access-secret: "prod-jwt-secret-key"

3. Service

yaml
# k8s/user-api-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: user-api
  namespace: production
spec:
  selector:
    app: user-api
  ports:
    - name: http
      port: 80
      targetPort: 8888
      protocol: TCP
    - name: metrics
      port: 9100
      targetPort: 9100
      protocol: TCP
  type: ClusterIP

如果需要对外暴露,用 Ingress:

yaml
# k8s/user-api-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: user-api-ingress
  namespace: production
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: user-api
                port:
                  number: 80

4. HPA 自动扩缩容

yaml
# k8s/user-api-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: user-api
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: user-api
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

5. 用 goctl 生成 K8s 部署文件

goctl 可以一键生成 K8s 部署文件:

bash
goctl kube deploy -name user-api \
  -namespace production \
  -image registry.cn-hangzhou.aliyuncs.com/myrepo/user-api:v1 \
  -secret db-secret \
  -configMap user-api-config \
  -port 8888 \
  -replicas 3 \
  -o k8s/user-api.yaml

6. 完整部署流程

bash
# 1. 创建命名空间
kubectl create namespace production

# 2. 应用配置
kubectl apply -f k8s/user-api-configmap.yaml
kubectl apply -f k8s/user-api-secret.yaml
kubectl apply -f k8s/user-api-deployment.yaml
kubectl apply -f k8s/user-api-service.yaml
kubectl apply -f k8s/user-api-hpa.yaml

# 3. 查看状态
kubectl get pods -n production -l app=user-api
kubectl logs -f deployment/user-api -n production

# 4. 滚动更新
kubectl set image deployment/user-api user-api=registry.cn-hangzhou.aliyuncs.com/myrepo/user-api:v2 -n production

# 5. 回滚
kubectl rollout undo deployment/user-api -n production

八、配置管理最佳实践

1. 配置分层

默认配置(代码内默认值)
    ↓ 覆盖
环境配置(YAML 文件)
    ↓ 覆盖
环境变量(容器/K8s)
    ↓ 覆盖
配置中心(动态配置)

越上层越通用,越下层越具体。

2. 敏感信息保护

  • 密码、密钥、token 不进 Git
  • 用 Secret Manager 或 K8s Secret
  • 配置文件用占位符,启动时注入
  • 日志中不要打印敏感配置

3. 配置版本化

  • 配置文件随代码一起版本管理
  • 配置变更走 Code Review
  • 配置中心支持历史版本回滚

4. 配置校验

  • 启动时校验必填项
  • 用单元测试覆盖配置解析
  • CI 流程中校验配置语法
go
// config_test.go
func TestConfigLoad(t *testing.T) {
    var c Config
    err := conf.LoadConfig("etc/user-api.yaml", &c)
    assert.NoError(t, err)
    assert.NotEmpty(t, c.MySQL.DataSource)
    assert.NotEmpty(t, c.Auth.AccessSecret)
}

5. 配置文档

为每个配置项写文档,可以用 struct 注释:

go
type Config struct {
    rest.RestConf
    MySQL struct {
        // DataSource 是 MySQL 连接串,格式:user:pass@tcp(host:port)/db
        DataSource string
    }
    Auth struct {
        // AccessSecret 是 JWT 签名密钥,至少 32 字符
        AccessSecret string
        // AccessExpire 是 token 过期时间(秒)
        AccessExpire int64
    }
}

九、小结

本篇讲解了 go-zero 的配置管理与多环境部署。要点回顾:

  • 配置采用 YAML 文件 + Go 结构体,支持环境变量覆盖
  • rest.RestConfzrpc.RpcServerConf 是核心配置结构,包含内置中间件、监控、链路追踪等开关
  • 多环境配置隔离:每个环境一份 YAML,启动时 -f 指定
  • 配置中心集成:etcd 存储 + 热更新监听(部分配置项支持)
  • Docker 化部署:多阶段构建,镜像优化(alpine/scratch)
  • K8s 部署:Deployment + ConfigMap + Secret + Service + HPA
  • goctl 可自动生成 Dockerfile 和 K8s 部署文件
  • 敏感信息用 Secret 管理,配置文件用占位符
  • 配置分层、版本化、校验、文档化是最佳实践

下一篇我们将进入日志、监控与链路追踪,讲解 go-zero 的可观测性体系。