云原生从0到1:Kubernetes 工作负载实战——Deployment/Service/滚动更新/弹性伸缩

《云原生从0到1:Kubernetes 工作负载实战------Deployment/Service/滚动更新/弹性伸缩》

作者:云原生学习者 | 系列:云原生工程师实战之路

一句话导读:集群搭好了(见系列前两篇),本篇开始"用起来":以一个 Go 编写的 HTTP 微服务为例,走一遍 Deployment 部署 → Service 暴露 → 滚动更新 → 水平伸缩 → 故障自愈的完整链路,带你建立对 K8s 工作负载的直观认识。


0. 实验环境回顾

集群 1 Master + 3 Worker(K8s v1.28.2)
运行时 containerd 2.2.1
CNI Calico(Pod 网段 10.244.0.0/16)
示例应用 go-demo(Go 编写的 JSON 接口服务)

1. 编写 Go 微服务

一个返回服务实例信息的 HTTP 服务,用于直观展示"请求打到了哪个 Pod":

go 复制代码
package main

import (
	"encoding/json"
	"log"
	"net/http"
	"os"
	"time"
)

type Info struct {
	Service  string `json:"service"`
	Version  string `json:"version"`
	Hostname string `json:"hostname"`
	PodIP    string `json:"pod_ip"`
	Time     string `json:"time"`
}

var version = "v1.0.0"

func infoHandler(w http.ResponseWriter, r *http.Request) {
	hostname, _ := os.Hostname()
	podIP := os.Getenv("POD_IP")
	if podIP == "" {
		podIP = r.RemoteAddr
	}
	json.NewEncoder(w).Encode(Info{
		Service: "go-demo", Version: version,
		Hostname: hostname, PodIP: podIP,
		Time: time.Now().Format("2006-01-02 15:04:05"),
	})
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", infoHandler)
	log.Fatal(http.ListenAndServe(":8080", mux))
}

多阶段构建 Dockerfile(builder 阶段编译 + 运行阶段仅保留二进制,镜像极小):

dockerfile 复制代码
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY main.go .
RUN go mod init go-demo && go build -ldflags="-s -w" -o go-demo .

FROM alpine:3.19
WORKDIR /root/
COPY --from=builder /app/go-demo .
EXPOSE 8080
CMD ["./go-demo"]

2. Deployment:声明式管理应用

Deployment 是 K8s 中最常用的工作负载控制器,负责:副本数保证、滚动更新、故障自愈、回滚

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-demo
  labels:
    app: go-demo
spec:
  replicas: 3                    # 期望副本数
  selector:
    matchLabels:
      app: go-demo
  template:
    metadata:
      labels:
        app: go-demo
    spec:
      containers:
      - name: go-demo
        image: go-demo:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        env:
        - name: POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP   # Downward API:把 Pod IP 注入环境变量
        resources:
          requests:                    # 资源请求(调度依据)
            cpu: 100m
            memory: 128Mi
          limits:                      # 资源上限(限制使用)
            cpu: 500m
            memory: 256Mi
        readinessProbe:                # 就绪探针:通过才加入 Service 转发
          httpGet:
            path: /
            port: 8080
          initialDelaySeconds: 3
          periodSeconds: 5

关键点解读:

  1. selector.matchLabels 必须与 template 的 labels 匹配,Deployment 通过它管理 Pod;
  2. readinessProbe:Pod 就绪才接收流量,滚动更新时保证不中断服务;
  3. resources:requests 决定调度到哪个节点,limits 限制资源使用。

3. Service:稳定的访问入口

Pod 的 IP 会随重建而变化,Service 提供稳定的虚拟 IP(ClusterIP)+ DNS 名称

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: go-demo
spec:
  selector:
    app: go-demo          # 关联上面 Deployment 管理的 Pod
  ports:
  - port: 80              # Service 端口
    targetPort: 8080      # 转发到 Pod 的端口
  type: ClusterIP

