Go工程师体系课 016

Table of Contents

Kubernetes 入门 —— Go 微服务部署与编排


一、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 云厂商负载均衡器 外部访问(云环境)
ExternalName DNS 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, Secret v1
Deployment, StatefulSet, DaemonSet apps/v1
Ingress networking.k8s.io/v1
HPA autoscaling/v2
CronJob, Job batch/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 Compose Kubernetes
定位 单机多容器编排 集群级容器编排
规模 单台主机 数十到数千台主机
高可用 不支持 内置(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 对比

特性 Minikube Kind
实现方式 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 常用工具推荐

工具 用途 安装方式
kubectl K8s 命令行 brew install kubectl
minikube 本地集群 brew install minikube
kind 轻量本地集群 brew install kind
helm K8s 包管理器 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 容器化

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/6763

(0)
Walker的头像Walker
上一篇 3小时前
下一篇 5小时前

相关推荐

  • Go工程师体系课 019

    Go 内存模型与 GC 1. 内存分配基础 1.1 栈(Stack)与堆(Heap) ┌─────────────────────────────┐ │ 堆 (Heap) │ ← 动态分配,GC 管理 │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │ obj │ │ obj │ │ obj │ │ │ └─────┘ └─────┘ └────…

    后端开发 1小时前
    000
  • Go工程师体系课 006

    项目结构说明:user-web 模块 user-web 是 joyshop_api 工程中的用户服务 Web 层模块,负责处理用户相关的 HTTP 请求、参数校验、业务路由以及调用后端接口等功能。以下是目录结构说明: user-web/ ├── api/ # 控制器层,定义业务接口处理逻辑 ├── config/ # 配置模块,包含系统配置结构体及读取逻辑 …

    后端开发 14小时前
    400
  • Go工程师体系课 020

    性能优化与 pprof 1. 先测量后优化 "Premature optimization is the root of all evil." — Donald Knuth 优化流程:1. 先写正确的代码2. 用 Benchmark 确认性能瓶颈3. 用 pprof 定位具体位置4. 优化 → 再测量 → 对比 2. pprof 工具 2.1 在 HTTP …

  • Go工程师体系课 008

    订单及购物车 先从库存服务中将 srv 的服务代码框架复制过来,查找替换对应的名称(order_srv) 加密技术基础 对称加密(Symmetric Encryption) 原理: 使用同一个密钥进行加密和解密 就像一把钥匙,既能锁门也能开门 加密速度快,适合大量数据传输 使用场景: 本地文件加密 数据库内容加密 大量数据传输时的内容加密 内部系统间的快速通…

    后端开发 12小时前
    400
  • Go工程师体系课 011

    查询的倒排索引 1. 什么是倒排索引? 倒排索引(Inverted Index)是一种数据结构,用于快速查找包含特定词汇的文档。它是搜索引擎的核心技术之一。 1.1 基本概念 正排索引:文档 ID → 文档内容(词列表) 倒排索引:词 → 包含该词的文档 ID 列表 1.2 为什么叫"倒排"? 倒排索引将传统的"文档包含哪些词"的关系倒转为"词出现在哪些文档…

    后端开发 9小时前
    400
简体中文 繁体中文 English