返回首页

Golang横向:02 Kubernetes 部署模型与实战

在云原生体系里,Kubernetes 已经成为容器编排的事实标准。对于 Go 应用而言,Kubernetes 不只是一个“把容器跑起来”的平台,更是一套完整的部署、扩缩容、故障恢复和多环境治理方案。

本文会以一个可运行的 Go HTTP 服务为例,系统讲清楚 Kubernetes 部署模型的关键概念,并给出一套相对完整的实战 YAML 配置,覆盖以下内容:

  • K8s 核心资源:Pod、Deployment、Service、ConfigMap、Secret
  • Go 应用完整 K8s 部署 YAML 编写
  • 资源限制(requests/limits)与 HPA 自动扩缩容
  • Readiness/Liveness/Startup Probe 配置
  • 滚动更新与回滚策略
  • 多环境配置管理(dev/staging/prod)

如果你已经会写 Dockerfile,但还不太清楚如何让服务在 Kubernetes 中稳定、可控、可扩展地运行,这篇文章可以作为一份从概念到落地的实战模板。

一、先理解 Kubernetes 的部署模型

在 Kubernetes 中,应用部署通常不是“启动一个容器”这么简单,而是由一组资源对象共同协作完成。

我们可以先从一个典型链路来理解:

  1. 开发者将 Go 服务打包成镜像。
  2. Kubernetes 使用 Deployment 管理 Pod 的副本数和发布策略。
  3. Pod 中运行真正的容器实例。
  4. Service 为 Pod 提供稳定访问入口。
  5. ConfigMap 和 Secret 为应用注入配置与敏感信息。
  6. HPA 根据 CPU 或内存等指标进行自动扩缩容。
  7. Probe 探针负责健康检查,保证流量只进入可用实例。

也就是说,Kubernetes 的部署模型本质上是:用声明式资源描述“应用应该如何运行”,再由控制器持续把集群状态收敛到目标状态。

二、K8s 核心资源详解

先把本文涉及到的几个核心资源捋清楚。

资源 作用 典型职责
Pod Kubernetes 中最小调度单元 承载一个或多个紧密协作的容器
Deployment 无状态应用的部署控制器 管理副本、滚动更新、回滚
Service 服务访问抽象 为一组 Pod 提供稳定地址和负载均衡
ConfigMap 非敏感配置管理 注入环境变量、配置文件、启动参数
Secret 敏感配置管理 存储密码、Token、密钥等

1. Pod

Pod 是 Kubernetes 的最小调度单位。一个 Pod 中可以包含一个主容器,也可以有多个协同容器,但最常见的场景仍然是“一个 Pod 跑一个应用容器”。

对 Go Web 服务来说,一个 Pod 往往就代表一个服务实例。

Pod 有几个很重要的特点:

  • Pod 内多个容器共享网络命名空间
  • Pod 有独立 IP,但这个 IP 不是稳定不变的
  • Pod 可能因为重建、漂移、故障恢复而被替换

因此,不要直接依赖 Pod IP 访问服务,而应通过 Service 暴露稳定入口。

2. Deployment

Deployment 是日常部署 Go 无状态服务最常用的资源。它并不直接管理容器,而是通过 ReplicaSet 间接管理 Pod。

Deployment 主要解决这些问题:

  • 维持指定副本数
  • 支持滚动更新
  • 支持历史版本回滚
  • 支持声明式变更

例如,你希望服务始终有 3 个副本在线,那么即使其中某个 Pod 异常退出,Deployment 也会自动补齐。

3. Service

Pod 会变化,但业务访问入口不能变化。所以 Kubernetes 引入了 Service。

Service 会把一组带有相同 label 的 Pod 聚合起来,对外暴露一个稳定的访问地址,并在内部进行负载均衡。

常见的 Service 类型包括:

  • ClusterIP:集群内部访问,默认类型
  • NodePort:通过节点端口暴露服务
  • LoadBalancer:通过云厂商负载均衡对外暴露

在微服务内部调用场景中,ClusterIP 是最常用的。

4. ConfigMap

ConfigMap 用于存储非敏感配置,例如:

  • 服务监听端口
  • 日志级别
  • 运行环境标识
  • 下游服务地址

这样做的好处是:镜像与配置解耦。同一个镜像,可以在不同环境通过不同 ConfigMap 注入不同配置,而不需要重新构建镜像。

5. Secret

Secret 用于存储敏感信息,例如:

  • 数据库用户名和密码
  • JWT 签名密钥
  • 第三方 API Token

