前言

单机 Docker 跑十几个容器还行,成百上千个跨几十台机器呢?谁挂了谁来重启?怎么滚动升级不中断服务?Kubernetes(K8s)就是容器世界的"操作系统",负责调度、自愈、扩缩容。

一、为什么需要 K8s

痛点 K8s 的答案
容器挂了没人管 自愈:自动重新拉起(重启/换节点)
手动挑机器部署 调度:按资源请求自动选择节点
发布中断服务 滚动更新:新旧副本渐进切换,随时回滚
流量打到哪个容器 服务发现与负载均衡(Service)
配置改了要重启 配置中心(ConfigMap/Secret 热更新)
高峰扩容、低谷缩容 HPA 自动扩缩容

二、架构:控制面 + 工作节点

┌─────────────── 控制平面 (Control Plane) ───────────────┐
│  API Server ── 唯一入口, 所有增删改查走 REST/kubectl     │
│  etcd ──────── 集群大脑: 存储全部期望状态(键值库)          │
│  Scheduler ─── 决定新 Pod 落在哪个节点                    │
│  Controller ── 控制循环: 不断对齐"期望状态 vs 实际状态"     │
└───────────────────────────────────────────────────────┘
            │ 监听/上报
┌───────────▼─────────────── 工作节点 (Node) ──────────────┐
│  kubelet ──── 节点管家: 管理本节点容器生命周期              │
│  kube-proxy ─ 网络规则: 让 Service 的 VIP 能转发到 Pod    │
│  容器运行时 ── containerd(实际跑容器的进程)               │
└────────────────────────────────────────────────────────┘

核心思想:声明式 API + 控制循环

你只声明"我要 3 个副本的 nginx"(写 YAML),控制器持续对比现状并修复差距——挂一个补一个。这与传统"一步步执行命令"的命令式运维是范式级差异。

kubectl get pods                 # 万物皆可 get
kubectl describe pod xxx         # 排障第一命令
kubectl logs -f xxx              # 看日志
kubectl exec -it xxx -- sh       # 进容器

三、核心对象(由小到大)

Pod:最小调度单元

apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: nginx
    image: nginx:1.25
    resources:
      requests: {cpu: 100m, memory: 128Mi}   # 调度依据
      limits:   {cpu: 500m, memory: 256Mi}   # 上限(超限可能被 OOM 杀)
  • 一个 Pod = 一组同生共死、共享网络/存储的容器(多数 Pod 只有一个主容器)
  • Pod 是易逝的(牛,不是宠物)——IP 会变,所以不能直接对外

Deployment:管理 Pod 的副本与升级

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3                      # 期望副本数
  selector:
    matchLabels: {app: web}
  template:                        # Pod 模板
    metadata:
      labels: {app: web}           # 打标签, selector 靠它认领
    spec:
      containers:
      - name: web
        image: reg.local/myapp:v1.2.0
        ports: [{containerPort: 8080}]
        livenessProbe:              # 存活检查: 失败则重启容器
          httpGet: {path: /healthz, port: 8080}
        readinessProbe:             # 就绪检查: 未就绪不接流量
          httpGet: {path: /ready, port: 8080}

Deployment 能力:副本控制、滚动更新、回滚、暂停发布。

kubectl rollout status deploy/web
kubectl rollout undo deploy/web              # 一键回滚
kubectl scale deploy/web --replicas=5        # 手动扩容
kubectl set image deploy/web web=reg.local/myapp:v1.3.0

Service:稳定的访问入口

Pod IP 随时会变,Service 提供固定虚拟 IP(VIP)+ 域名,把流量负载均衡到后端 Pod:

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector: {app: web}          # 认领带此标签的 Pod
  ports:
  - port: 80                    # Service 端口
    targetPort: 8080            # 转发到容器的端口
三种类型:
ClusterIP   集群内访问(默认): http://web.default.svc.cluster.local
NodePort    每个节点开一个高位端口: 节点IP:30080
LoadBalancer 云厂商分配公网 LB(付费但省心)

Ingress:七层入口(域名/路由/TLS)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blog
spec:
  rules:
  - host: antidebug.cn
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web
            port: {number: 80}

集群只需一个 LoadBalancer 暴露 Ingress Controller,内部靠域名路由到不同 Service。

ConfigMap / Secret:配置与敏感信息

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-conf
data:
  APP_ENV: "production"
  nginx.conf: |
    server { listen 80; }
---
# Secret 同理, 值是 base64(编码≠加密, 生产用外部密钥管理)
apiVersion: v1
kind: Secret
metadata:
  name: db-cred
stringData:
  password: "s3cret"
# 挂进 Pod: 环境变量 或 文件
env:
- name: APP_ENV
  valueFrom: {configMapKeyRef: {name: app-conf, key: APP_ENV}}
volumeMounts: [{name: conf, mountPath: /etc/app}]
volumes:
- name: conf
  configMap: {name: app-conf}

命名空间:逻辑分区

kubectl get ns
kubectl -n prod get pods          # 生产命名空间下的 Pod

按环境或团队划分,配 ResourceQuota 限额。

四、一个应用的完整上云之路

# 1. 镜像先行(上篇的 Dockerfile 产物)
docker build -t reg.local/myapp:v1.0 . && docker push reg.local/myapp:v1.0

# 2. 写 YAML(Deployment + Service + ConfigMap)
kubectl apply -f app.yaml

# 3. 观察
kubectl get pods -w
kubectl rollout status deploy/web

# 4. 升级
kubectl set image deploy/web web=reg.local/myapp:v1.1
kubectl rollout undo deploy/web          # 有问题秒回滚

# 5. 对外暴露
kubectl apply -f ingress.yaml
curl http://antidebug.cn/

五、学习建议

  1. 先用 kind/minikube 起个单机集群练手:kind create cluster
  2. 把上面每个对象各写一遍 YAML,describe 看事件
  3. 别背概念,盯住一条流量路径:Ingress → Service → Pod → 容器端口
  4. 排障三板斧:describe(Events 段)、logs、exec

小结

对象 一句话
Pod 最小调度单元,易逝
Deployment 副本管理 + 滚动升级
Service 稳定 VIP + 负载均衡
Ingress 域名/路由/TLS 的七层入口
ConfigMap/Secret 配置与密钥
声明式 说"要什么",控制器负责"怎么做"

本文是「云原生」系列第 4 篇,下篇动手把应用部署进 K8s。