知远漫谈头像
关注
Kubernetes - 零基础理解 K8s 的核心组件及功能分工封面图

Kubernetes - 零基础理解 K8s 的核心组件及功能分工

在这里插入图片描述

👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕Kubernetes这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


文章目录

Kubernetes - 零基础理解 K8s 的核心组件及功能分工 🌐✨

“Kubernetes 是一个可移植、可扩展的开源平台,用于自动化容器化应用的部署、扩展和管理。”
—— 官方定义(kubernetes.io)

如果你刚接触云原生,第一次看到 kubectl get pods、Deployment、Service、etcd、kubelet 这些词时感到头晕目眩——别担心!你不是一个人。🎯
本篇博客将从零开始、不预设任何前置知识,用清晰的逻辑脉络 + 真实可运行的 Java 示例 + 可视化 Mermaid 图表 + 恰到好处的类比,带你穿透 Kubernetes 的抽象迷雾,真正理解:
✅ 每个核心组件是谁?它坐在系统哪个位置?
✅ 它到底在做什么?为什么非它不可?
✅ Java 应用如何与它协作?代码里哪一行在跟 K8s 打交道?
✅ 当一个 HTTP 请求从浏览器发出,K8s 内部发生了什么?

全文约 8000 字,全程无术语轰炸,只有层层递进的理解。


🌱 一、先问一个问题:我们为什么需要 Kubernetes?

想象你是一位 Java 后端工程师,刚完成了一个 Spring Boot 微服务:用户注册服务 user-service,打包成 Docker 镜像 registry.example.com/user-service:v1.2.0。

你本地 docker run -p 8080:8080 user-service:v1.2.0 ✅ 正常启动;
你把它拷贝到一台阿里云 ECS 上,手动 docker run ... ✅ 也能访问;
但当业务爆发,你需要:

  • 同时运行 5 个副本抗住流量;
  • 某个副本 OOM 崩溃了,要 自动拉起新实例;
  • 新版本发布时,要 灰度 10% 流量 → 50% → 全量,出问题秒级回滚;
  • 用户请求进来,要 自动负载均衡到任意一个健康副本;
  • 日志统一收集、指标集中监控、配置动态更新……

⚠️ 如果全靠 Shell 脚本 + docker ps + curl 健康检查 + scp 配置文件……
👉 你会在凌晨三点被 PagerDuty 报警叫醒,一边喝冰美式一边手抖写 docker kill $(docker ps -q --filter "status=exited")。

这就是 Kubernetes 存在的根本意义:

它不是“另一个 Docker”,而是“容器的操作系统”——负责调度、编排、自愈、网络、存储、安全等一切基础设施职责,让你专注写 Java 业务代码。 💡

🔗 拓展阅读:Kubernetes 官方架构概览(官方文档,语言简洁,配图清晰)


🧩 二、K8s 不是单体程序,而是一组协同工作的控制平面 + 工作节点 🏗️

Kubernetes 是典型的 控制平面(Control Plane) + 工作节点(Worker Node) 架构:

┌─────────────────────────────────────────────────────────────┐
│                        控制平面(Master)                     │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐   │
│  │  kube-   │   │  kube-   │   │  kube-   │   │   etcd   │   │
│  │ scheduler│   │ controller│   │  apiserver│   │ (数据库) │   │
│  └──────────┘   └──────────┘   └──────────┘   └──────────┘   │
└─────────────────────────────────────────────────────────────┘
                                     ↓ HTTPS API(RESTful)
                                     ↓
┌─────────────────────────────────────────────────────────────┐
│                        工作节点(Node)                        │
│  ┌──────────┐   ┌──────────┐   ┌──────────────────────────┐   │
│  │  kubelet │   │  container │   │     Pod(含多个容器)      │   │
│  │ (代理)   │   │ runtime    │   │  ┌─────────┐ ┌─────────┐ │   │
│  └──────────┘   └──────────┘   │  │ Java App│ │ Redis   │ │   │
│                                 │  └─────────┘ └─────────┘ │   │
│                                 └──────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

