欢迎光临
我们一直在努力

Kubernetes - 核心资源对象的关系梳理,构建 K8s 知识框架

在这里插入图片描述

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


文章目录

  • Kubernetes – 核心资源对象的关系梳理,构建 K8s 知识框架 🌐✨
    • 一、Pod:一切调度与运行的原子单元 🧫
      • ✅ 为什么必须是 Pod,而不是单个容器?
      • 📜 Java 示例:使用 Fabric8 Client 创建 Pod
      • 🔄 Pod 的生命周期状态(Phase)
    • 二、Controller:赋予 Pod 生命力的“指挥官” 🎼
      • 📊 关键关系图:Controller 与 Pod 的拓扑依赖
      • 🐘 Java 示例:用 Deployment 实现滚动更新
      • 📈 Deployment 滚动更新策略详解
    • 三、Service:服务发现与负载均衡的“交通警察” 🚦
      • 🔗 Service 的三种类型对比
      • 🧩 Service 如何找到 Pod?靠 `selector` + `Endpoints`
      • 🐍 Java 示例:Spring Boot 调用另一服务(Service 名称解析)
      • 🛡️ Headless Service:无 ClusterIP,直连 Pod(StatefulSet 场景)
    • 四、ConfigMap 与 Secret:解耦配置与代码的“保险箱” 🗃️
      • 📁 Java 示例:从 ConfigMap/Secret 加载 Spring Boot 配置
        • 步骤 1:创建 ConfigMap 与 Secret(YAML)
        • 步骤 2:在 Deployment 中挂载为 Volume(推荐)或环境变量
        • 步骤 3:Java 代码优雅读取(无需改动)
    • 五、Volume:Pod 的“持久化外挂硬盘” 💾
      • 🧩 PVC/PV 模型:存储的“申请-分配”契约
      • 🐘 Java 示例:Spring Boot 使用 PVC 存储上传文件
    • 六、Namespace:集群内的“虚拟子集群” 🏙️
      • 📊 Namespace 关系图:资源作用域层级
    • 七、RBAC:权限的“门禁系统” 🚪
      • 🛡️ Java 示例:为 Spring Boot 应用 ServiceAccount 授权访问 ConfigMap
        • 步骤 1:创建 ServiceAccount
        • 步骤 2:定义 Role(仅允许读取 ConfigMap)
        • 步骤 3:绑定 Role 到 ServiceAccount
        • 步骤 4:在 Deployment 中指定 ServiceAccount
        • 步骤 5:Java 代码安全读取 ConfigMap
    • 八、Ingress:七层 HTTP/HTTPS 路由的“智能网关” 🌐
      • 🌐 Ingress 工作原理简图
      • 🐘 Java 示例:Spring Boot 应用暴露 HTTPS 入口
    • 九、构建你的 K8s 知识框架:一张图看懂核心关系 🧭
    • 十、结语:从理解到驾驭,Java 工程师的 K8s 进阶之路 🚀

Kubernetes – 核心资源对象的关系梳理,构建 K8s 知识框架 🌐✨

Kubernetes(简称 K8s)已成为云原生时代的操作系统级抽象层——它不直接管理硬件,却统一调度计算、存储与网络;它不编写业务逻辑,却为千万微服务提供可信赖的运行基座。对 Java 工程师而言,理解 K8s 不再是“运维的事”,而是构建高可用、可观测、可灰度、可弹性的分布式系统的必修内功 🔧。本文将从核心资源对象的本质出发,系统性梳理 Pod、Controller、Service、ConfigMap/Secret、Volume、Namespace、RBAC 等关键组件的语义边界、协作机制与依赖关系,并结合真实可运行的 Java 示例代码(基于 Spring Boot + Fabric8 Kubernetes Client),辅以动态 Mermaid 关系图谱,助你构建结构清晰、逻辑自洽的 K8s 知识框架 🧱→🚀。

💡 前置认知锚点:Kubernetes 是一个声明式 API 驱动的控制平面。你通过 YAML 或 Java 客户端“告诉”集群“我想要什么状态”(Desired State),而 kube-controller-manager、kube-scheduler、kubelet 等组件持续观测实际状态(Actual State),并通过调谐(Reconciliation)循环不断逼近目标。所有资源对象,都是这个声明式世界中的“一等公民”。


一、Pod:一切调度与运行的原子单元 🧫

Pod 是 Kubernetes 中最小、最不可分割的可调度与可运行单元。它不是容器,而是共享 Linux 命名空间(Network、PID、IPC)、挂载点(Volumes)和生命周期的容器集合。一个 Pod 内可包含多个紧密协作的容器(如主应用 + sidecar 日志收集器),它们共享 IP 和端口空间,通过 localhost 通信。

✅ 为什么必须是 Pod,而不是单个容器?

  • 容器本质是进程隔离单元,但微服务架构中常需“胶水型”辅助进程(如 Envoy 代理、Prometheus Exporter、Nginx 静态文件服务);
  • 共享网络栈让 http://localhost:9090/metrics 在主应用与 Exporter 间零配置互通;
  • 共享 Volume 让日志采集器可直接读取主应用写入 /var/log/app/ 的文件。

📜 Java 示例:使用 Fabric8 Client 创建 Pod