虽然 Secret 默认只是 Base64 编码,不等于绝对安全,但它仍然是 Kubernetes 中管理敏感配置的标准做法。生产环境一般还会配合 KMS、外部密钥管理系统或密文方案使用。

三、实战示例:一个可运行的 Go HTTP 服务

下面我们先准备一个简单的 Go 服务,用于后续完整部署演示。

1. 目录结构

.
├── Dockerfile
├── go.mod
├── main.go
└── k8s
    ├── base
    │   ├── configmap.yaml
    │   ├── deployment.yaml
    │   ├── hpa.yaml
    │   ├── secret.yaml
    │   └── service.yaml
    └── overlays
        ├── dev
        │   └── kustomization.yaml
        ├── staging
        │   └── kustomization.yaml
        └── prod
            └── kustomization.yaml

2. Go 应用代码

这个服务提供几个接口:

  • /healthz:用于 liveness 检查
  • /readyz:用于 readiness 检查
  • /startupz:用于 startup 检查
  • /config:查看当前环境配置
package main

import (
    "encoding/json"
    "log"
    "net/http"
    "os"
    "sync/atomic"
    "time"
)

type App struct {
    started atomic.Bool
}

type Config struct {
    AppName     string `json:"appName"`
    AppEnv      string `json:"appEnv"`
    Port        string `json:"port"`
    LogLevel    string `json:"logLevel"`
    FeatureFlag string `json:"featureFlag"`
    DBHost      string `json:"dbHost"`
    DBUser      string `json:"dbUser"`
}

func getEnv(key, fallback string) string {
    if value := os.Getenv(key); value != "" {
        return value
    }
    return fallback
}

func loadConfig() Config {
    return Config{
        AppName:     getEnv("APP_NAME", "go-k8s-demo"),
        AppEnv:      getEnv("APP_ENV", "dev"),
        Port:        getEnv("PORT", "8080"),
        LogLevel:    getEnv("LOG_LEVEL", "info"),
        FeatureFlag: getEnv("FEATURE_FLAG", "false"),
        DBHost:      getEnv("DB_HOST", "mysql.default.svc.cluster.local"),
        DBUser:      getEnv("DB_USER", "demo_user"),
    }
}

func main() {
    cfg := loadConfig()
    app := &App{}

    go func() {
        time.Sleep(12 * time.Second)
        app.started.Store(true)
        log.Println("application startup completed")
    }()

    mux := http.NewServeMux()

    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
        _, _ = w.Write([]byte("hello from go app on kubernetes\n"))
    })

    mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
        _, _ = w.Write([]byte("ok\n"))
    })

    mux.HandleFunc("/startupz", func(w http.ResponseWriter, r *http.Request) {
        if !app.started.Load() {
            http.Error(w, "starting", http.StatusServiceUnavailable)
            return
        }
        w.WriteHeader(http.StatusOK)
        _, _ = w.Write([]byte("started\n"))
    })

    mux.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) {
        if !app.started.Load() {
            http.Error(w, "not ready", http.StatusServiceUnavailable)
            return
        }
        w.WriteHeader(http.StatusOK)
        _, _ = w.Write([]byte("ready\n"))
    })

    mux.HandleFunc("/config", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        _ = json.NewEncoder(w).Encode(cfg)
    })

    addr := ":" + cfg.Port
    log.Printf("app=%s env=%s listening on %s", cfg.AppName, cfg.AppEnv, addr)
    if err := http.ListenAndServe(addr, mux); err != nil {
        log.Fatalf("server exited: %v", err)
    }
}

3. go.mod

module github.com/example/go-k8s-demo

go 1.22

4. Dockerfile

下面是一个适合 Go 服务的多阶段构建镜像示例。

FROM golang:1.22-alpine AS builder
WORKDIR /app

COPY go.mod .
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server main.go

FROM alpine:3.20
WORKDIR /app
RUN addgroup -S app && adduser -S app -G app
COPY --from=builder /app/server /app/server
USER app
EXPOSE 8080
ENTRYPOINT ["/app/server"]

构建并推送镜像示例:

docker build -t registry.example.com/demo/go-k8s-demo:v1.0.0 .
docker push registry.example.com/demo/go-k8s-demo:v1.0.0

四、Go 应用完整 K8s 部署 YAML 编写

下面给出一套较完整的 Kubernetes 部署清单。

1. ConfigMap

用于保存非敏感配置。

