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