Fabric8 是 Java 生态最成熟、API 最贴近 Kubernetes 原生语义的客户端库。以下代码创建一个运行 Spring Boot 应用的 Pod:

import io.fabric8.kubernetes.api.model.*;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;

public class PodExample {
public static void main(String[] args) {
try (KubernetesClient client = new KubernetesClientBuilder().build()) {
// 构建 PodSpec:定义容器与共享资源
Container container = new ContainerBuilder()
.withName("spring-boot-app")
.withImage("registry.example.com/myapp:1.2.0") // 替换为你自己的镜像
.withPorts(new ContainerPortBuilder()
.withContainerPort(8080)
.withProtocol("TCP")
.build())
.withEnv(
new EnvVarBuilder().withName("SPRING_PROFILES_ACTIVE").withValue("prod").build(),
new EnvVarBuilder().withName("JAVA_TOOL_OPTIONS").withValue("-Xmx512m").build()
)
.build();

// PodSpec 核心:容器列表 + 共享卷(此处定义空目录卷)
PodSpec podSpec = new PodSpecBuilder()
.withContainers(container)
.withVolumes(
new VolumeBuilder()
.withName("config-volume")
.withConfigMap(
new ConfigMapVolumeSourceBuilder()
.withName("app-config")
.build()
)
.build()
)
.build();

// 构建完整 Pod 对象(metadata + spec)
Pod pod = new PodBuilder()
.withNewMetadata()
.withName("myapp-pod-v1")
.withNamespace("default")
.withLabels(Map.of("app", "myapp", "version", "v1"))
.endMetadata()
.withSpec(podSpec)
.build();

// 提交到集群(注意:生产环境强烈建议使用 Deployment 管理 Pod)
Pod createdPod = client.pods().inNamespace("default").create(pod);
System.out.println("✅ Pod created: " + createdPod.getMetadata().getName());
System.out.println("📍 IP Address: " + createdPod.getStatus().getPodIP());
}
}
}

⚠️ 注意:上述代码创建的是裸 Pod(Bare Pod),它不具备自愈能力(节点宕机后不会自动重建)、无法水平伸缩、不支持滚动更新。它仅用于教学演示或调试场景。生产环境应始终通过 Controller(如 Deployment) 来管理 Pod 生命周期。

🔄 Pod 的生命周期状态(Phase)

状态含义触发条件
Pending 已被 API Server 接收,但尚未调度或拉取镜像 资源不足、镜像拉取失败、节点污点不匹配
Running 已绑定到节点,且至少一个容器正在运行 kubelet 成功启动容器
Succeeded 所有容器成功终止,且不会重启 Job 完成
Failed 所有容器都已终止,至少一个以失败状态退出 应用崩溃、OOMKilled、健康检查失败
Unknown 无法获取 Pod 状态(如节点失联) kubelet 与 API Server 断连

你可以通过 kubectl get pods -o wide 查看 Phase,或在 Java 中监听:

client.pods().inNamespace("default").withName("myapp-pod-v1")
.watch(new Watcher<Pod>() {
@Override
public void eventReceived(Action action, Pod resource) {
String phase = resource.getStatus().getPhase();
System.out.println("🔄 Pod state changed to: " + phase);
if ("Running".equals(phase)) {
System.out.println("🟢 Ready for traffic!");
}
}
// … onError, onClose
});


二、Controller:赋予 Pod 生命力的“指挥官” 🎼

如果说 Pod 是士兵,那么 Controller 就是排长、连长、团长——它定义了“需要多少个士兵”、“士兵挂了谁来补上”、“升级时怎么换人不扰民”。Kubernetes 提供多种 Controller,每种解决一类编排问题:

Controller核心职责典型场景是否管理 Pod?
ReplicaSet 保证指定数量的 Pod 副本始终运行(副本集) Deployment 的底层支撑,极少直接使用
Deployment 声明式更新 Pod 模板(镜像、环境变量等),支持滚动更新、回滚、暂停 无状态 Web 应用、API 服务 ✅(委托给 ReplicaSet)
StatefulSet 为每个 Pod 提供稳定身份(网络标识 + 存储),按序部署/扩缩/删除 Kafka、ZooKeeper、MySQL 主从
DaemonSet 确保每个(或选定)节点上运行且仅运行一个 Pod 副本 日志收集(Fluentd)、监控代理(Prometheus Node Exporter)、网络插件(Calico)
Job/CronJob 运行一次性任务或定时任务(如数据备份、报表生成) 批处理、ETL、清理脚本 ✅(Job 创建 Pod,完成后终止)

📊 关键关系图:Controller 与 Pod 的拓扑依赖

渲染错误: Mermaid 渲染失败: Lexical error on line 6. Unrecognized text. …] subgraph “Control Plane” ———————^

🔍 图解说明:

  • Deployment 不直接操作 Pod,而是通过创建/更新 ReplicaSet 来间接控制;
  • ReplicaSet 是真正的“副本控制器”,它通过 selector 匹配标签(如 app=myapp)来发现并维持 Pod 数量;
  • 所有状态最终持久化到 etcd,kubelet 作为节点代理,负责执行 Pod 创建/销毁,并上报真实状态。

🐘 Java 示例:用 Deployment 实现滚动更新

以下代码创建一个 Deployment,初始版本为 v1.2.0,随后将其更新为 v1.3.0,触发滚动更新:

import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.kubernetes.api.model.apps.DeploymentStatus;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
import java.util.Map;

public class DeploymentExample {
public static void main(String[] args) throws InterruptedException {
try (KubernetesClient client = new KubernetesClientBuilder().build()) {
// Step 1: 创建 v1.2.0 版本 Deployment
Deployment deploymentV1 = buildDeployment("myapp-deployment", "v1.2.0");
Deployment createdV1 = client.apps().deployments()
.inNamespace("default")
.create(deploymentV1);
System.out.println("✅ v1.2.0 Deployment created");

// Wait for rollout completion
waitForRollout(client, "default", "myapp-deployment");

// Step 2: 更新为 v1.3.0 —— 仅修改镜像标签即触发滚动更新
Deployment updatedDeployment = buildDeployment("myapp-deployment", "v1.3.0");
Deployment rolledOut = client.apps().deployments()
.inNamespace("default")
.createOrReplace(updatedDeployment);
System.out.println("🔄 Rolling update to v1.3.0 initiated");

waitForRollout(client, "default", "myapp-deployment");
System.out.println("🎉 Rollout completed successfully!");
}
}

private static Deployment buildDeployment(String name, String version) {
return new DeploymentBuilder()
.withNewMetadata()
.withName(name)
.withNamespace("default")
.endMetadata()
.withNewSpec()
.withReplicas(3)
.withNewSelector()
.addToMatchLabels("app", "myapp")
.endSelector()
.withNewTemplate()
.withNewMetadata()
.addToLabels("app", "myapp")
.addToLabels("version", version)
.endMetadata()
.withNewSpec()
.addNewContainer()
.withName("spring-boot-app")
.withImage("registry.example.com/myapp:" + version)
.withPorts(new ContainerPortBuilder()
.withContainerPort(8080)
.build())
.endContainer()
.endSpec()
.endTemplate()
.endSpec()
.build();
}

private static void waitForRollout(KubernetesClient client, String namespace, String name)
throws InterruptedException {
while (true) {
Deployment deployment = client.apps().deployments()
.inNamespace(namespace).withName(name).get();
DeploymentStatus status = deployment.getStatus();
if (status != null &&
status.getReadyReplicas() != null &&
status.getReadyReplicas().equals(status.getReplicas())) {
break;
}
System.out.print("⏳ Waiting for rollout… ");
Thread.sleep(2000);
}
}
}

📈 Deployment 滚动更新策略详解

spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25% # 最多允许超出期望副本数 25% 的新 Pod(如 replicas=4 → 最多创建 5 个)
maxUnavailable: 25% # 更新过程中最多允许 25% 的旧 Pod 不可用(如 replicas=4 → 至少保持 3 个在线)

该策略确保服务零中断:新 Pod 启动并就绪(Readiness Probe 通过)后,才逐步终止旧 Pod。Spring Boot 应用需正确配置探针:

// Spring Boot Actuator + Kubernetes Probes
@RestController
public class HealthController {
@GetMapping("/actuator/health/readiness")
public Map<String, Object> readiness() {
// 自定义就绪逻辑:DB 连接池是否初始化完成?缓存是否预热?
return Map.of("status", "UP", "details", Map.of("cache", "WARMED"));
}

@GetMapping("/actuator/health/liveness")
public Map<String, Object> liveness() {
// 存活性:进程是否卡死?线程池是否耗尽?
return Map.of("status", "UP");
}
}

并在 Deployment 中声明:

livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5

🌐 深入学习:Kubernetes 官方文档对 Pod Lifecycle 和 Deployments 的解释极为精准,建议精读。


三、Service:服务发现与负载均衡的“交通警察” 🚦

Pod 是临时的(IP 变化、生命周期短),而 Service 提供了一个稳定的网络端点(ClusterIP / NodePort / LoadBalancer),将流量智能路由到后端健康的 Pod。它是 Kubernetes 服务发现(Service Discovery)的核心载体。

🔗 Service 的三种类型对比

类型ClusterIPNodePortLoadBalancer
作用域 集群内部访问 集群外部通过 <NodeIP>:<NodePort> 访问 云厂商提供公网 LB(如 AWS ALB、阿里云 SLB)
IP 分配 集群内虚拟 IP(VIP),由 kube-proxy 实现 在 ClusterIP 基础上,额外在每个节点开放一个端口(30000–32767) 云平台分配公网 IP,后端指向 NodePort 或直接 Pod
典型用途 微服务间调用(如 order-service → user-service) 测试环境快速暴露服务 生产环境面向公网的入口

🧩 Service 如何找到 Pod?靠 selector + Endpoints

渲染错误: Mermaid 渲染失败: Lexical error on line 6. Unrecognized text. …] subgraph “kube-proxy works he ———————^

💡 关键点:

  • Service 的 spec.selector 必须与 Pod 的 metadata.labels 完全匹配;
  • 当 Pod 创建/销毁时,Endpoints 对象(由 EndpointSlice 替代)会自动更新,kube-proxy 监听其变化并重写内核路由规则;
  • Java 应用无需硬编码 Pod IP,只需通过 http://myapp-service:8080/api/users 调用——DNS 解析由 CoreDNS 完成(<service-name>.<namespace>.svc.cluster.local)。

