← 返回
后端开发 2026.03.05

Go工程师体系课 016

后端开发

一、Kubernetes 核心概念

1.1 什么是 Kubernetes

Kubernetes(简称 K8s)是 Google 开源的容器编排平台,用于自动化部署、扩展和管理容器化应用。如果说 Docker 解决了”如何打包和运行单个容器”的问题,那么 K8s 解决的是”如何管理成百上千个容器”的问题。

K8s 的核心能力:

  • 自动调度:根据资源需求自动将容器分配到合适的节点
  • 自愈能力:容器崩溃自动重启,节点故障自动迁移
  • 水平伸缩:根据负载自动增减实例数量
  • 滚动更新:零停机更新应用版本
  • 服务发现与负载均衡:内置 DNS 和服务发现机制
  • 配置管理与密钥管理:统一管理配置和敏感信息

1.2 集群架构

┌─────────────────────────────────────────────────────────────┐
│                    Kubernetes Cluster                        │
│                                                             │
│  ┌─────────────────────────────────────┐                   │
│  │          Control Plane (主节点)      │                   │
│  │                                     │                   │
│  │  ┌────────────┐  ┌──────────────┐  │                   │
│  │  │ API Server │  │  Scheduler   │  │                   │
│  │  └────────────┘  └──────────────┘  │                   │
│  │  ┌────────────┐  ┌──────────────┐  │                   │
│  │  │   etcd     │  │ Controller   │  │                   │
│  │  │ (数据存储)  │  │  Manager     │  │                   │
│  │  └────────────┘  └──────────────┘  │                   │
│  └─────────────────────────────────────┘                   │
│                                                             │
│  ┌──────────────────┐  ┌──────────────────┐               │
│  │   Worker Node 1  │  │   Worker Node 2  │  ...          │
│  │                  │  │                  │               │
│  │  ┌────┐ ┌────┐  │  │  ┌────┐ ┌────┐  │               │
│  │  │Pod │ │Pod │  │  │  │Pod │ │Pod │  │               │
│  │  └────┘ └────┘  │  │  └────┘ └────┘  │               │
│  │                  │  │                  │               │
│  │  ┌──────────┐   │  │  ┌──────────┐   │               │
│  │  │ kubelet  │   │  │  │ kubelet  │   │               │
│  │  └──────────┘   │  │  └──────────┘   │               │
│  │  ┌──────────┐   │  │  ┌──────────┐   │               │
│  │  │kube-proxy│   │  │  │kube-proxy│   │               │
│  │  └──────────┘   │  │  └──────────┘   │               │
│  └──────────────────┘  └──────────────────┘               │
└─────────────────────────────────────────────────────────────┘

1.3 核心资源对象

Pod —— 最小调度单元

Pod 是 K8s 中最小的可部署单元,一个 Pod 包含一个或多个容器。同一个 Pod 中的容器:

  • 共享网络命名空间(可以通过 localhost 互访)
  • 共享存储卷
  • 共享 IPC 命名空间
  • 被一起调度到同一个节点
# 最简单的 Pod 定义(实际中很少直接创建 Pod)
apiVersion: v1
kind: Pod
metadata:
  name: my-go-app
  labels:
    app: my-go-app
spec:
  containers:
    - name: app
      image: myapp:v1.0
      ports:
        - containerPort: 8080

重要:实际生产中不直接管理 Pod,而是通过 Deployment 来管理。

Node —— 工作节点

Node 是集群中的一台机器(物理机或虚拟机),每个 Node 上运行:

  • kubelet:负责管理该节点上的 Pod 生命周期
  • kube-proxy:负责网络代理和负载均衡
  • 容器运行时:如 containerd、CRI-O(Docker 已在新版本中移除)

Cluster —— 集群

由一个或多个 Control Plane 节点和多个 Worker Node 组成的整体。

Deployment —— 部署控制器

Deployment 是最常用的工作负载控制器,管理 Pod 的副本数、滚动更新和回滚:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-go-app
spec:
  replicas: 3              # 期望的 Pod 副本数
  selector:
    matchLabels:
      app: my-go-app       # 选择管理哪些 Pod
  template:                 # Pod 模板
    metadata:
      labels:
        app: my-go-app
    spec:
      containers:
        - name: app
          image: myapp:v1.0

Service —— 服务发现与负载均衡

Service 为一组 Pod 提供稳定的网络入口和负载均衡:

apiVersion: v1
kind: Service
metadata:
  name: my-go-app-svc
spec:
  selector:
    app: my-go-app         # 选择后端 Pod
  ports:
    - port: 80             # Service 端口
      targetPort: 8080     # 容器端口
  type: ClusterIP          # 服务类型

Service 类型说明:

类型说明访问范围
ClusterIP默认类型,集群内部 IP仅集群内部
NodePort在每个节点上开放端口集群外可通过节点IP访问
LoadBalancer云厂商负载均衡器外部访问(云环境)
ExternalNameDNS CNAME 映射访问外部服务

Ingress —— 外部访问入口

Ingress 提供 HTTP/HTTPS 路由,将外部请求转发到不同的 Service:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /users
            pathType: Prefix
            backend:
              service:
                name: user-service
                port:
                  number: 80
          - path: /orders
            pathType: Prefix
            backend:
              service:
                name: order-service
                port:
                  number: 80
  tls:
    - hosts:
        - api.example.com
      secretName: tls-secret

ConfigMap —— 配置管理

将配置信息与容器镜像解耦:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  # 简单键值对
  LOG_LEVEL: "info"
  DB_HOST: "mysql-svc"
  DB_PORT: "3306"
  # 配置文件
  config.yaml: |
    server:
      port: 8080
      mode: production
    database:
      max_open_conns: 100
      max_idle_conns: 10

Secret —— 敏感信息管理

存储密码、Token、证书等敏感数据(Base64 编码存储):

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
data:
  # 值需要 Base64 编码: echo -n "mypassword" | base64
  DB_PASSWORD: bXlwYXNzd29yZA==
  REDIS_PASSWORD: cmVkaXNwYXNz
  JWT_SECRET: c3VwZXJzZWNyZXRrZXk=

注意:K8s Secret 的 Base64 编码并不是加密,生产环境建议使用 Vault 或 Sealed Secrets 等方案加强安全性。

Namespace —— 命名空间

用于将集群资源逻辑隔离,适用于多团队或多环境场景:

# 常见的命名空间划分
kubectl create namespace development
kubectl create namespace staging
kubectl create namespace production

# 查看所有命名空间
kubectl get namespaces

二、常用 kubectl 命令

2.1 集群与上下文管理

# 查看集群信息
kubectl cluster-info

# 查看当前上下文
kubectl config current-context

# 切换上下文(多集群管理)
kubectl config use-context my-cluster

# 设置默认命名空间
kubectl config set-context --current --namespace=production

2.2 资源查看

# 查看资源(通用格式)
kubectl get <resource-type> [-n namespace]

# 常用查看命令
kubectl get pods                       # 查看当前命名空间的 Pod
kubectl get pods -A                    # 查看所有命名空间的 Pod
kubectl get pods -o wide               # 显示更多信息(IP、节点等)
kubectl get pods -l app=my-go-app      # 按标签筛选
kubectl get deployments                # 查看 Deployment
kubectl get services                   # 查看 Service
kubectl get ingress                    # 查看 Ingress
kubectl get configmaps                 # 查看 ConfigMap
kubectl get secrets                    # 查看 Secret
kubectl get nodes                      # 查看节点
kubectl get all                        # 查看所有资源

# 详细信息
kubectl describe pod my-go-app-xxx     # 查看 Pod 详情(含事件日志)
kubectl describe deployment my-go-app  # 查看 Deployment 详情

# 输出格式
kubectl get pods -o yaml               # YAML 格式
kubectl get pods -o json               # JSON 格式
kubectl get pods -o jsonpath='{.items[*].metadata.name}'  # 自定义输出

2.3 资源操作

# 创建/更新资源
kubectl apply -f deployment.yaml       # 声明式(推荐)
kubectl create -f deployment.yaml      # 命令式

# 删除资源
kubectl delete -f deployment.yaml      # 删除 YAML 中定义的资源
kubectl delete pod my-go-app-xxx       # 删除指定 Pod
kubectl delete deployment my-go-app    # 删除 Deployment

# 编辑资源(在线编辑)
kubectl edit deployment my-go-app

# 快速创建(无需 YAML 文件)
kubectl create deployment my-app --image=myapp:v1.0
kubectl expose deployment my-app --port=80 --target-port=8080

2.4 调试排查