别急着记名字!我们用一个生活类比来锚定认知:

🍳 把 Kubernetes 想象成一家 24 小时运转的智能中央厨房:

  • 控制平面 = 厨房大脑(主厨 + 食材库 + 订单中心)
  • 工作节点 = 分布在各楼层的智能烹饪工作站(带灶台、冰箱、机械臂)
  • Pod = 一个密封料理盒,里面放「必须一起烧」的菜(如:主菜 Java + 辅料 Redis 容器)
  • 你的 Spring Boot 应用 = 盒子里那道主菜 👨‍🍳

现在,我们逐个拆解每个组件——不仅说它是什么,更说它在“做一道菜”的过程中具体干了什么。


🧠 三、控制平面四大金刚:谁在发号施令?怎么发?

1️⃣ kube-apiserver —— 整个集群的唯一“前台接待 + 总机” 📞

✅ 它是 Kubernetes 的唯一入口,所有操作(无论是 kubectl、CI/CD 脚本、还是 Java 客户端)都必须通过它。
✅ 它不直接干活,只负责鉴权、校验、转发、提供 REST API。
✅ 它是无状态的,可以水平扩展(加机器)。

🔍 它在做什么?
  • 当你执行 kubectl get pods -n default,实际是向 https://<master-ip>:6443/api/v1/namespaces/default/pods 发 GET 请求;
  • 当 CI/CD 流水线调用 kubectl apply -f deployment.yaml,API Server 解析 YAML,验证字段合法性(比如 replicas: 3 是整数),再存入 etcd;
  • 它还强制执行 RBAC 权限检查:“这个 Jenkins 机器人账号,有没有权限在 prod 命名空间删 Pod?” ❌
💡 关键特性:
  • RESTful 设计:所有资源(Pod、Service、ConfigMap…)都是 API 对象,有标准 URL 路径 /api/v1/namespaces/{ns}/pods/{name};
  • 声明式接口:你告诉它“我要 3 个副本”,而不是“请帮我启 3 个容器”——它自己决定怎么做;
  • Watch 机制:其他组件(如 kubelet、controller-manager)会建立长连接,监听资源变更(如 Pod 状态从 Pending → Running)。
🐘 Java 示例:用 Fabric8 Kubernetes Client 调用 API Server(真实可运行)

假设你有一个 Spring Boot 管理后台,想实时展示集群中所有 Java 应用 Pod 的状态:

// pom.xml 添加依赖
<!-- https://search.maven.org/artifact/io.fabric8/kubernetes-client -->
<dependency>
  <groupId>io.fabric8</groupId>
  <artifactId>kubernetes-client</artifactId>
  <version>6.12.0</version> <!-- 请使用最新稳定版 -->
</dependency>
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodList;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class K8sPodMonitor {

    // 在集群内运行时,自动加载 ServiceAccount Token 和 CA 证书
    private final KubernetesClient client = new DefaultKubernetesClient();

    /**
     * 获取 default 命名空间下所有包含 'java' 标签的 Pod(模拟 Java 应用)
     */
    public List<PodInfo> listJavaPods() {
        PodList podList = client.pods()
                .inNamespace("default")
                .withLabel("app.kubernetes.io/component", "java-backend") // 自定义标签
                .list();

        return podList.getItems().stream()
                .map(pod -> new PodInfo(
                        pod.getMetadata().getName(),
                        pod.getStatus().getPhase(), // Running / Pending / Failed
                        pod.getStatus().getHostIP(),
                        pod.getStatus().getPodIP()
                ))
                .collect(Collectors.toList());
    }

    // 简单 DTO
    public static class PodInfo {
        private final String name;
        private final String status;
        private final String hostIP;
        private final String podIP;

        public PodInfo(String name, String status, String hostIP, String podIP) {
            this.name = name;
            this.status = status;
            this.hostIP = hostIP;
            this.podIP = podIP;
        }
        // getter...
    }
}