🐍 Java 示例:Spring Boot 调用另一服务(Service 名称解析)

假设集群中存在名为 user-service 的 Service,Java 代码可直接使用其 DNS 名:

@Service
public class OrderService {

private final RestTemplate restTemplate;

public OrderService(RestTemplateBuilder builder) {
this.restTemplate = builder
.setConnectTimeout(Duration.ofSeconds(3))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}

public User getUser(Long userId) {
// ✅ 正确:使用 Service DNS 名(集群内默认域名后缀为 .svc.cluster.local)
String url = "http://user-service:8080/users/" + userId;

// ❌ 错误:硬编码 Pod IP 或 Node IP(不稳定、不可扩展)
// String url = "http://10.244.1.12:8080/users/" + userId;

try {
ResponseEntity<User> response = restTemplate.getForEntity(url, User.class);
return response.getBody();
} catch (ResourceAccessException e) {
throw new ServiceException("Failed to call user-service", e);
}
}
}

🛡️ Headless Service:无 ClusterIP,直连 Pod(StatefulSet 场景)

当需要直接访问特定 Pod 实例(如 Kafka broker ID 绑定),而非负载均衡时,使用 Headless Service:

apiVersion: v1
kind: Service
metadata:
name: kafkaheadless
spec:
clusterIP: None # 👈 关键:无 VIP
selector:
app: kafka
ports:
port: 9092
targetPort: 9092

此时 DNS 解析结果为 Pod IP 列表:

  • kafka-headless.default.svc.cluster.local → [10.244.1.5, 10.244.2.7, 10.244.3.9]
  • kafka-0.kafka-headless.default.svc.cluster.local → 10.244.1.5(精确到序号)

Spring Boot Kafka 客户端配置:

spring:
kafka:
bootstrap-servers: kafka0.kafkaheadless:9092,kafka1.kafkaheadless:9092,kafka2.kafkaheadless:9092

🌐 更多实践参考:Kubernetes Service 官方指南 提供了详尽的故障排查技巧与高级特性(如 ExternalName、SessionAffinity)。


四、ConfigMap 与 Secret:解耦配置与代码的“保险箱” 🗃️

将配置(数据库地址、Feature Flag)硬编码在 Jar 包中,违背了“一次构建、多环境部署”原则。Kubernetes 提供两种标准化配置注入方式:

资源数据类型存储方式安全性典型用途
ConfigMap 明文键值对(String) etcd(base64 编码) ❌ 无加密 日志级别、Redis 地址、非敏感开关
Secret 二进制数据(base64 编码) etcd(同 ConfigMap) ⚠️ 基础防护(需 RBAC + 网络策略加固) 密码、TLS 证书、API Token

🔐 重要提醒:Secret 并非绝对安全!它只是 base64 编码,不是加密。生产环境必须配合:

  • RBAC:限制谁可读取 Secret;
  • NetworkPolicy:阻止非法 Pod 访问 kube-apiserver;
  • 第三方工具:如 HashiCorp Vault、AWS Secrets Manager(通过 CSI Driver 注入)。

📁 Java 示例:从 ConfigMap/Secret 加载 Spring Boot 配置

步骤 1:创建 ConfigMap 与 Secret(YAML)

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: appconfig
namespace: default
data:
application.properties: |
logging.level.com.example=DEBUG
spring.redis.host=redis-service
spring.redis.port=6379


# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: dbsecret
namespace: default
type: Opaque
data:
SPRING_DATASOURCE_URL: cG9zdGdyZXNxbC1zZXJ2aWNlOjU0MzIvZGJfZGVtbw== # base64 "postgresql-service:5432/db_demo"
SPRING_DATASOURCE_USERNAME: YWRtaW4= # "admin"
SPRING_DATASOURCE_PASSWORD: cGFzc3dvcmQxMjM= # "password123"

步骤 2:在 Deployment 中挂载为 Volume(推荐)或环境变量

spec:
containers:
name: springbootapp
image: registry.example.com/myapp:1.3.0
envFrom:
configMapRef:
name: appconfig
secretRef:
name: dbsecret
volumeMounts:
name: configvolume
mountPath: /app/config
readOnly: true
volumes:
name: configvolume
configMap:
name: appconfig

步骤 3:Java 代码优雅读取(无需改动)

Spring Boot 自动支持:

  • envFrom.configMapRef → 注入为环境变量(SPRING_DATASOURCE_URL);
  • volumeMounts → 挂载为文件(/app/config/application.properties);

@Component
public class ConfigLoader {

@Value("${spring.redis.host:localhost}")
private String redisHost; // 优先从 env,fallback 到 properties

@Value("${logging.level.com.example:INFO}")
private String logLevel;

@PostConstruct
public void init() {
System.out.println("📡 Redis host: " + redisHost);
System.out.println("📝 Log level: " + logLevel);
}
}

✅ 优势:配置变更后,只需 kubectl apply -f configmap.yaml,再滚动重启 Pod(或使用 Reloader 类工具),无需重新构建镜像。


五、Volume:Pod 的“持久化外挂硬盘” 💾

Pod 重启后,容器内文件系统(如 /tmp, /app/logs)会丢失。Volume 提供了Pod 层面的存储抽象,支持多种后端(本地磁盘、NFS、云盘、对象存储网关)。关键分类:

Volume 类型生命周期共享性典型用途
emptyDir 与 Pod 同生共死 同一 Pod 内容器共享 临时缓存、容器间文件交换
hostPath 节点磁盘路径 节点内共享 DaemonSet 日志采集(/var/log)
persistentVolumeClaim (PVC) 独立于 Pod,由管理员预置 PV 多 Pod(需 ReadWriteMany) 数据库、文件服务、AI 训练数据集

🧩 PVC/PV 模型:存储的“申请-分配”契约

#mermaid-svg-Ft8p5aJxuJsIKiSP{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Ft8p5aJxuJsIKiSP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Ft8p5aJxuJsIKiSP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Ft8p5aJxuJsIKiSP .error-icon{fill:#552222;}#mermaid-svg-Ft8p5aJxuJsIKiSP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Ft8p5aJxuJsIKiSP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Ft8p5aJxuJsIKiSP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Ft8p5aJxuJsIKiSP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Ft8p5aJxuJsIKiSP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Ft8p5aJxuJsIKiSP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Ft8p5aJxuJsIKiSP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Ft8p5aJxuJsIKiSP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Ft8p5aJxuJsIKiSP .marker.cross{stroke:#333333;}#mermaid-svg-Ft8p5aJxuJsIKiSP svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Ft8p5aJxuJsIKiSP p{margin:0;}#mermaid-svg-Ft8p5aJxuJsIKiSP .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Ft8p5aJxuJsIKiSP .cluster-label text{fill:#333;}#mermaid-svg-Ft8p5aJxuJsIKiSP .cluster-label span{color:#333;}#mermaid-svg-Ft8p5aJxuJsIKiSP .cluster-label span p{background-color:transparent;}#mermaid-svg-Ft8p5aJxuJsIKiSP .label text,#mermaid-svg-Ft8p5aJxuJsIKiSP span{fill:#333;color:#333;}#mermaid-svg-Ft8p5aJxuJsIKiSP .node rect,#mermaid-svg-Ft8p5aJxuJsIKiSP .node circle,#mermaid-svg-Ft8p5aJxuJsIKiSP .node ellipse,#mermaid-svg-Ft8p5aJxuJsIKiSP .node polygon,#mermaid-svg-Ft8p5aJxuJsIKiSP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Ft8p5aJxuJsIKiSP .rough-node .label text,#mermaid-svg-Ft8p5aJxuJsIKiSP .node .label text,#mermaid-svg-Ft8p5aJxuJsIKiSP .image-shape .label,#mermaid-svg-Ft8p5aJxuJsIKiSP .icon-shape .label{text-anchor:middle;}#mermaid-svg-Ft8p5aJxuJsIKiSP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Ft8p5aJxuJsIKiSP .rough-node .label,#mermaid-svg-Ft8p5aJxuJsIKiSP .node .label,#mermaid-svg-Ft8p5aJxuJsIKiSP .image-shape .label,#mermaid-svg-Ft8p5aJxuJsIKiSP .icon-shape .label{text-align:center;}#mermaid-svg-Ft8p5aJxuJsIKiSP .node.clickable{cursor:pointer;}#mermaid-svg-Ft8p5aJxuJsIKiSP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Ft8p5aJxuJsIKiSP .arrowheadPath{fill:#333333;}#mermaid-svg-Ft8p5aJxuJsIKiSP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Ft8p5aJxuJsIKiSP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Ft8p5aJxuJsIKiSP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ft8p5aJxuJsIKiSP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Ft8p5aJxuJsIKiSP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ft8p5aJxuJsIKiSP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Ft8p5aJxuJsIKiSP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Ft8p5aJxuJsIKiSP .cluster text{fill:#333;}#mermaid-svg-Ft8p5aJxuJsIKiSP .cluster span{color:#333;}#mermaid-svg-Ft8p5aJxuJsIKiSP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Ft8p5aJxuJsIKiSP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Ft8p5aJxuJsIKiSP rect.text{fill:none;stroke-width:0;}#mermaid-svg-Ft8p5aJxuJsIKiSP .icon-shape,#mermaid-svg-Ft8p5aJxuJsIKiSP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ft8p5aJxuJsIKiSP .icon-shape p,#mermaid-svg-Ft8p5aJxuJsIKiSP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Ft8p5aJxuJsIKiSP .icon-shape .label rect,#mermaid-svg-Ft8p5aJxuJsIKiSP .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ft8p5aJxuJsIKiSP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Ft8p5aJxuJsIKiSP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Ft8p5aJxuJsIKiSP :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

creates

provisions

binds to

uses

mounts

User

PersistentVolumeClaim

Admin

PersistentVolume

Deployment

Container

🌐 官方文档深度解析:Persistent Volumes 详细说明了 StorageClass、Dynamic Provisioning、Access Modes(RWO/ROX/RWX)等核心概念。

🐘 Java 示例:Spring Boot 使用 PVC 存储上传文件

假设已创建 PVC upload-pvc,挂载至 /data/uploads:

@RestController
public class FileUploadController {

private final Path uploadRoot = Paths.get("/data/uploads");

@PostConstruct
public void init() {
try {
Files.createDirectories(uploadRoot);
} catch (IOException e) {
throw new RuntimeException("Failed to create upload dir", e);
}
}

@PostMapping("/upload")
public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file) {
try {
String filename = System.currentTimeMillis() + "_" + file.getOriginalFilename();
Path dest = uploadRoot.resolve(filename);
file.transferTo(dest);
return ResponseEntity.ok("Uploaded: " + filename);
} catch (Exception e) {
return ResponseEntity.status(500).body("Upload failed: " + e.getMessage());
}
}
}

Deployment 挂载片段:

volumeMounts:
name: uploadvolume
mountPath: /data/uploads
volumes:
name: uploadvolume
persistentVolumeClaim:
claimName: uploadpvc


六、Namespace:集群内的“虚拟子集群” 🏙️

Namespace 是 Kubernetes 的逻辑分组与资源隔离机制。它不提供网络或运行时隔离(需配合 NetworkPolicy、RuntimeClass),但能实现:

  • ✅ 资源配额(ResourceQuota):限制 CPU/Memory 总量;
  • ✅ 限额范围(LimitRange):设置 Pod 默认 Request/Limit;
  • ✅ 访问控制(RBAC):RoleBinding 作用于 Namespace 级;
  • ✅ 环境划分:dev / staging / prod。

📊 Namespace 关系图:资源作用域层级

#mermaid-svg-Ox6KnZbFtTN7nCug{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Ox6KnZbFtTN7nCug .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Ox6KnZbFtTN7nCug .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Ox6KnZbFtTN7nCug .error-icon{fill:#552222;}#mermaid-svg-Ox6KnZbFtTN7nCug .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Ox6KnZbFtTN7nCug .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Ox6KnZbFtTN7nCug .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Ox6KnZbFtTN7nCug .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Ox6KnZbFtTN7nCug .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Ox6KnZbFtTN7nCug .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Ox6KnZbFtTN7nCug .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Ox6KnZbFtTN7nCug .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Ox6KnZbFtTN7nCug .marker.cross{stroke:#333333;}#mermaid-svg-Ox6KnZbFtTN7nCug svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Ox6KnZbFtTN7nCug p{margin:0;}#mermaid-svg-Ox6KnZbFtTN7nCug .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Ox6KnZbFtTN7nCug .cluster-label text{fill:#333;}#mermaid-svg-Ox6KnZbFtTN7nCug .cluster-label span{color:#333;}#mermaid-svg-Ox6KnZbFtTN7nCug .cluster-label span p{background-color:transparent;}#mermaid-svg-Ox6KnZbFtTN7nCug .label text,#mermaid-svg-Ox6KnZbFtTN7nCug span{fill:#333;color:#333;}#mermaid-svg-Ox6KnZbFtTN7nCug .node rect,#mermaid-svg-Ox6KnZbFtTN7nCug .node circle,#mermaid-svg-Ox6KnZbFtTN7nCug .node ellipse,#mermaid-svg-Ox6KnZbFtTN7nCug .node polygon,#mermaid-svg-Ox6KnZbFtTN7nCug .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Ox6KnZbFtTN7nCug .rough-node .label text,#mermaid-svg-Ox6KnZbFtTN7nCug .node .label text,#mermaid-svg-Ox6KnZbFtTN7nCug .image-shape .label,#mermaid-svg-Ox6KnZbFtTN7nCug .icon-shape .label{text-anchor:middle;}#mermaid-svg-Ox6KnZbFtTN7nCug .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Ox6KnZbFtTN7nCug .rough-node .label,#mermaid-svg-Ox6KnZbFtTN7nCug .node .label,#mermaid-svg-Ox6KnZbFtTN7nCug .image-shape .label,#mermaid-svg-Ox6KnZbFtTN7nCug .icon-shape .label{text-align:center;}#mermaid-svg-Ox6KnZbFtTN7nCug .node.clickable{cursor:pointer;}#mermaid-svg-Ox6KnZbFtTN7nCug .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Ox6KnZbFtTN7nCug .arrowheadPath{fill:#333333;}#mermaid-svg-Ox6KnZbFtTN7nCug .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Ox6KnZbFtTN7nCug .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Ox6KnZbFtTN7nCug .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ox6KnZbFtTN7nCug .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Ox6KnZbFtTN7nCug .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ox6KnZbFtTN7nCug .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Ox6KnZbFtTN7nCug .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Ox6KnZbFtTN7nCug .cluster text{fill:#333;}#mermaid-svg-Ox6KnZbFtTN7nCug .cluster span{color:#333;}#mermaid-svg-Ox6KnZbFtTN7nCug div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Ox6KnZbFtTN7nCug .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Ox6KnZbFtTN7nCug rect.text{fill:none;stroke-width:0;}#mermaid-svg-Ox6KnZbFtTN7nCug .icon-shape,#mermaid-svg-Ox6KnZbFtTN7nCug .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ox6KnZbFtTN7nCug .icon-shape p,#mermaid-svg-Ox6KnZbFtTN7nCug .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Ox6KnZbFtTN7nCug .icon-shape .label rect,#mermaid-svg-Ox6KnZbFtTN7nCug .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ox6KnZbFtTN7nCug .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Ox6KnZbFtTN7nCug .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Ox6KnZbFtTN7nCug :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

Cluster

Namespace: dev

Namespace: staging

Namespace: prod

Deployment: myapp

Service: myapp

ConfigMap: app-config

Deployment: myapp

