← 返回
后端开发 2026.03.07

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 容器化