✅ 这段 Java 代码没有碰 Docker、没连 etcd、没调用 kubelet——它只和 kube-apiserver 通信,就像前端调后端 API 一样自然。
✅ 它利用了 Kubernetes 的 ServiceAccount 自动挂载机制:当 Pod 运行在集群内,K8s 会自动注入 Token 和 CA 证书到 /var/run/secrets/kubernetes.io/serviceaccount/,客户端开箱即用。

🔗 拓展阅读:Fabric8 官方文档 - Java Client 使用指南


2️⃣ etcd —— 集群的“中央档案馆” 📚

✅ 它是 Kubernetes 的唯一可信数据源,一个分布式的、强一致性的键值数据库。
✅ 所有集群状态(Pod 列表、Service IP、Secret 内容、Deployment 副本数…)都持久化在这里。
✅ API Server 是它唯一的“合法写入者”,其他组件只能通过 API Server 读写。

🔍 它在做什么?
  • 当你 kubectl apply -f nginx-deployment.yaml,API Server 把 Deployment 对象序列化为 JSON,存入 etcd 的 /registry/deployments/default/nginx-deployment 路径;
  • 当某个 Node 失联,kube-controller-manager 检测到其上 Pod 长时间未上报心跳,就从 etcd 中读取该 Pod 的原始定义,触发“驱逐”逻辑,并写入新 Pod 对象;
  • 它不存日志、不存应用数据、不存镜像——只存“集群应该长什么样”的声明式事实。
⚠️ 重要原则:
  • 绝不直连 etcd! 所有组件(包括你写的 Java 程序)必须通过 kube-apiserver 间接访问。这是安全与一致性的基石。
  • 备份 etcd = 备份整个集群。生产环境必须定期快照(etcdctl snapshot save)。
🧩 类比加深理解:

📦 想象 etcd 是厨房的「电子点餐系统后台数据库」:

  • 顾客下单(kubectl apply)→ 前台(API Server)录入订单 → 存入数据库(etcd);
  • 主厨(Controller Manager)定时查库:“哪些订单还没做?” → 下达指令给灶台(kubelet);
  • 如果数据库崩了,前台无法接单,主厨不知道该做什么,灶台不知道自己烧的是哪道菜——整个厨房停摆。💥

3️⃣ kube-controller-manager —— “永不停歇的自动化管家” 🤖

✅ 它是一组控制器(Controller)的集合,持续“观察-比较-修正”,确保集群实际状态(Actual State)永远匹配你声明的目标状态(Desired State)。
✅ 它是 Kubernetes 自愈能力的核心。

🔍 它在做什么?看几个经典控制器:
控制器监控对象做什么?Java 开发者关联场景
ReplicaSet ControllerReplicaSet确保当前运行的 Pod 数量 = .spec.replicas。若 Pod 意外终止,立刻新建一个。Deployment 的底层支撑,保障 Java 应用高可用
Node ControllerNode检测 Node 心跳超时(默认 40 秒),标记为 NotReady,并驱逐其上所有 Pod。你的 Java Pod 自动漂移到健康节点,用户无感
EndpointSlice ControllerService + Pod监听 Pod 变化,自动更新 Service 对应的 EndpointSlice(记录后端 Pod IP+Port 列表)。Spring Cloud LoadBalancer 无需再自己维护实例列表!
PersistentVolume ControllerPersistentVolumeClaim绑定 PVC 到 PV,或动态创建 PV(对接 NFS/AWS EBS)。Java 应用挂载 MySQL 数据盘
🧪 Java 示例:用 Deployment 声明“我要 3 个 Java 实例”,Controller 如何响应?
# java-app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: java-user-service
  labels:
    app: user-service
spec:
  replicas: 3  # ← 这就是 Desired State!
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: app
        image: registry.example.com/user-service:v1.2.0
        ports:
        - containerPort: 8080
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: "k8s"

