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/6782

(0)
Walker的頭像Walker
上一篇 10小時前
下一篇 1天前

相關推薦

  • Go工程師體系課 010

    es 安裝 elasticsearch(理解為庫) kibana(理解為連接工具)es 和 kibana(5601) 的版本要保持一致 MySQL 對照學習 Elasticsearch(ES) 術語對照 MySQL Elasticsearch database index(索引) table type(7.x 起固定為 _doc,8.x 徹底移除多 type…

    後端開發 3小時前
    000
  • Go資深工程師講解(慕課) 006_函數式編程

    Go 函數式編程 對應視頻 Ch6(6-2 函數式編程例一),在 002.md 基礎上擴展更多函數式編程模式 1. 回顧:Go 中函數是一等公民 Go 不是純函數式語言,但函數可以作為:- 變量- 參數- 返回值- 存放在數據結構中 // 函數作為變量 var add = func(a, b int) int { return a + b } // 函數作為…

    後端開發 22小時前
    000
  • Go工程師體系課 018

    API 網關與持續部署入門(Kong & Jenkins) 對應資料目錄《第 2 章 Jenkins 入門》《第 3 章 通過 Jenkins 部署服務》,整理 Kong 與 Jenkins 在企業級持續交付中的實戰路徑。即便零基礎,也能順著步驟搭建出自己的網關 + 持續部署流水線。 課前導覽:甚麼是 API 網關 API 網關位於客戶端與後端微服務…

  • Go工程師體系課 007

    商品微服務 實體結構說明 本模塊包含以下核心實體: 商品(Goods) 商品分類(Category) 品牌(Brands) 輪播圖(Banner) 品牌分類(GoodsCategoryBrand) 1. 商品(Goods) 描述平台中實際展示和銷售的商品信息。 字段說明 字段名 類型 說明 name String 商品名稱,必填 brand Pointer …

  • 編程基礎 0005_錯誤處理進階

    Go 錯誤處理進階 目錄 Go 錯誤處理哲學 error 接口本質 自定義錯誤類型 fmt.Errorf 與 %w 包裝錯誤 errors.Is 和 errors.As 哨兵錯誤模式 錯誤處理最佳實踐 實際項目中的錯誤處理模式 1. Go 錯誤處理哲學 1.1 與 try-catch 的根本區別 在 Java、Python、C++ 等語言中,異常處理依賴 t…

    後端開發 14小時前
    700
簡體中文 繁體中文 English