# 查看 Pod 日志
kubectl logs my-go-app-xxx             # 当前日志
kubectl logs -f my-go-app-xxx          # 实时跟踪
kubectl logs my-go-app-xxx -c app      # 指定容器(多容器 Pod)
kubectl logs my-go-app-xxx --previous  # 上一次崩溃的日志

# 进入 Pod 容器
kubectl exec -it my-go-app-xxx -- sh
kubectl exec -it my-go-app-xxx -c app -- sh  # 指定容器

# 端口转发(本地调试)
kubectl port-forward pod/my-go-app-xxx 8080:8080
kubectl port-forward svc/my-go-app-svc 8080:80

# 查看事件(排查问题的重要手段)
kubectl get events --sort-by='.lastTimestamp'
kubectl get events -n production

# 资源使用情况(需要 metrics-server)
kubectl top pods
kubectl top nodes

三、YAML 资源配置文件详解

3.1 YAML 基本结构

每个 K8s 资源的 YAML 文件都包含四个核心部分:

apiVersion: apps/v1       # API 版本 —— 决定可用的字段
kind: Deployment          # 资源类型 —— Pod/Service/Deployment 等
metadata:                 # 元数据 —— 名称、标签、注解等
  name: my-app
  namespace: production
  labels:
    app: my-app
    env: production
  annotations:
    description: "My Go Application"
spec:                     # 规格 —— 资源的期望状态(最核心的部分)
  replicas: 3
  # ...

3.2 常用 apiVersion 对照

资源类型apiVersion
Pod, Service, ConfigMap, Secretv1
Deployment, StatefulSet, DaemonSetapps/v1
Ingressnetworking.k8s.io/v1
HPAautoscaling/v2
CronJob, Jobbatch/v1

3.3 标签(Labels)与选择器(Selectors)

标签是 K8s 中资源关联的核心机制:

# Deployment 通过 selector 选择管理哪些 Pod
# Service 通过 selector 选择后端 Pod
# 两者的 selector 必须与 Pod 的 labels 匹配

# Deployment
spec:
  selector:
    matchLabels:
      app: my-go-app      # 必须与 template.labels 匹配
  template:
    metadata:
      labels:
        app: my-go-app     # Pod 的标签

# Service
spec:
  selector:
    app: my-go-app         # 匹配 Pod 的标签

四、部署 Go 微服务到 K8s(完整 YAML 示例)

4.1 完整的部署方案

以一个 Go Web 服务为例,提供完整的 K8s 部署配置。

文件结构

k8s/
├── namespace.yaml
├── configmap.yaml
├── secret.yaml
├── deployment.yaml
├── service.yaml
├── ingress.yaml
└── hpa.yaml

namespace.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: go-app
  labels:
    name: go-app

configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: go-app-config
  namespace: go-app
data:
  LOG_LEVEL: "info"
  GIN_MODE: "release"
  DB_HOST: "mysql-svc"
  DB_PORT: "3306"
  DB_NAME: "myapp"
  REDIS_ADDR: "redis-svc:6379"
  CONSUL_ADDR: "consul-svc:8500"
  config.yaml: |
    server:
      port: 8080
      read_timeout: 10s
      write_timeout: 10s
    log:
      level: info
      format: json

secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: go-app-secret
  namespace: go-app
type: Opaque
data:
  DB_PASSWORD: cm9vdHBhc3N3b3Jk          # rootpassword
  REDIS_PASSWORD: cmVkaXNwYXNzd29yZA==    # redispassword
  JWT_SECRET: bXktand0LXNlY3JldC1rZXk=   # my-jwt-secret-key

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-app
  namespace: go-app
  labels:
    app: go-app
    version: v1.0.0