✅ 提交后,kube-controller-manager 中的 ReplicaSet Controller 立刻行动:

  1. 读取 etcd 中该 Deployment 的 replicas: 3;
  2. 查询当前 app=user-service 的 Pod 数量 → 发现是 0;
  3. 创建一个 ReplicaSet 对象(带 OwnerReference 指向 Deployment);
  4. 再创建 3 个 Pod 对象,写入 etcd;
  5. kube-scheduler 开始为这 3 个 Pod 选择 Node;
  6. kubelet 在对应 Node 上拉起容器……

整个过程全自动,无需人工干预。你的 Java 代码完全感知不到——它只管处理 HTTP 请求 🌐。


4️⃣ kube-scheduler —— “最强大脑调度员” 🧠

✅ 它负责将“待运行”的 Pod(处于 Pending 状态)分配到合适的 Node 上。
✅ 它不执行启动,只做决策:“这个 Pod,应该放在哪台机器上跑?”

🔍 它在做什么?

Scheduler 持续监听 API Server:
➡️ 发现新 Pod(.spec.nodeName 为空,且 .status.phase == Pending)
➡️ 运行两阶段算法:

  1. Predicate(过滤):排除不满足硬性条件的 Node
    • 资源足够?(CPU 2C / Memory 4Gi → Node 剩余资源 ≥ 此值)
    • 满足亲和性?(requiredDuringSchedulingIgnoredDuringExecution)
    • 没有污点冲突?(Node 有 node-role.kubernetes.io/master:NoSchedule,而 Pod 没容忍)
  2. Priority(打分):对剩余 Node 打分,选最高分
    • CPU 利用率低的 Node 分更高(均衡负载)
    • 同一 Zone 的 Node 分更高(降低网络延迟)
    • 有更多空闲磁盘的 Node 分更高

➡️ 选定 Node 后,调用 API Server 的 PATCH /api/v1/namespaces/{ns}/pods/{name},设置 .spec.nodeName = "node-03"

➡️ 此时 Pod 状态变为 Scheduled,kubelet 在 node-03 上看到自己被指派,立刻行动。

🧩 Java 场景思考:

假设你的 Java 应用是风控服务,对延迟极度敏感,且需访问同机房的 GPU 推理服务:

# 风控服务 Pod 模板片段
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: topology.kubernetes.io/zone
            operator: In
            values: ["cn-shanghai-a"] # 强制同可用区
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values: ["risk-engine"]
          topologyKey: kubernetes.io/hostname # 尽量不在同一物理机
  tolerations:
  - key: "gpu-only"
    operator: "Exists" # 容忍 GPU 节点的污点

✅ kube-scheduler 会严格按这些规则筛选,确保你的 Java 风控服务永远运行在最优位置。你不用改一行 Java 代码,只需声明意图。


🧱 四、工作节点三剑客:谁在真正干活?

控制平面发号施令,但真正烧菜、洗碗、擦灶台的,是工作节点上的三个核心组件:

1️⃣ kubelet —— Node 上的“全能现场经理” 👷

✅ 它是每个 Node 上必须运行的代理,唯一职责:确保本机上所有 Pod 都按 API Server 的描述准确运行。
✅ 它不关心“为什么启动这个 Pod”,只关心“启动了没?健康吗?日志在哪?”

🔍 它在做什么?
  • 定期(默认 10s)向 API Server 报告本机状态(NodeCondition)、Pod 状态(PodStatus);
  • 通过 CRI(Container Runtime Interface)调用底层容器运行时(Docker、containerd、CRI-O);
  • 执行生命周期钩子(postStart, preStop);
  • 运行 Liveness/Readiness Probe(健康检查);
  • 挂载 Volume(ConfigMap、Secret、PersistentVolume)到容器路径。
🐘 Java 示例:Spring Boot 的 Readiness Probe 如何与 kubelet 协作?
// Spring Boot Actuator + Kubernetes 集成
// application.yml
management:
  endpoint:
    health:
      show-details: when_authorized
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  health:
    probes:
      show-details: always