Service: myapp

ConfigMap: app-config

🔑 关键事实:default Namespace 是默认上下文;kube-system 专供系统组件(kube-dns, metrics-server);kube-public 供所有用户读取(如集群 CA 证书)。

Java 客户端操作命名空间:

// 列出所有 Namespace
client.namespaces().list().getItems().forEach(ns ->
System.out.println("🌍 Namespace: " + ns.getMetadata().getName())
);

// 在指定 Namespace 下操作资源
client.apps().deployments().inNamespace("staging").list();


七、RBAC:权限的“门禁系统” 🚪

Kubernetes 默认启用 RBAC(Role-Based Access Control)。它通过四类对象定义“谁(Subject)在什么范围(Namespace/Cluster)对什么资源(Resource)能做什么(Verb)”:

对象作用域关联关系
Role Namespace 级别 RoleBinding 引用
ClusterRole 集群全局 ClusterRoleBinding 引用
RoleBinding 将 Role 绑定到 User/Group/ServiceAccount 作用于单一 Namespace
ClusterRoleBinding 将 ClusterRole 绑定到主体 作用于整个集群

🛡️ Java 示例:为 Spring Boot 应用 ServiceAccount 授权访问 ConfigMap

生产环境不建议应用 Pod 使用 default ServiceAccount(权限过大)。应创建专用账号并授予最小权限:

步骤 1:创建 ServiceAccount

apiVersion: v1
kind: ServiceAccount
metadata:
name: myappsa
namespace: default

步骤 2:定义 Role(仅允许读取 ConfigMap)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: configreader
namespace: default
rules:
apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]

步骤 3:绑定 Role 到 ServiceAccount

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: readconfigmaps
namespace: default
subjects:
kind: ServiceAccount
name: myappsa
namespace: default
roleRef:
kind: Role
name: configreader
apiGroup: rbac.authorization.k8s.io

步骤 4:在 Deployment 中指定 ServiceAccount

spec:
serviceAccountName: myappsa
containers:
name: springbootapp
image: registry.example.com/myapp:1.3.0

步骤 5:Java 代码安全读取 ConfigMap

@Service
public class ConfigMapReader {

private final KubernetesClient client;

public ConfigMapReader(KubernetesClient client) {
this.client = client;
}

public String getConfigValue(String key) {
try {
ConfigMap configMap = client.configMaps()
.inNamespace("default")
.withName("app-config")
.get();
return configMap.getData().get(key);
} catch (KubernetesClientException e) {
// 权限不足时抛出 Forbidden,可降级处理
if (e.getCode() == 403) {
return "DEFAULT_VALUE";
}
throw e;
}
}
}

✅ 效果:即使攻击者攻破应用容器,也无法删除 Secret 或调度新 Pod——权限被严格限制。


八、Ingress:七层 HTTP/HTTPS 路由的“智能网关” 🌐

Service 提供四层(TCP/UDP)负载均衡,而 Ingress 提供七层(HTTP Host/Path、TLS 终止)路由能力,是微服务网关(如 Spring Cloud Gateway、Kong)的前置入口。

🌐 Ingress 工作原理简图

#mermaid-svg-HB7ACY9bo6P9q9JA{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HB7ACY9bo6P9q9JA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HB7ACY9bo6P9q9JA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HB7ACY9bo6P9q9JA .error-icon{fill:#552222;}#mermaid-svg-HB7ACY9bo6P9q9JA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HB7ACY9bo6P9q9JA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HB7ACY9bo6P9q9JA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HB7ACY9bo6P9q9JA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HB7ACY9bo6P9q9JA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HB7ACY9bo6P9q9JA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HB7ACY9bo6P9q9JA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HB7ACY9bo6P9q9JA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HB7ACY9bo6P9q9JA .marker.cross{stroke:#333333;}#mermaid-svg-HB7ACY9bo6P9q9JA svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HB7ACY9bo6P9q9JA p{margin:0;}#mermaid-svg-HB7ACY9bo6P9q9JA .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-HB7ACY9bo6P9q9JA .cluster-label text{fill:#333;}#mermaid-svg-HB7ACY9bo6P9q9JA .cluster-label span{color:#333;}#mermaid-svg-HB7ACY9bo6P9q9JA .cluster-label span p{background-color:transparent;}#mermaid-svg-HB7ACY9bo6P9q9JA .label text,#mermaid-svg-HB7ACY9bo6P9q9JA span{fill:#333;color:#333;}#mermaid-svg-HB7ACY9bo6P9q9JA .node rect,#mermaid-svg-HB7ACY9bo6P9q9JA .node circle,#mermaid-svg-HB7ACY9bo6P9q9JA .node ellipse,#mermaid-svg-HB7ACY9bo6P9q9JA .node polygon,#mermaid-svg-HB7ACY9bo6P9q9JA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HB7ACY9bo6P9q9JA .rough-node .label text,#mermaid-svg-HB7ACY9bo6P9q9JA .node .label text,#mermaid-svg-HB7ACY9bo6P9q9JA .image-shape .label,#mermaid-svg-HB7ACY9bo6P9q9JA .icon-shape .label{text-anchor:middle;}#mermaid-svg-HB7ACY9bo6P9q9JA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HB7ACY9bo6P9q9JA .rough-node .label,#mermaid-svg-HB7ACY9bo6P9q9JA .node .label,#mermaid-svg-HB7ACY9bo6P9q9JA .image-shape .label,#mermaid-svg-HB7ACY9bo6P9q9JA .icon-shape .label{text-align:center;}#mermaid-svg-HB7ACY9bo6P9q9JA .node.clickable{cursor:pointer;}#mermaid-svg-HB7ACY9bo6P9q9JA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HB7ACY9bo6P9q9JA .arrowheadPath{fill:#333333;}#mermaid-svg-HB7ACY9bo6P9q9JA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HB7ACY9bo6P9q9JA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HB7ACY9bo6P9q9JA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HB7ACY9bo6P9q9JA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HB7ACY9bo6P9q9JA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HB7ACY9bo6P9q9JA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HB7ACY9bo6P9q9JA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HB7ACY9bo6P9q9JA .cluster text{fill:#333;}#mermaid-svg-HB7ACY9bo6P9q9JA .cluster span{color:#333;}#mermaid-svg-HB7ACY9bo6P9q9JA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HB7ACY9bo6P9q9JA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HB7ACY9bo6P9q9JA rect.text{fill:none;stroke-width:0;}#mermaid-svg-HB7ACY9bo6P9q9JA .icon-shape,#mermaid-svg-HB7ACY9bo6P9q9JA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HB7ACY9bo6P9q9JA .icon-shape p,#mermaid-svg-HB7ACY9bo6P9q9JA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HB7ACY9bo6P9q9JA .icon-shape .label rect,#mermaid-svg-HB7ACY9bo6P9q9JA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HB7ACY9bo6P9q9JA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HB7ACY9bo6P9q9JA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HB7ACY9bo6P9q9JA :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