apiVersion: v1
kind: ConfigMap
metadata:
  name: go-k8s-demo-config
  labels:
    app: go-k8s-demo
data:
  APP_NAME: go-k8s-demo
  PORT: "8080"
  LOG_LEVEL: info
  FEATURE_FLAG: "false"
  DB_HOST: mysql.default.svc.cluster.local

2. Secret

用于保存敏感配置。这里使用 stringData 便于编写明文,Kubernetes 会自动转换。

apiVersion: v1
kind: Secret
metadata:
  name: go-k8s-demo-secret
  labels:
    app: go-k8s-demo
type: Opaque
stringData:
  DB_USER: demo_user
  DB_PASSWORD: demo_password
  JWT_SECRET: demo-jwt-secret

3. Service

为 Deployment 管理的 Pod 提供稳定访问入口。

apiVersion: v1
kind: Service
metadata:
  name: go-k8s-demo
  labels:
    app: go-k8s-demo
spec:
  type: ClusterIP
  selector:
    app: go-k8s-demo
  ports:
    - name: http
      port: 80
      targetPort: 8080
      protocol: TCP

4. Deployment

这是本文的核心配置,包含:

  • 副本数
  • 资源限制
  • 探针
  • 滚动更新策略
  • ConfigMap / Secret 注入
  • 安全上下文
apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-k8s-demo
  labels:
    app: go-k8s-demo
spec:
  replicas: 2
  revisionHistoryLimit: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app: go-k8s-demo
  template:
    metadata:
      labels:
        app: go-k8s-demo
    spec:
      terminationGracePeriodSeconds: 30
      containers:
        - name: app
          image: registry.example.com/demo/go-k8s-demo:v1.0.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          env:
            - name: APP_ENV
              value: "dev"
          envFrom:
            - configMapRef:
                name: go-k8s-demo-config
            - secretRef:
                name: go-k8s-demo-secret
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"
          startupProbe:
            httpGet:
              path: /startupz
              port: http
            periodSeconds: 3
            timeoutSeconds: 1
            failureThreshold: 10
          readinessProbe:
            httpGet:
              path: /readyz
              port: http
            initialDelaySeconds: 3
            periodSeconds: 5
            timeoutSeconds: 1
            successThreshold: 1
            failureThreshold: 3
          livenessProbe:
            httpGet:
              path: /healthz
              port: http
            initialDelaySeconds: 10
            periodSeconds: 10
            timeoutSeconds: 1
            failureThreshold: 3
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsNonRoot: true
            runAsUser: 10001
            capabilities:
              drop:
                - ALL

5. HPA

HPA 会根据资源使用情况自动调整副本数。

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: go-k8s-demo
  labels:
    app: go-k8s-demo
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: go-k8s-demo
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 75
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
        - type: Percent
          value: 100
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 50
          periodSeconds: 60

6. 一次性应用全部资源

如果你不做环境区分,可以直接按顺序应用:

kubectl apply -f k8s/base/configmap.yaml
kubectl apply -f k8s/base/secret.yaml
kubectl apply -f k8s/base/service.yaml
kubectl apply -f k8s/base/deployment.yaml
kubectl apply -f k8s/base/hpa.yaml

检查部署结果:

kubectl get deploy,po,svc,hpa
kubectl describe deployment go-k8s-demo
kubectl get events --sort-by=.metadata.creationTimestamp

五、为什么资源限制和 HPA 必须一起设计

很多团队刚接触 Kubernetes 时,会把 requests/limits 和 HPA 分开理解,但在真实生产环境里,它们应该一起设计。

1. requests 与 limits 的区别

  • requests:调度时的保底资源需求
  • limits:容器运行时允许使用的资源上限

如果不给 requests,调度器就难以合理安置 Pod;如果不给 limits,某个实例可能会在异常情况下吃掉过多资源,影响节点稳定性。

一个典型配置如下:

resources:
  requests:
    cpu: "100m"
    memory: "128Mi"
  limits:
    cpu: "500m"
    memory: "512Mi"

这里的含义是:

  • 应用至少需要 0.1 核 CPU、128Mi 内存才能稳定运行
  • 允许峰值最多使用 0.5 核 CPU、512Mi 内存

2. HPA 为什么依赖 requests

很多人会忽略一点:基于 CPU 使用率的 HPA,本质上是相对于 requests 来计算目标利用率的。

例如:

  • Pod requests.cpu = 100m
  • 当前实际使用为 80m
  • 那么 CPU 利用率约为 80%