spec:
  replicas: 3
  selector:
    matchLabels:
      app: go-app
  # 滚动更新策略
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1           # 滚动更新时最多超出期望副本数 1 个
      maxUnavailable: 0     # 更新过程中不允许有不可用的 Pod
  template:
    metadata:
      labels:
        app: go-app
        version: v1.0.0
    spec:
      # 优雅终止等待时间
      terminationGracePeriodSeconds: 30

      # 初始化容器(可选 —— 等待依赖服务就绪)
      initContainers:
        - name: wait-for-mysql
          image: busybox:1.36
          command:
            - sh
            - -c
            - |
              until nc -z mysql-svc 3306; do
                echo "Waiting for MySQL..."
                sleep 2
              done

      containers:
        - name: app
          image: registry.example.com/myns/go-app:v1.0.0
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP

          # 从 ConfigMap 注入环境变量
          envFrom:
            - configMapRef:
                name: go-app-config

          # 从 Secret 注入敏感环境变量
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: go-app-secret
                  key: DB_PASSWORD
            - name: REDIS_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: go-app-secret
                  key: REDIS_PASSWORD
            - name: JWT_SECRET
              valueFrom:
                secretKeyRef:
                  name: go-app-secret
                  key: JWT_SECRET

          # 挂载配置文件
          volumeMounts:
            - name: config-volume
              mountPath: /app/config
              readOnly: true

          # 资源限制
          resources:
            requests:
              cpu: 100m          # 最低保证 0.1 核 CPU
              memory: 128Mi      # 最低保证 128MB 内存
            limits:
              cpu: 500m          # 最多使用 0.5 核 CPU
              memory: 256Mi      # 最多使用 256MB 内存

          # 存活探针 —— 检测容器是否需要重启
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 10    # 容器启动后等待 10 秒
            periodSeconds: 15          # 每 15 秒检查一次
            timeoutSeconds: 3          # 超时 3 秒视为失败
            failureThreshold: 3        # 连续 3 次失败则重启

          # 就绪探针 —— 检测容器是否可以接收流量
          readinessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 3

          # 启动探针 —— 保护慢启动的应用
          startupProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 0
            periodSeconds: 5
            failureThreshold: 30       # 最多等待 150 秒启动

      volumes:
        - name: config-volume
          configMap:
            name: go-app-config
            items:
              - key: config.yaml
                path: config.yaml

      # 拉取私有镜像的凭证
      imagePullSecrets:
        - name: registry-credentials

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: go-app-svc
  namespace: go-app
  labels:
    app: go-app
spec:
  selector:
    app: go-app
  ports:
    - name: http
      port: 80               # Service 暴露的端口
      targetPort: 8080        # 转发到容器的端口
      protocol: TCP
  type: ClusterIP

ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: go-app-ingress
  namespace: go-app
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
    # 限流
    nginx.ingress.kubernetes.io/limit-rps: "100"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - api.example.com
      secretName: tls-secret
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: go-app-svc
                port:
                  number: 80

4.2 一键部署

# 按顺序部署所有资源
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/ingress.yaml

# 或者一次性部署整个目录
kubectl apply -f k8s/

# 查看部署状态
kubectl get all -n go-app
kubectl rollout status deployment/go-app -n go-app

五、健康检查(Liveness / Readiness Probe)

5.1 三种探针的作用

探针作用失败后果
livenessProbe检测容器是否存活重启容器
readinessProbe检测容器是否就绪从 Service 端点移除,不再接收流量
startupProbe检测容器是否启动完成启动阶段不会被 liveness 杀死

5.2 探针类型

# 1. HTTP GET 探针(最常用)
livenessProbe:
  httpGet:
    path: /health
    port: 8080
    httpHeaders:
      - name: X-Custom-Header
        value: "probe"

# 2. TCP Socket 探针(适合非 HTTP 服务)
livenessProbe:
  tcpSocket:
    port: 8080

# 3. Exec 命令探针(自定义检测逻辑)
livenessProbe:
  exec:
    command:
      - /bin/sh
      - -c
      - "wget -q --spider http://localhost:8080/health"

# 4. gRPC 探针(K8s 1.24+)
livenessProbe:
  grpc:
    port: 50051

5.3 Go 中实现健康检查端点

package main

import (
    "database/sql"
    "encoding/json"
    "net/http"
    "sync/atomic"
)

// 全局就绪状态标志
var isReady atomic.Bool

type HealthResponse struct {
    Status   string            `json:"status"`
    Details  map[string]string `json:"details,omitempty"`
}

func healthHandler(db *sql.DB, redisClient RedisClient) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        resp := HealthResponse{
            Status:  "ok",
            Details: make(map[string]string),
        }
        statusCode := http.StatusOK

        // 检查数据库连接
        if err := db.Ping(); err != nil {
            resp.Status = "degraded"
            resp.Details["mysql"] = "unhealthy: " + err.Error()
            statusCode = http.StatusServiceUnavailable
        } else {
            resp.Details["mysql"] = "healthy"
        }

        // 检查 Redis 连接
        if err := redisClient.Ping(r.Context()).Err(); err != nil {
            resp.Status = "degraded"
            resp.Details["redis"] = "unhealthy: " + err.Error()
            statusCode = http.StatusServiceUnavailable
        } else {
            resp.Details["redis"] = "healthy"
        }

        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(statusCode)
        json.NewEncoder(w).Encode(resp)
    }
}