# 定义 Readiness 探针(告诉 kubelet:“我准备好接流量了吗?”)
readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10
// 自定义 Readiness Indicator(例如:等待数据库连接池初始化完成)
@Component
public class DatabaseReadinessIndicator implements HealthIndicator {

    private final HikariDataSource dataSource;

    public DatabaseReadinessIndicator(HikariDataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Health health() {
        try {
            // 尝试获取连接(轻量级检测)
            try (Connection conn = dataSource.getConnection()) {
                return Health.up().withDetail("db-status", "connected").build();
            }
        } catch (Exception e) {
            return Health.down()
                    .withDetail("error", e.getMessage())
                    .build();
        }
    }
}

✅ 当 kubelet 调用 http://localhost:8080/actuator/health/readiness:

  • 若返回 200 { "status": "UP" } → kubelet 标记该 Pod 为 Ready → EndpointSlice 加入此 Pod IP;
  • 若连续失败(如 DB 连不上)→ kubelet 标记 NotReady → Service 流量自动剔除该实例;
  • 你的 Java 代码无需监听 Kubernetes 事件!只需暴露标准健康端点,kubelet 主动来问。

🔗 拓展阅读:Kubernetes 官方探针文档


2️⃣ container-runtime(如 containerd)—— “真正的灶台与锅具” 🍳

✅ 它负责下载镜像、解压、创建容器命名空间、挂载 rootfs、启动进程……是容器技术的真正执行者。
✅ Kubernetes 通过 CRI(Container Runtime Interface)与它解耦——你可以自由切换 Docker → containerd → CRI-O。

🔍 它在做什么?
  • 接收 kubelet 的 CRI gRPC 请求(如 RunPodSandbox, CreateContainer, StartContainer);
  • 拉取镜像(registry.example.com/user-service:v1.2.0);
  • 创建 Linux cgroup + namespace 隔离环境;
  • 启动 Java 进程:java -Xms512m -Xmx1g -jar app.jar;
  • 管理容器生命周期(stop、pause、exec)。
💡 Java 开发者注意:
  • 你的 Dockerfile 决定了 container-runtime 如何启动 Java 进程:
    FROM openjdk:17-jre-slim
    COPY target/user-service.jar /app.jar
    EXPOSE 8080
    ENTRYPOINT ["java","-Xms512m","-Xmx1g","-jar","/app.jar"]
    
  • 不要在容器内跑 systemd 或 supervisord!Kubernetes 期望容器是“一个前台进程”,Java 应用天然符合。

3️⃣ kube-proxy —— “集群内部的智能流量转发器” 🚦

✅ 它负责实现 Kubernetes Service 的抽象:让 Pod 可以通过 Service 名称互相访问,且自动负载均衡。
✅ 它不处理外部流量(那是 Ingress 的事),只管集群内部东西向通信。

🔍 它在做什么?

kube-proxy 有三种模式(v1.22+ 默认 iptables → ipvs → nftables),我们以现代 ipvs 模式为例:

  • 监听 API Server 的 Service 和 EndpointSlice 变化;
  • 在 Node 上创建 IPVS 规则,例如:
    # Service: user-service.default.svc.cluster.local → ClusterIP 10.96.12.100:8080
    # 后端 Pod: 10.244.1.10:8080, 10.244.1.11:8080, 10.244.2.5:8080
    ipvsadm -A -t 10.96.12.100:8080 -s rr
    ipvsadm -a -t 10.96.12.100:8080 -r 10.244.1.10:8080 -m
    ipvsadm -a -t 10.96.12.100:8080 -r 10.244.1.11:8080 -m
    ipvsadm -a -t 10.96.12.100:8080 -r 10.244.2.5:8080 -m
    
  • 当 Pod A(order-service)访问 http://user-service:8080/api/users:
    1. DNS 解析 user-service.default.svc.cluster.local → 10.96.12.100(ClusterIP);
    2. Linux netfilter 截获包,IPVS 按 rr 策略转发到某个后端 Pod IP;
    3. 整个过程对 Java 应用完全透明——你代码里写 http://user-service:8080,就像调本地服务一样简单!
🐘 Java 示例:Spring Boot 调用另一服务,零配置实现服务发现
@Service
public class UserServiceClient {