如果 HPA 目标是 70%,那么就可能触发扩容。

这意味着:

  • requests 配太小,HPA 容易频繁扩容
  • requests 配太大,HPA 又可能不敏感

所以 requests 不能凭感觉拍脑袋设置,而应基于压测数据、历史监控和业务峰谷规律来确定。

3. 一个更稳妥的资源规划思路

可以按下面的思路进行:

  1. 先压测单 Pod 的吞吐和平均资源占用。
  2. 根据常态流量设置 requests。
  3. 根据峰值流量和节点容量设置 limits。
  4. 再根据业务目标设置 HPA 的目标利用率和副本区间。

例如:

  • 常态 CPU 使用 80m,峰值 250m
  • requests 可设为 100m
  • limits 可设为 500m
  • HPA CPU target 可先设为 70%

这样系统会更稳定,也更容易预测扩容行为。

六、Readiness、Liveness、Startup Probe 如何正确配置

探针配置是 Kubernetes 稳定部署的关键。很多线上故障并不是程序本身崩了,而是探针配置不合理导致实例反复被重启或流量误切。

1. 三种探针的职责分工

探针 作用 常见问题场景
Startup Probe 判断应用是否完成启动 启动慢、预热时间长
Readiness Probe 判断是否可以接收流量 依赖未就绪、缓存未加载完成
Liveness Probe 判断是否还活着 死锁、卡死、主循环异常

2. 为什么 Go 应用也需要 Startup Probe

很多人觉得 Go 程序启动很快,不需要 Startup Probe。实际上,服务本身启动快,不代表“业务已可用”。

例如下面这些场景:

  • 需要预热本地缓存
  • 需要加载大字典或规则文件
  • 需要等待下游连接准备完毕
  • 需要初始化连接池

如果没有 Startup Probe,Liveness 可能过早介入,导致服务还没启动完就被重启。

3. 本文示例中的探针逻辑

示例程序中,应用会在 12 秒后把内部状态标记为启动完成。

因此:

  • /startupz 在启动完成前返回 503
  • /readyz 在启动完成前返回 503
  • /healthz 始终返回 200,表示进程还活着

这对应的探针配置如下:

startupProbe:
  httpGet:
    path: /startupz
    port: http
  periodSeconds: 3
  timeoutSeconds: 1
  failureThreshold: 10

readinessProbe:
  httpGet:
    path: /readyz
    port: http
  initialDelaySeconds: 3
  periodSeconds: 5
  timeoutSeconds: 1
  failureThreshold: 3

livenessProbe:
  httpGet:
    path: /healthz
    port: http
  initialDelaySeconds: 10
  periodSeconds: 10
  timeoutSeconds: 1
  failureThreshold: 3

4. 实战中的配置建议

  • healthz 尽量只表示“进程是否存活”,不要把太多外部依赖判断塞进去
  • readyz 应体现“当前实例是否适合接流量”
  • 启动耗时超过数秒的应用,优先补上 startupProbe
  • 探针阈值不要过于激进,否则容易误杀正常实例

七、滚动更新与回滚策略

Kubernetes 中最常用的发布方式就是滚动更新。它能在不中断服务的前提下,逐步替换旧版本 Pod。

1. RollingUpdate 配置含义

Deployment 中常见配置如下:

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 0
    maxSurge: 1

含义如下:

  • maxUnavailable: 0:更新过程中,至少保证当前期望副本数全部可用
  • maxSurge: 1:更新时允许额外多启动 1 个新 Pod

如果 Deployment 期望副本数为 2,那么更新过程可能会这样进行:

  1. 先额外拉起 1 个新版本 Pod,总数变成 3
  2. 新 Pod readiness 成功后,下掉 1 个旧 Pod
  3. 再拉起下一个新 Pod
  4. 最终完成全部替换

这种方式对线上服务更平滑。

2. 触发滚动更新

修改镜像版本后重新 apply 即可。

kubectl set image deployment/go-k8s-demo app=registry.example.com/demo/go-k8s-demo:v1.0.1
kubectl rollout status deployment/go-k8s-demo

查看发布历史:

kubectl rollout history deployment/go-k8s-demo

3. 回滚策略

如果新版本异常,可以直接回滚。

kubectl rollout undo deployment/go-k8s-demo

如果你想回滚到指定 revision:

kubectl rollout history deployment/go-k8s-demo
kubectl rollout undo deployment/go-k8s-demo --to-revision=3