// readinessHandler 就绪检查 —— 服务是否可以接收流量
func readinessHandler() http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if !isReady.Load() {
            http.Error(w, "not ready", http.StatusServiceUnavailable)
            return
        }
        w.WriteHeader(http.StatusOK)
        w.Write([]byte("ready"))
    }
}

func main() {
    // 初始化数据库、Redis 等...
    // db, redisClient := initDeps()

    mux := http.NewServeMux()

    // liveness 探针 —— 简单返回 200 即可
    mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
    })

    // readiness 探针 —— 检查依赖服务
    mux.HandleFunc("/readyz", readinessHandler())

    // 详细健康信息(内部使用)
    // mux.HandleFunc("/health", healthHandler(db, redisClient))

    // 完成初始化后标记为就绪
    isReady.Store(true)

    http.ListenAndServe(":8080", mux)
}

对应的 K8s 配置:

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 15

readinessProbe:
  httpGet:
    path: /readyz
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 10

六、水平自动伸缩 HPA

6.1 HPA 工作原理

HPA(Horizontal Pod Autoscaler)根据 Pod 的 CPU/内存使用率或自定义指标自动调整副本数:

                    ┌─────────┐
  监控指标 ────────▶│   HPA   │
  (CPU/内存/自定义)  │ 控制器   │
                    └────┬────┘
                         │ 调整 replicas

                    ┌─────────┐
                    │Deployment│
                    └────┬────┘

              ┌──────────┼──────────┐
              ▼          ▼          ▼
           ┌─────┐   ┌─────┐   ┌─────┐
           │Pod 1│   │Pod 2│   │Pod 3│  ← 自动扩缩
           └─────┘   └─────┘   └─────┘

6.2 前提条件

HPA 需要 metrics-server 来获取资源使用数据:

# 安装 metrics-server(Minikube 自带,云环境通常已安装)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# 验证
kubectl top pods
kubectl top nodes

6.3 HPA 配置

# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: go-app-hpa
  namespace: go-app
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: go-app
  minReplicas: 2            # 最少 2 个副本
  maxReplicas: 10           # 最多 10 个副本
  metrics:
    # 基于 CPU 使用率
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70    # CPU 使用率超过 70% 时扩容
    # 基于内存使用率
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80    # 内存使用率超过 80% 时扩容
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60    # 扩容冷却时间
      policies:
        - type: Pods
          value: 2                      # 每次最多扩 2 个 Pod
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300   # 缩容冷却时间(5 分钟)
      policies:
        - type: Percent
          value: 25                     # 每次最多缩容 25%
          periodSeconds: 60
# 命令行创建简单 HPA
kubectl autoscale deployment go-app \
  --min=2 --max=10 --cpu-percent=70 \
  -n go-app

# 查看 HPA 状态
kubectl get hpa -n go-app
kubectl describe hpa go-app-hpa -n go-app

# 压测观察自动伸缩(使用 hey 或 wrk 等工具)
hey -n 10000 -c 100 http://api.example.com/

七、滚动更新与回滚

7.1 滚动更新策略

在 Deployment 的 strategy 字段中配置:

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1           # 更新时最多多出 1 个 Pod
      maxUnavailable: 0     # 更新时不允许不可用的 Pod(零停机)

更新过程示意(3 副本,maxSurge=1,maxUnavailable=0):

初始状态:   [v1] [v1] [v1]           总数=3, 可用=3
步骤 1:     [v1] [v1] [v1] [v2]     创建新版 Pod   总数=4, 可用=3
步骤 2:     [v1] [v1]      [v2]     新 Pod 就绪后终止旧 Pod  总数=3, 可用=3
步骤 3:     [v1] [v1]      [v2] [v2]  总数=4, 可用=3
步骤 4:     [v1]           [v2] [v2]  总数=3, 可用=3
步骤 5:     [v1]           [v2] [v2] [v2]  总数=4, 可用=3
步骤 6:                    [v2] [v2] [v2]  完成!总数=3, 可用=3

7.2 触发更新

# 方式 1: 更新镜像版本
kubectl set image deployment/go-app app=myapp:v2.0 -n go-app