routes by host/path

routes by host/path

terminates TLS

Internet User

Ingress Controllere.g. nginx-ingress, traefik

Service: api-service

Service: web-service

Secret: tls-cert

🔑 关键点:

  • Ingress 是资源对象(YAML 定义路由规则);
  • Ingress Controller 是运行在集群中的反向代理程序(需单独部署);
  • TLS 证书必须存为 Secret,并在 Ingress 中引用。

🐘 Java 示例:Spring Boot 应用暴露 HTTPS 入口

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myappingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
hosts:
myapp.example.com
secretName: myapptlssecret # 必须提前创建
rules:
host: myapp.example.com
http:
paths:
path: /api/
pathType: Prefix
backend:
service:
name: apiservice
port:
number: 8080
path: /
pathType: Prefix
backend:
service:
name: webservice
port:
number: 80

🌐 深入掌握:Ingress 官方文档 包含了多种 Ingress Controller 的安装与配置指南。


九、构建你的 K8s 知识框架:一张图看懂核心关系 🧭

现在,我们将所有核心对象整合为一张动态演化的知识网络图,揭示它们如何协同构成一个健壮的云原生系统:

渲染错误: Mermaid 渲染失败: Lexical error on line 14. Unrecognized text. …J subgraph “Observability & Res ———————^

🌟 框架精髓总结:

  • 声明式为魂:所有操作始于 kubectl apply -f xxx.yaml 或 Java Client 的 create();
  • 控制器模式为骨:Deployment → ReplicaSet → Pod 形成三级控制链,保障终态一致;
  • 服务网络为脉:Service 提供稳定入口,Ingress 实现七层智能路由;
  • 配置与存储为血:ConfigMap/Secret 解耦配置,Volume/PVC 解耦状态;
  • 安全与隔离为盾:Namespace 划分环境,RBAC 控制权限,NetworkPolicy 限制流量。

  • 十、结语:从理解到驾驭,Java 工程师的 K8s 进阶之路 🚀

    Kubernetes 不是一个待 memorize 的命令清单,而是一套关于分布式系统可靠性的设计哲学。当你看到一个 kubectl get pods 的输出,眼中浮现的不应只是 Running 状态,而是背后 kube-scheduler 的调度决策、kubelet 的容器生命周期管理、CoreDNS 的服务发现、kube-proxy 的流量转发……这种“穿透式理解”,正是云原生时代高级 Java 工程师的核心竞争力。

    本文所涉 Java 示例均基于 Fabric8 Kubernetes Client(v6.x),它完美映射 Kubernetes 原生 API,是 Spring Boot 与 K8s 深度集成的事实标准。你无需成为 Go 语言专家,也能用 Java 编写出生产级的 Operator、CI/CD 插件、自助式平台前端。

    最后,请记住这句箴言:

    “Kubernetes is not about containers. It’s about building reliable systems out of unreliable parts.” —— Brendan Burns, Co-creator of Kubernetes

    愿你在云原生的星辰大海中,既做踏实的造船者,也做勇敢的远航人 🌊⛵。

    🌐 延伸阅读推荐(均实测可访问):

    • Kubernetes 官方文档中文版 —— 最权威、最及时的知识源头
    • Spring Boot with Kubernetes —— Spring 官方对 K8s 集成的完整指南
    • Kubernetes Patterns —— 用模式语言解构 K8s 最佳实践(含 Java 示例)

    Happy K8s-ing! 🎉


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

    赞(0)
    未经允许不得转载:171主机测评 » Kubernetes - 核心资源对象的关系梳理,构建 K8s 知识框架
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址