4. 生产实践建议

  • 保留足够的 revisionHistoryLimit
  • 配合 readiness probe,确保新实例就绪后才接流量
  • 不要把大版本配置改动、镜像升级、资源参数改动一次性全部混在一起发布
  • 发布前后观察 rollout status、Pod 日志和关键指标

八、多环境配置管理:dev / staging / prod

多环境管理是 Kubernetes 落地中的核心问题之一。同一个 Go 服务,通常会在开发、预发、生产等环境使用不同配置,例如:

  • 镜像标签不同
  • 副本数不同
  • 资源配额不同
  • 日志级别不同
  • 功能开关不同
  • 下游依赖地址不同

如果把这些差异都硬编码到一份 YAML 中,后期会非常难维护。因此建议采用 base + overlay 的方式管理。

本文使用 Kustomize 来演示多环境配置。

1. base 层:放公共配置

先准备 k8s/base/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - configmap.yaml
  - secret.yaml
  - service.yaml
  - deployment.yaml
  - hpa.yaml

2. dev 环境

开发环境通常副本更少、日志更详细、功能开关更灵活。

k8s/overlays/dev/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: dev
namePrefix: dev-

resources:
  - ../../base

labels:
  - pairs:
      env: dev

replicas:
  - name: go-k8s-demo
    count: 1

images:
  - name: registry.example.com/demo/go-k8s-demo
    newTag: v1.0.0-dev

configMapGenerator:
  - name: go-k8s-demo-config
    behavior: merge
    literals:
      - APP_NAME=go-k8s-demo
      - APP_ENV=dev
      - PORT=8080
      - LOG_LEVEL=debug
      - FEATURE_FLAG=true
      - DB_HOST=mysql.dev.svc.cluster.local

patches:
  - target:
      kind: Deployment
      name: go-k8s-demo
    patch: |
      - op: replace
        path: /spec/template/spec/containers/0/resources/requests/cpu
        value: "50m"
      - op: replace
        path: /spec/template/spec/containers/0/resources/requests/memory
        value: "64Mi"
      - op: replace
        path: /spec/template/spec/containers/0/resources/limits/cpu
        value: "200m"
      - op: replace
        path: /spec/template/spec/containers/0/resources/limits/memory
        value: "256Mi"
      - op: replace
        path: /spec/template/spec/containers/0/env/0/value
        value: dev

3. staging 环境

预发环境更接近生产环境,用于联调、灰度和验收。

k8s/overlays/staging/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: staging
namePrefix: staging-

resources:
  - ../../base

labels:
  - pairs:
      env: staging

replicas:
  - name: go-k8s-demo
    count: 2

images:
  - name: registry.example.com/demo/go-k8s-demo
    newTag: v1.0.0-rc1

configMapGenerator:
  - name: go-k8s-demo-config
    behavior: merge
    literals:
      - APP_NAME=go-k8s-demo
      - APP_ENV=staging
      - PORT=8080
      - LOG_LEVEL=info
      - FEATURE_FLAG=false
      - DB_HOST=mysql.staging.svc.cluster.local

patches:
  - target:
      kind: Deployment
      name: go-k8s-demo
    patch: |
      - op: replace
        path: /spec/template/spec/containers/0/resources/requests/cpu
        value: "100m"
      - op: replace
        path: /spec/template/spec/containers/0/resources/requests/memory
        value: "128Mi"
      - op: replace
        path: /spec/template/spec/containers/0/resources/limits/cpu
        value: "500m"
      - op: replace
        path: /spec/template/spec/containers/0/resources/limits/memory
        value: "512Mi"
      - op: replace
        path: /spec/template/spec/containers/0/env/0/value
        value: staging

4. prod 环境

生产环境通常副本更多,资源更稳健,日志级别更保守。

k8s/overlays/prod/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: prod
namePrefix: prod-

resources:
  - ../../base

labels:
  - pairs:
      env: prod

replicas:
  - name: go-k8s-demo
    count: 3

images:
  - name: registry.example.com/demo/go-k8s-demo
    newTag: v1.0.0

configMapGenerator:
  - name: go-k8s-demo-config
    behavior: merge
    literals:
      - APP_NAME=go-k8s-demo
      - APP_ENV=prod
      - PORT=8080
      - LOG_LEVEL=warn
      - FEATURE_FLAG=false
      - DB_HOST=mysql.prod.svc.cluster.local