# 方式 2: 修改 YAML 后 apply
kubectl apply -f k8s/deployment.yaml

# 方式 3: 使用 patch
kubectl patch deployment go-app -n go-app \
  -p '{"spec":{"template":{"spec":{"containers":[{"name":"app","image":"myapp:v2.0"}]}}}}'

# 查看更新状态
kubectl rollout status deployment/go-app -n go-app

# 查看更新历史
kubectl rollout history deployment/go-app -n go-app
kubectl rollout history deployment/go-app -n go-app --revision=2

7.3 回滚

# 回滚到上一个版本
kubectl rollout undo deployment/go-app -n go-app

# 回滚到指定版本
kubectl rollout undo deployment/go-app -n go-app --to-revision=1

# 暂停更新(用于金丝雀发布场景)
kubectl rollout pause deployment/go-app -n go-app

# 恢复更新
kubectl rollout resume deployment/go-app -n go-app

7.4 Go 应用的优雅关闭

为了让滚动更新实现真正的零停机,Go 应用需要正确处理 SIGTERM 信号:

package main

import (
    "context"
    "log"
    "net/http"
    "os"
    "os/signal"
    "syscall"
    "time"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, K8s!"))
    })
    mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
    })

    server := &http.Server{
        Addr:         ":8080",
        Handler:      mux,
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
    }

    // 在 goroutine 中启动服务器
    go func() {
        log.Println("Server starting on :8080")
        if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("Server error: %v", err)
        }
    }()

    // 等待终止信号
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    sig := <-quit
    log.Printf("Received signal: %v, shutting down gracefully...", sig)

    // 给正在处理的请求一个完成的窗口期
    ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
    defer cancel()

    if err := server.Shutdown(ctx); err != nil {
        log.Fatalf("Server forced to shutdown: %v", err)
    }

    log.Println("Server exited gracefully")
}

对应的 Deployment 配置中设置优雅终止等待时间:

spec:
  template:
    spec:
      terminationGracePeriodSeconds: 30   # 给 Pod 30 秒时间优雅退出

八、K8s 与 Docker Compose 的区别和关系

8.1 定位不同

维度Docker ComposeKubernetes
定位单机多容器编排集群级容器编排
规模单台主机数十到数千台主机
高可用不支持内置(Pod 自动重启/迁移)
自动伸缩不支持内置 HPA/VPA
滚动更新有限支持完善的滚动更新和回滚
服务发现通过容器名 DNS内置 Service 和 DNS
负载均衡基本的 round-robin多种策略,支持 Ingress
配置管理环境变量、文件挂载ConfigMap、Secret
学习曲线
适用场景本地开发、小型项目生产环境、大型项目

8.2 从 Docker Compose 到 K8s 的映射

Docker Compose               Kubernetes
──────────────               ──────────
docker-compose.yml    →    多个 YAML 文件(或 Helm Chart)
service (定义)         →    Deployment + Service
ports                  →    Service(NodePort/LoadBalancer) + Ingress
environment            →    ConfigMap + Secret
volumes                →    PersistentVolumeClaim (PVC)
depends_on             →    initContainers / 就绪探针
build                  →    CI/CD 流水线预先构建镜像
networks               →    Namespace + NetworkPolicy
restart: always        →    Pod restartPolicy + Deployment 控制器

8.3 迁移路径

推荐的学习和迁移路径:

1. 本地开发     → Docker Compose
2. 测试环境     → Docker Compose 或 Minikube
3. 预发布环境   → K8s(可以用 Kind 或云厂商托管 K8s)
4. 生产环境     → K8s(推荐使用托管服务:AKS/EKS/GKE/ACK)

8.4 Kompose —— 快速转换工具

可以使用 kompose 工具将 docker-compose.yml 转换为 K8s YAML:

# 安装 kompose
brew install kompose         # macOS
# 或者下载二进制文件

# 将 docker-compose.yml 转换为 K8s 资源文件
kompose convert
# 会生成 deployment.yaml、service.yaml 等文件

# 直接部署
kompose up

# 注意:kompose 生成的文件通常需要手动调整优化

九、本地开发环境

9.1 Minikube

Minikube 是最流行的本地 K8s 工具,在本机创建一个单节点集群:

# 安装(macOS)
brew install minikube

# 启动集群
minikube start
minikube start --cpus=4 --memory=8192 --driver=docker

# 查看状态
minikube status