    private final RestTemplate restTemplate;

    // 构造注入,使用 Service 名称(DNS 自动解析!)
    public UserServiceClient(RestTemplateBuilder builder) {
        this.restTemplate = builder
                .rootUri("http://user-service:8080") // ← 注意!不是 IP,不是域名,就是 Service 名!
                .build();
    }

    public User getUser(Long id) {
        // 自动负载均衡到任意一个 user-service Pod
        return restTemplate.getForObject("/api/users/{id}", User.class, id);
    }
}

✅ 没有 Eureka、没有 Nacos、不需要 @LoadBalanced 注解(那是 Spring Cloud Netflix 时代的遗留)——Kubernetes 原生 Service + kube-proxy 已为你搞定一切。


🌐 五、一次完整的 HTTP 请求之旅:K8s 内部发生了什么?🚀

让我们把所有组件串起来,追踪一个真实请求:

🌐 用户在浏览器输入:https://shop.example.com/order/123
→ 经过公网 DNS → Ingress Controller(如 Nginx Ingress)→ order-service → 调用 user-service → 返回 JSON

Kubernetes 集群

HTTPS

HTTP

HTTP

MySQL

用户浏览器

公网DNS

Cloud Load Balancer
(阿里云 SLB / AWS ALB)

Ingress Controller Pod
nginx-ingress-controller

order-service Pod
Spring Boot

user-service Pod
Spring Boot

StatefulSet Pod
MySQL

🔍 步骤分解(从 Ingress 到 Java 应用):

步骤组件动作关键点
① 入口Cloud LB将 shop.example.com 的 443 端口流量,转发到集群内 Ingress Controller 的 NodePort(如 31234)LB 不懂 Kubernetes,只做四层转发
② 路由Ingress ControllerNginx 解析 HTTP Host 和 Path:
host: shop.example.com + path: /order/* → 匹配到 order-service Service
Ingress 是 Kubernetes 对象,由 ingress-controller 实现
③ 发现 & 转发kube-proxy(在 Ingress Controller Node 上)将请求目标 IP:Port 替换为 order-service 的 ClusterIP(如 10.96.10.20:80),再通过 IPVS 转发到某个 order-service Pod IP(如 10.244.1.15:8080)Service 抽象在此生效
④ 启动 Javakubelet + containerd在 10.244.1.15 节点上,containerd 启动容器,执行 java -jar order-service.jar,暴露 8080 端口Java 进程作为容器主进程运行
⑤ 内部调用order-service Java 代码调用 RestTemplate.getForObject("http://user-service:8080/api/users/1", User.class)DNS 解析 user-service → 10.96.12.100,再经 kube-proxy 转发
⑥ 自愈保障kube-controller-manager若 user-service 某 Pod OOM 退出,Controller 检测到 Running 数 < 3,立即创建新 Pod;kubelet 拉起;kube-proxy 自动更新 IPVS 规则用户无感知

✅ 看到了吗?你的 Java 代码只写了两行关键逻辑:

  1. RestTemplate 调用 http://user-service:8080(服务发现)
  2. 暴露 /actuator/health/readiness(健康检查)
    其余所有运维复杂性——扩缩容、故障转移、网络策略、证书管理——全部由 Kubernetes 组件分担。

🧩 六、核心资源对象全景图:它们不是概念,而是 API 资源!

Kubernetes 的一切,最终都落地为 API Server 管理的资源对象(Resource Object)。理解它们,就是理解 K8s 的“编程模型”。

核心对象

Workload

Service Discovery & Load Balancing

Configuration & Storage

Cluster-wide

Pod

Deployment

StatefulSet

DaemonSet

Job/CronJob

Service

Ingress

EndpointSlice

ConfigMap

Secret

Volume
PersistentVolume
PersistentVolumeClaim

Namespace

Role/RoleBinding
ClusterRole/ClusterRoleBinding

Node

我们重点聚焦 Java 应用最常打交道的 5 个对象:

✅ 1. Pod —— 最小的、不可分割的部署单元 📦

  • 一个 Pod = 一个“逻辑主机”,可含 1 个或多个紧密耦合的容器(如 Java App + log-forwarder sidecar);
  • 所有容器共享 Network Namespace(同 IP、同端口空间)、IPC、UTS,挂载相同 Volume;
  • Pod 是短暂的(Ephemeral):崩溃即销毁,新 Pod 是全新实体(IP、Hostname 都变)。
# 一个典型的 Java Pod(通常由 Deployment 管理,不手动创建)
apiVersion: v1
kind: Pod
metadata:
  name: user-service-7f8d9c4b5-xz2qk  # 自动生成
  labels:
    app: user-service
    pod-template-hash: 7f8d9c4b5
spec:
  containers:
  - name: app
    image: registry.example.com/user-service:v1.2.0
    ports:
    - containerPort: 8080
    envFrom:
    - configMapRef:
        name: app-config
    - secretRef:
        name: app-secrets
  restartPolicy: Always # Kubernetes 控制重启,不是容器内进程

✅ 2. Deployment —— 声明式管理 Pod 生命周期的“指挥官” 🎯

  • 它不直接创建 Pod,而是创建 ReplicaSet,再由 ReplicaSet 创建 Pod;
  • 支持滚动更新(RollingUpdate)、回滚(kubectl rollout undo)、暂停/恢复;
  • Java 应用发布的事实标准。
# deployment.yaml 片段(已见前文)
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # 更新时最多多启 1 个 Pod
      maxUnavailable: 0  # 更新时 0 个 Pod 不可用(保证 100% SLA)

✅ 3. Service —— 为 Pod 提供稳定的网络端点 🌐

  • ClusterIP(默认):集群内访问,如 user-service.default.svc.cluster.local;
  • NodePort:通过 <NodeIP>:<NodePort> 从集群外访问(测试用);
  • LoadBalancer:对接云厂商 LB(生产常用);
  • Service 的 IP 是虚拟的(VIP),由 kube-proxy 实现。
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service  # 匹配 Pod labels
  ports:
  - protocol: TCP
    port: 8080         # Service 暴露的端口
    targetPort: 8080   # Pod 容器端口
  type: ClusterIP

✅ 4. ConfigMap & Secret —— 解耦配置与镜像 🗂️🔒

  • ConfigMap:存非敏感配置(application.yml、JVM 参数);
  • Secret:存敏感信息(DB password、API keys),Base64 编码(⚠️ 不是加密!需配合 RBAC 和 Encryption at Rest);
  • 挂载为文件 or 环境变量,Java 应用零改造读取。
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  application.yml: |
    spring:
      profiles:
        active: k8s
      datasource:
        url: jdbc:mysql://mysql:3306/shop?useSSL=false
    server:
      port: 8080

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
data:
  DB_PASSWORD: cGFzc3dvcmQxMjM= # base64 encoded "password123"
// Java 代码读取(通过 Spring Boot 自动绑定)
@Component
public class DbConfig {
    @Value("${spring.datasource.password}")
    private String dbPassword; // ← 自动从 Secret 注入!
}

✅ 5. Ingress —— 集群南北向流量的七层网关 🌍

  • 它本身不转发流量,只是一个“路由规则声明”;
  • 必须搭配 Ingress Controller(如 Nginx、Traefik)才能工作;
  • 支持基于 Host/Path 的路由、TLS 终止、重写。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop-ingress
spec:
  tls:
  - hosts:
      - shop.example.com
    secretName: shop-tls-secret  # 引用 Secret 中的证书
  rules:
  - host: shop.example.com
    http:
      paths:
      - path: /order
        pathType: Prefix
        backend:
          service:
            name: order-service
            port:
              number: 8080
      - path: /user
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 8080

🌟 七、给 Java 工程师的终极建议:如何与 K8s 和谐共处?

你不需要成为 K8s 专家,但掌握以下原则,能让你写出更云原生、更健壮的 Java 应用:

✅ 1. 拥抱“十二要素应用”(The Twelve-Factor App)

  • 配置外置:用 ConfigMap/Secret,而非打包进 Jar;
  • 无状态优先:Session 存 Redis,文件存 OSS/S3,数据库用 StatefulSet + PV;
  • 一个进程一个容器:不要在容器里跑多个服务(Java + Nginx + crond);
  • 快速启动与优雅关闭:preStop Hook 中调用 /actuator/shutdown,等待连接 draining。
lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "curl -X POST http://localhost:8080/actuator/shutdown"]

✅ 2. 善用 Spring Boot Actuator + Kubernetes 原生集成

  • health 端点 → Readiness Probe;
  • prometheus 端点 → Prometheus 抓取指标;
  • loggers 端点 → 动态调整日志级别(无需重启);
  • threaddump → 排查 CPU 飙高。

✅ 3. 监控不是可选项,而是上线前提

  • 必埋指标:jvm_memory_used_bytes, http_server_requests_seconds_count, tomcat_sessions_active_current;
  • 用 Prometheus + Grafana 做 SLO 看板(如错误率 < 0.1%,P95 延迟 < 500ms);
  • kubectl top pods 查实时资源占用,比 ps aux 更准。

✅ 4. 调试技巧:当 Pod 启动失败

# 1. 看 Pod 事件(最有价值!)
kubectl describe pod user-service-7f8d9c4b5-xz2qk

# 2. 看容器日志(-c 指定容器名,如有 sidecar)
kubectl logs user-service-7f8d9c4b5-xz2qk -c app --previous

# 3. 进容器调试(临时)
kubectl exec -it user-service-7f8d9c4b5-xz2qk -c app -- /bin/sh

# 4. 检查 Service 是否正确关联 Pod
kubectl get endpoints user-service

✅ 5. 学习路径推荐(循序渐进)

  1. ✅ 先掌握 kubectl 常用命令(get, describe, logs, exec, port-forward);
  2. ✅ 理解 Pod/Deployment/Service/ConfigMap YAML 结构;
  3. ✅ 在 Minikube 或 Kind 本地集群跑通一个 Spring Boot 示例;
  4. ✅ 学习 Helm(K8s 的包管理器),一键部署复杂应用;
  5. ✅ 深入网络(CNI)、存储(CSI)、安全(PodSecurityPolicy / Pod Security Admission)。

🔗 拓展阅读:Kubernetes 官方交互式教程(免费) —— 15 分钟动手体验,强烈推荐!


🌈 结语:Kubernetes 是舞台,Java 是主角

回到最初的问题:Kubernetes 到底是什么?
它不是一个让你加班 debug 的新工具链,而是一套现代化的、声明式的、面向终态的基础设施契约。

当你写下:

replicas: 5
readinessProbe: { httpGet: { path: "/actuator/health/readiness" } }
resources: { requests: { memory: "512Mi" }, limits: { memory: "1Gi" } }

你不是在配置服务器,而是在向宇宙宣告:我的 Java 应用,应以何种尊严存在。
Kubernetes 的使命,就是不惜一切代价,让这个宣言成真。

所以,放下对 etcd 的恐惧,忘记 kube-scheduler 的算法细节,不必深究 ipvs 的哈希函数——
先让一个 Spring Boot 应用,在 kubectl apply 后,稳稳地跑起来。
然后,再一层层剥开洋葱,你会爱上这种“所见即所得”的确定性。

毕竟,最好的架构,是让你忘记架构的存在。
而 Kubernetes,正努力成为那个“隐形的巨人”。 🌟


本文完。愿你每一次 kubectl get pods,都看到绿色的 Running。 🍀


🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qq_41187124/article/details/157586305

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--