patches:
  - target:
      kind: Deployment
      name: go-k8s-demo
    patch: |
      - op: replace
        path: /spec/template/spec/containers/0/resources/requests/cpu
        value: "200m"
      - op: replace
        path: /spec/template/spec/containers/0/resources/requests/memory
        value: "256Mi"
      - op: replace
        path: /spec/template/spec/containers/0/resources/limits/cpu
        value: "1000m"
      - op: replace
        path: /spec/template/spec/containers/0/resources/limits/memory
        value: "1024Mi"
      - op: replace
        path: /spec/template/spec/containers/0/env/0/value
        value: prod
  - target:
      kind: HorizontalPodAutoscaler
      name: go-k8s-demo
    patch: |
      - op: replace
        path: /spec/minReplicas
        value: 3
      - op: replace
        path: /spec/maxReplicas
        value: 20

5. 按环境部署

部署开发环境:

kubectl apply -k k8s/overlays/dev

部署预发环境:

kubectl apply -k k8s/overlays/staging

部署生产环境:

kubectl apply -k k8s/overlays/prod

查看渲染后的 YAML:

kubectl kustomize k8s/overlays/prod

6. 多环境管理的实践建议

  • 公共逻辑放 base
  • 环境差异放 overlay
  • 镜像版本、资源规格、环境变量按环境拆分
  • Secret 尽量通过外部密钥系统管理,不要长期明文提交到仓库
  • 生产环境变更应可审计、可回滚、可追踪

九、一套完整的部署流程示例

把前面的内容串起来,一个典型的 Go 服务 Kubernetes 部署流程可以是这样:

1. 本地构建镜像

docker build -t registry.example.com/demo/go-k8s-demo:v1.0.0 .
docker push registry.example.com/demo/go-k8s-demo:v1.0.0

2. 预览生产环境配置

kubectl kustomize k8s/overlays/prod

3. 部署到集群

kubectl apply -k k8s/overlays/prod

4. 观察发布状态

kubectl rollout status deployment/prod-go-k8s-demo -n prod
kubectl get po -n prod -w

5. 检查 Service 与 HPA

kubectl get svc,hpa -n prod
kubectl describe hpa prod-go-k8s-demo -n prod

6. 模拟发布新版本

kubectl set image deployment/prod-go-k8s-demo app=registry.example.com/demo/go-k8s-demo:v1.0.1 -n prod
kubectl rollout status deployment/prod-go-k8s-demo -n prod

7. 异常时快速回滚

kubectl rollout undo deployment/prod-go-k8s-demo -n prod

十、实战中最容易踩的几个坑

最后再总结几个非常常见的问题。

1. 只配 liveness,不配 readiness

结果往往是容器刚启动就被 Service 转发流量,导致请求失败。正确做法是优先保证 readiness 正确。

2. requests 设置不合理

如果 requests 太低,HPA 会频繁触发;如果太高,会降低节点利用率,甚至造成调度失败。

3. 把配置写死在镜像里

这样 dev、staging、prod 三个环境就必须构建三次镜像,成本高且容易出错。更合理的方式是镜像统一、配置外置。

4. 发布策略过于激进

例如 maxUnavailable 设置过大,可能导致更新时可用实例骤降。对线上业务来说,应该优先保证平滑发布。

5. 忽略启动慢场景

即使 Go 服务本身很轻,也可能因为预热、连接建立、依赖检查而延迟可用,因此 Startup Probe 在很多场景下是有必要的。

十一、总结

Kubernetes 部署 Go 应用时,真正需要掌握的并不只是“会写一个 Deployment”,而是整套部署模型的协同关系:

  • 用 Pod 承载实例
  • 用 Deployment 管理副本和发布
  • 用 Service 提供稳定访问入口
  • 用 ConfigMap 和 Secret 管理配置
  • 用 resources 和 HPA 控制资源与弹性
  • 用三类 Probe 保证稳定接流量与故障恢复
  • 用 Kustomize 管理多环境差异

当这些要素组合在一起后,你的 Go 服务才真正具备了云原生部署能力:可发布、可扩展、可观测、可回滚、可治理。

如果你正在推进 Go 服务上云或容器化改造,建议直接把本文里的结构作为模板,先搭出一条完整链路,再结合业务特性逐步细化探针、资源和弹性策略。


📝 版权声明:本文为原创技术博客,转载请注明出处。

如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!

上一篇

Golang横向:01 Docker 容器化最佳实践

下一篇

Golang横向:03 Helm Chart编写与管理