# 常用附加组件
minikube addons enable ingress           # Nginx Ingress
minikube addons enable metrics-server    # 资源监控
minikube addons enable dashboard         # Web 管理界面

# 打开 Dashboard
minikube dashboard

# 使用 Minikube 内置的 Docker(避免推送到远程仓库)
eval $(minikube docker-env)
docker build -t myapp:v1.0 .            # 直接构建到 Minikube 的 Docker 中
# Deployment 中设置 imagePullPolicy: Never

# 访问 Service
minikube service go-app-svc -n go-app    # 自动打开浏览器
minikube tunnel                          # 启用 LoadBalancer 支持

# 停止/删除
minikube stop
minikube delete

9.2 Kind(Kubernetes in Docker)

Kind 使用 Docker 容器模拟 K8s 节点,更轻量,适合 CI/CD 环境:

# 安装(macOS)
brew install kind

# 创建集群(默认单节点)
kind create cluster --name my-cluster

# 创建多节点集群
cat <<EOF | kind create cluster --name multi-node --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
  - role: worker
  - role: worker
EOF

# 将本地镜像加载到 Kind 集群(不需要推送到仓库)
kind load docker-image myapp:v1.0 --name my-cluster

# 查看集群
kind get clusters
kubectl cluster-info --context kind-my-cluster

# 删除集群
kind delete cluster --name my-cluster

9.3 Minikube vs Kind 对比

特性MinikubeKind
实现方式VM 或 Docker 容器Docker 容器
多节点支持有限原生支持
启动速度较慢(30-60s)快(20-30s)
资源占用较高较低
内置插件丰富(dashboard等)较少
CI/CD 适用性一般非常好
学习友好度高(有 dashboard)
推荐场景本地开发和学习CI/CD 和测试

9.4 完整的本地开发工作流

# 1. 启动本地 K8s 集群
minikube start --cpus=4 --memory=8192
minikube addons enable ingress
minikube addons enable metrics-server

# 2. 使用 Minikube 的 Docker 环境构建镜像
eval $(minikube docker-env)
docker build -t go-app:dev .

# 3. 部署应用(imagePullPolicy 设为 Never)
kubectl apply -f k8s/

# 4. 查看状态
kubectl get all -n go-app

# 5. 访问应用
minikube service go-app-svc -n go-app
# 或者
kubectl port-forward svc/go-app-svc 8080:80 -n go-app

# 6. 查看日志
kubectl logs -f -l app=go-app -n go-app

# 7. 修改代码后重新构建部署
docker build -t go-app:dev .
kubectl rollout restart deployment/go-app -n go-app

# 8. 开发完成,清理环境
kubectl delete -f k8s/
minikube stop

十、总结与学习路径

10.1 核心知识点回顾

K8s 核心概念
├── 调度单元:Pod
├── 工作负载:Deployment / StatefulSet / DaemonSet
├── 服务发现:Service / Ingress
├── 配置管理:ConfigMap / Secret
├── 存储:PersistentVolume / PVC
├── 自动伸缩:HPA / VPA
├── 隔离:Namespace / NetworkPolicy
└── 更新策略:RollingUpdate / Recreate

10.2 推荐学习路径

第一阶段(入门):
  Docker 基础 → Dockerfile → docker-compose → 本章内容

第二阶段(进阶):
  Helm Chart 包管理 → K8s 存储 (PV/PVC) → StatefulSet (有状态服务)
  → RBAC 权限管理 → NetworkPolicy 网络策略

第三阶段(生产实践):
  CI/CD 流水线 (GitLab CI / GitHub Actions / ArgoCD)
  → 监控告警 (Prometheus + Grafana)
  → 日志收集 (EFK/ELK Stack)
  → 服务网格 (Istio / Linkerd)

第四阶段(运维深入):
  集群管理与运维 → 安全加固 → 多集群管理
  → 自定义 Controller / Operator

10.3 常用工具推荐

工具用途安装方式
kubectlK8s 命令行brew install kubectl
minikube本地集群brew install minikube
kind轻量本地集群brew install kind
helmK8s 包管理器brew install helm
k9s终端 UI 管理工具brew install k9s
lens桌面 GUI 管理工具官网下载
kubectx/kubens快速切换上下文/命名空间brew install kubectx
stern多 Pod 日志聚合brew install stern
skaffold开发工作流自动化brew install skaffold

上一篇015 - Docker 容器化