集群内通过 go-demo.default.svc.cluster.localgo-demo 访问,Service 自动负载均衡到 3 个 Pod。


4. 滚动更新实战

修改镜像版本号触发更新:

bash 复制代码
kubectl set image deployment/go-demo go-demo=go-demo:v2.0.0
# 或者声明式更新
kubectl rollout status deployment/go-demo

滚动更新过程(ReplicaSet 交替扩容/缩容,全程零停机):

text 复制代码
Waiting for deployment "go-demo" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "go-demo" rollout to finish: 2 out of 3 new replicas have been updated...
deployment "go-demo" successfully rolled out

回滚

bash 复制代码
kubectl rollout undo deployment/go-demo

5. 水平伸缩(HPA)

根据 CPU 使用率自动扩缩容:

bash 复制代码
kubectl autoscale deployment go-demo --cpu-percent=50 --min=3 --max=10
# 或声明式
kubectl apply -f hpa.yaml
yaml 复制代码
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: go-demo
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: go-demo
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

用压测工具(如 hey)打流量,观察 Pod 自动扩容:

bash 复制代码
kubectl get hpa -w
kubectl get pods -w

6. 故障自愈演示

模拟 Pod 故障,观察 K8s 自动拉起新副本:

bash 复制代码
kubectl delete pod <pod名称>
kubectl get pods -w
# 几秒内,Deployment 会重新创建一个新 Pod,服务不受影响

核心原理:kubelet 上报 Pod 状态 → controller-manager 中的 Deployment controller 发现副本数不足 → 通过 ReplicaSet 创建新 Pod → scheduler 调度到合适节点。这正是课程第 17 周"controller 底层原理"讲的**控制循环(reconcile loop)**思想。


7. 验证 Service 负载均衡

从集群内发起多次请求,观察返回的 hostname 是否在不同 Pod 间轮转:

bash 复制代码
kubectl run curl-test --image=curlimages/curl -it --rm -- \
  sh -c 'for i in $(seq 1 6); do curl -s go-demo | jq -r .hostname; done'

预期:3 个不同 Pod 名轮流出现,证明负载均衡生效。


8. 小结

本篇用一个小微服务完整演示了 K8s 工作负载的核心能力。这张表值得收藏:

能力 对应资源 一句话原理
副本管理 Deployment → ReplicaSet 控制循环保证期望状态
稳定访问 Service (ClusterIP) iptables/IPVS 规则转发
滚动更新 Deployment strategy 新旧 ReplicaSet 交替
自动伸缩 HPA 指标采集 + 期望副本计算
故障自愈 kubelet + controller 状态上报 + 控制循环
配置注入 Downward API / ConfigMap 运行时信息注入

下一篇将分享 Prometheus + Grafana 监控告警体系部署实战,敬请期待!


本文为原创实操记录。欢迎转载,请注明出处。

相关推荐
江华森24 分钟前
《云原生从0到1:4台华为云ECS搭建Kubernetes 1.28集群实录(上)——环境与踩坑全记录》
前端·后端
那咋乎吧25 分钟前
数据包到达网卡后到用户态应用程序的全流程
后端
codeY28 分钟前
Vite 前端发布后「点击菜单没反应」?旧版本资源 404 的完整排查与修复实录
前端·前端工程化
程序猿阿越29 分钟前
kubelet源码阅读
后端·kubernetes·源码阅读
90后的晨仔1 小时前
uni-app Vue3 状态管理 Pinia 完全指南:从概念到实战的深度解析
前端
mqiqe1 小时前
AgentScope Java 2.0 集成 Chat Completions Web:一行依赖让你的 Agent 变身 OpenAI 兼容服务
java·开发语言·前端
程序员小八7771 小时前
后端开发初学TypeScript
前端·javascript·typescript
90后的晨仔1 小时前
Puppeteer 与 Playwright 深度实战指南:从零到精通,全面提升开发效率
前端
sunphp开发者1 小时前
阿里云CDN加速配置问题
前端·阿里云·云计算