K8s 网络分层全景:OSI 七层视角下看清 Pod IP、Service、Ingress 与组件分工

为什么 K8s 网络这么难懂 因为 K8s 的"网络"根本不是一张网,而是多张网叠在一起,而且不同组件在不同的协议层各干各的。以本文的 kind 集群为例,从外到内是四层: 层 网段(本文 kind 集群实测) 谁的"地盘" 物理机/宿主机 192.168.8.26 (debian 宿主机) 真实网卡(kind 之外的真实世界) 节点容器(kind 特有) 172.18.0.0/16 (节点 IP:172.18.0.2/3/4) kind 节点 = Docker 容器,这是 Docker 网络分给节点容器的 IP,不是物理机 IP Pod 网段 10.244.0.0/16 (Pod IP:10.244.1.x、10.244.2.x) 集群内每个 Pod 一个 IP(CNI 的虚拟网) Service 网段 10.96.0.0/16 (ClusterIP:10.96.x.x) 虚拟的"服务名"入口 ⚠️ 新手提示:kind 里看到的 172.18.0.x 是"节点容器"的 IP,不是物理机 IP——kind 的"容器即节点"让节点本身就是 Docker 容器(网络栈因此多一层)。kubeadm/生产集群没有这一层:节点就是物理机/虚拟机,节点 IP = 物理机 IP(如 192.168.8.26)。看下面的图就清楚了。 再加上:CoreDNS 在 L7 解析服务名、kube-proxy 在 L4 做转发、kindnet/CNI 在 L3 管 Pod IP 和路由、Ingress 在 L7 做域名路由——初学者拿着传统网络的知识套进来,发现"Pod 的 IP 不是 DNS 服务器的 IP"、“Service 的 IP 没有网卡”,自然就绕晕了。 ...

五月 22, 2024 · 10 分钟 · 1921 字 · yaomingye

K8s 组件职责全景:一条 kubectl 命令背后的控制面与节点协作

谁在干活:kubectl 命令背后的组件分工 系列前十几篇,集群一直当"黑盒"用—— kubectl apply 一个清单,应用就起来了,至于是谁把这件事做完的,没拆开看过。对兼职运维来说,这个黑盒必须拆开:排障的第一问不是"怎么修",而是"哪一环出了问题、该看谁"——Pod 一直 Pending 是调度的问题还是资源的问题?探针失败是应用的问题还是 kubelet 的问题?服务访问不通是 Service 配置还是网络插件?组件职责 = 排障归属地图。 这篇用一条生产里每天都在用的命令( kubectl apply )当主线案例,把控制面四个组件和节点四个组件的职责、工作流程讲清楚,并用 kind 集群上的实测事件证明"谁在干活"。理论向,不做源码级剖析——兼职运维只需要知道"每个组件干什么、出了事找谁"。 1. 组件全景:控制面管"想",节点管"做" K8s 的所有组件分成两组,职责边界非常清晰: 控制面(control plane):负责决策——存状态、做调度、收敛声明,全在控制面; 节点(node):负责执行——拉镜像、起容器、转发流量、管网络,全在节点。 %% K8s 组件全景: 控制面 4 件套 + 节点 4 件套 flowchart TD subgraph CP["控制面(决策)"] API["kube-apiserver\n唯一入口 + 收费站"] ETCD[("etcd\n唯一真相存储")] SCH["kube-scheduler\n给新 Pod 找节点"] CM["kube-controller-manager\n控制器集合(把声明收敛成动作)"] end subgraph N1["节点 learn-worker"] KL1["kubelet\nPod 生命周期 + 探针"] KP1["kube-proxy\nService 转发规则"] CT1["containerd\n容器运行时"] CNI1["kindnet\nPod 网络 + IP"] end subgraph N2["节点 learn-worker2"] KL2["kubelet"] KP2["kube-proxy"] CT2["containerd"] CNI2["kindnet"] end API --> ETCD API <-->|"watch/上报"| KL1 API <-->|"watch/上报"| KL2 API <-->|"watch"| KP1 API <-->|"watch"| KP2 API <-->|"watch"| SCH API <-->|"watch"| CM style API fill:#0f172a,stroke:#3b82f6,stroke-width:2.5px,color:#ffffff,font-weight:bold style SCH fill:#0f172a,stroke:#3b82f6,stroke-width:2.5px,color:#ffffff,font-weight:bold style CM fill:#0f172a,stroke:#3b82f6,stroke-width:2.5px,color:#ffffff,font-weight:bold style ETCD fill:#052e16,stroke:#16a34a,stroke-width:2px,color:#ffffff,font-weight:bold style KL1 fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#ffffff style KL2 fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#ffffff style KP1 fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#ffffff style KP2 fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#ffffff style CT1 fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#ffffff style CT2 fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#ffffff style CNI1 fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#ffffff style CNI2 fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#ffffff 在 kind 里这些组件都是真实运行的 Pod(生产 K8s 同款,只是 kind 把它们跑在 Docker 里)。看它们: ...

二月 22, 2024 · 5 分钟 · 869 字 · yaomingye

为什么是 K8s:传统微服务运维痛点与 K8s 的设计回应

先回答为什么,再谈怎么用 这是系列的自我批评篇,也是全系列的导航页。回看前十三篇文章,我发现一个通病:每篇都把"K8s 怎么做"讲得很细——清单、命令、预期输出、踩坑,可复现性拉满;但"为什么必须这么做“几乎没讲——没有 K8s 之前,同样的流程是怎么跑的?痛点在哪?K8s 的机制到底回应了什么? 作为 Java 开发者,你手里握着最好的参照系:Spring Cloud 时代的微服务。Nacos 配置中心、Eureka 注册中心、停机发布、人工巡检——这些痛点我们亲历过。这篇就用它当镜子,逐话题对照 K8s 的设计回应,每个话题都附上对应教程的链接——先看这篇理解"为什么”,再点链接去"怎么做"。 📌 系列结构:环境搭建见 kind 集群实战,开发者总览见 Java 开发工程师的 K8s 职责清单。 1. 总设计思想:声明式 + 控制回路 K8s 所有机制的地基是两个思想,先立起来: 声明式(Declarative):你不说"怎么做到",只说"我要什么"。传统方式是命令式——“把包拷到这台机器、改这个配置、重启这个进程”;K8s 方式是"这是我想要的最终状态(YAML),你来实现"。 控制回路(Control Loop):K8s 的控制器永远在循环"当前状态 vs 期望状态"——不一致就动手收敛,一致就闲着。这跟空调温控一个原理:设定 26 度(期望),温度计(当前),制冷/制热(动作),周而复始。 %% K8s 核心设计思想: 声明式期望 + 控制回路收敛 flowchart LR DESIRED["期望状态\nkubectl apply 提交的 YAML"] CTRL["控制器\n对比 期望 vs 当前"] ACTUAL["当前状态\n集群里的实际情况"] ACT["执行动作\n创建/重启/扩容/摘流"] DESIRED --> CTRL ACTUAL -->|"读取"| CTRL CTRL -->|"不一致 →"| ACT ACT -->|"改变"| ACTUAL CTRL -.->|"一致 → 空闲"| CTRL style DESIRED fill:#0f172a,stroke:#3b82f6,stroke-width:2.5px,color:#ffffff,font-weight:bold style CTRL fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#ffffff style ACTUAL fill:#052e16,stroke:#16a34a,stroke-width:2px,color:#ffffff,font-weight:bold style ACT fill:#052e16,stroke:#16a34a,stroke-width:2px,color:#ffffff,font-weight:bold 这个思想替代了什么:传统运维的"巡检 + 手动修复"是人肉控制回路——人发现、人决策、人执行,慢且会忘。K8s 把回路自动化了。下面七个话题,全是这个思想的展开。 ...

二月 16, 2024 · 2 分钟 · 419 字 · yaomingye

PLG 可观测栈生产化:Prometheus/Loki/Grafana 上线前必须补的参数清单

PLG 能跑 ≠ 能生产,这 40 个参数决定它会不会炸 第 1 步:目标——别把"能跑"当成"能上线" 某开发者第一次搭 Prometheus + Loki + Grafana 的时候,docker-compose 一把梭,数据能出图、日志能搜到,觉得"这不就完了吗"。 直到有一天:磁盘写满、Loki 摄入速率爆了、Prometheus 查询超时、Grafana 裸奔在公网被扫——才意识到玩具和生产是两回事。 这篇把 PLG 生产化的参数和注意事项一次性讲透,分四块: 组件 生产化核心问题 Prometheus 数据存多久?查询会不会拖垮?挂了怎么办? Loki 日志会不会把磁盘写爆?摄入限额?标签会不会爆炸? Promtail 标签设计红线 + 采集可靠性 Grafana 认证、数据库、配置管理、备份 📌 定位:写给后端开发兼职运维的人——不追求架构极客,只求上线后别半夜被磁盘告警叫醒。 第 2 步:前置——先理解 PLG 各自的生产"命门" 四件套的生产风险完全不一样,先建立直觉: flowchart LR APP["应用/主机"] -->|"指标 scrape"| P["Prometheus时序数据库"] APP -->|"日志 push"| PT["Promtail日志采集"] PT -->|"HTTP push"| L["Loki日志存储"] P --> G["Grafana可视化"] L --> G classDef root fill:#0f172a,stroke:#3b82f6,stroke-width:2.5px,color:#bfdbfe,font-weight:bold; classDef process fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#e5e7eb; classDef data fill:#052e16,stroke:#16a34a,stroke-width:2px,color:#bbf7d0,font-weight:bold; class APP root; class P,L data; class PT,G process; 组件 生产命门 典型事故 Prometheus 内存(TSDB 缓存)、磁盘(时序数据)、查询并发 OOM、磁盘写满、查询拖垮 Loki 磁盘(日志量)、摄入速率、流数量(标签基数) 磁盘爆、摄入拒绝、流爆炸 Promtail 标签设计、位置文件、网络缓冲 流爆炸、重启重采日志 Grafana 认证、数据库、配置漂移 裸奔被入侵、配置丢失 第 3 步:Prometheus 生产参数——存储、查询、高可用 3.1 数据保留期(默认 15 天,必须显式设置) # docker-compose 启动参数 prometheus: command: - '--storage.tsdb.retention.time=30d' # 按时间保留(推荐) - '--storage.tsdb.retention.size=50GB' # 按大小保留(和上面二选一或都用) 为什么:默认 15 天,生产一般要 30 ~ 90 天。但保留期越长磁盘越大——50GB 磁盘 + 30 天保留,要提前算好每台机器的指标量(一般每 target 每小时几百 KB,几十个 target 一天约 1 ~ 2GB)。 ...

十一月 12, 2023 · 5 分钟 · 904 字 · yaomingye

微服务架构下 nginx 运维:后端开发如何借 AI 守住流量入口

nginx 不再是"服务器"了,它是你家微服务的门卫 第 1 步:目标——搞懂 nginx 在微服务里到底干嘛 先说个某开发者的真实转变。以前写单体应用,nginx 的活就是:把静态资源甩给浏览器,把动态请求转发给 Tomcat。配置嘛,抄一份改改就能跑。 后来上了微服务,Spring Cloud Gateway 成了统一入口,nginx 的位置就尴尬了——它既不用管静态资源,也不直接碰业务,但它卡在所有流量的最前面。 浏览器 ↓ nginx ← 我们这篇的主角:流量大门 ↓ Spring Cloud Gateway ← 路由/鉴权/限流 ↓ 微服务 A 微服务 B 微服务 C nginx 在这条链路上的职责变成了: 职责 说明 TLS 终结 HTTPS 证书在 nginx 上解掉,网关不用管证书 流量分发 把请求转发给 gateway(可能不止一个实例) 连接管理 复用客户端连接,减少网关压力 基础防护 隐藏版本号、限流、挡扫描器 日志入口 记录所有进站请求(网关日志不覆盖 nginx 这一层) 📌 关键认知:nginx 挂 = 整个系统挂。它前面没有别的挡箭牌,所以 nginx 的配置质量直接决定入口的稳定性。这也是为什么值得花一篇的篇幅讲清楚。 这篇的目标很实在:让你(或让 AI 代你)改 nginx 配置时,知道哪些是命门、哪些是锦上添花,别把入口配成瓶颈。 第 2 步:前置条件——先弄懂 nginx 的"体力"从哪来 动手配之前,必须理解 nginx 的工作模型。它跟 Tomcat 那种"一连接一线程"完全不同: ...

十一月 10, 2023 · 5 分钟 · 931 字 · yaomingye

给 1核2G 的阿里云 ECS 换上免费 HTTPS:从装证书到踩坑全记录

博客裸奔 HTTP 大半年,我给它上了个免费锁 第 1 步:目标——让博客地址栏出现小锁 事情是这样的。某开发者的博客在阿里云 1核2G 的小 ECS 上跑了大半年,一直用 http://yaocat.cloud 裸奔。也不是没想过上 HTTPS,但总觉得"麻烦"、“要花钱”、“反正没人看”。 直到有天朋友发来一个链接,浏览器地址栏赫然一个大红叉:“不安全”。虽然博客确实没什么人看,但顶着这个红叉自己心里也膈应。 查了一圈发现:HTTPS 现在完全免费,Let’s Encrypt 发的证书不要钱,还能自动续期。那还等什么,搞它。 目标拆一下: 事项 说明 ① 申请免费证书 Let’s Encrypt,用 acme.sh 工具 ② nginx 配置挂载 配置从容器里挪出来,重建不丢 ③ HTTPS 配置 443 端口 + HTTP 自动跳转 ④ 顺带优化 gzip 压缩 + 静态缓存 第 2 步:前置条件——这台机器长什么样 先交代一下环境: 项 值 服务器 阿里云 ECS,1核2G,Debian 11 (bullseye) 网站 Docker 容器跑 nginx:alpine,挂载 /var/www/blog 域名 yaocat.cloud,已解析到服务器公网 IP 端口 80 已开(HTTP 正常访问) 动手前先确认两件事能不能通: ...

十一月 8, 2023 · 4 分钟 · 681 字 · yaomingye

Prometheus 告警体系搭建:从 Alertmanager 到 AI ChatOps 一条龙

告警别只发通知,让 AI 替你干活 第 1 步:目标——从"看面板"到"手机响" 上一篇把 Prometheus + Grafana 搭起来,指标也采进来了。但有个问题:指标不会自己说话。 某开发者当时的状态是:白天盯着 Grafana 面板看 CPU 曲线,晚上睡觉心里发毛——万一凌晨 3 点服务挂了,谁叫我? 这篇文章的目标很直白: ❌ 旧世界:出问题 → 用户投诉 → 你爬起来开电脑 → SSH → 查日志 → 修复 ✅ 新世界:出问题 → 手机响 → 聊天框里说"查一下" → AI 排查完给你结论 具体拆成三个里程碑: 里程碑 内容 产出 ① 告警规则 Prometheus 检测 CPU/内存/磁盘异常 8 条可用的告警规则 ② Alertmanager 告警去重分组、统一出口 一个能收敛告警的中枢 ③ ChatOps 告警 → webhook → AI → Telegram 手机上收告警 + 动嘴指挥 📌 前置知识:假设你已经跑通了上一篇的 Prometheus + Grafana + node-exporter,知道 up 、 rate() 这些基本 PromQL。 ...

十一月 6, 2023 · 5 分钟 · 1062 字 · yaomingye

RocketMQ 实战避坑指南:从消息丢失到高可用,9大核心问题一网打尽

RocketMQ 避坑全攻略 0. 前言 0.1 为什么写这篇博客 消息中间件是分布式系统的必修课——这话没错,但很多团队引入 MQ 的时候只看到了"解耦"和"削峰填谷"的好处,却没意识到它同时带来了消息丢失、重复消费、积压、顺序错乱等一系列新问题。坦白说,踩过这些坑的开发者不在少数。 某开发者在生产环境第一次遇到 RocketMQ 积压十几万条消息的时候,第一反应是重启消费者——结果毫无悬念地失败了。后来花了一整天排查,问题竟然只是消费逻辑里多了一个 Thread.sleep(200) 。这种教训值得记下来。 0.2 读者需要的基础知识 用过 RocketMQ(至少本地跑过 Demo,知道 Producer / Consumer / Topic / Broker 是什么) 知道什么是生产者、消费者、Topic、Broker、NameServer 了解基本的分布式系统概念(如 CAP、最终一致性) 0.3 文章结构说明 按"问题 → 原因 → 原理 → 解决方案"的结构展开,每个问题独立成章。读者可以按需跳读,也可以从头串下来形成体系。 0.4 一句话总结 本文不是教"怎么用",而是教"怎么用好、怎么避坑"。 默认配置在生产环境就是定时炸弹。 1. 消息丢失 消息丢失是 MQ 使用中最致命的问题之一——订单丢了就是资损,通知丢了就是客诉。先按链路拆解一下丢消息的三个位置。 1.1 丢失场景分类 flowchart TD start([消息发送]) --> prod{生产端是否可靠?} prod -->|网络超时| prodLoss[生产端丢失] prod -->|异步未回调| prodLoss prod -->|重试耗尽| prodLoss prod -->|发送成功| broker[Broker 存储] broker --> persist{持久化策略?} persist -->|异步刷盘| brokerLoss[Broker 端丢失] persist -->|异步复制| brokerLoss persist -->|磁盘故障| brokerLoss persist -->|同步落盘| consume[消费端拉取] consume --> ack{ACK 策略?} ack -->|自动提交| consLoss[消费端丢失] ack -->|并发异常| consLoss ack -->|手动确认成功| done([消息可靠送达]) classDef startEnd fill:#701a4c,stroke:#e11d48,stroke-width:2.5px,color:#fce7f3,font-weight:bold; classDef condition fill:#2a1147,stroke:#a855f7,stroke-width:2px,color:#ede9fe,font-weight:bold; classDef process fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#e5e7eb; classDef reject fill:#450a0a,stroke:#dc2626,stroke-width:2px,color:#fecaca,font-weight:bold; classDef data fill:#052e16,stroke:#16a34a,stroke-width:2px,color:#bbf7d0,font-weight:bold; class start,done startEnd; class prod,persist,ack condition; class prodLoss,brokerLoss,consLoss reject; class broker,consume process; 1.1.1 生产端丢失 场景 原因 网络超时 客户端以为发送成功,实际 Broker 未收到。网络抖动 + 超时配置不合理导致 异步发送未回调 producer.send(msg) 后直接 return,异常被吞掉 重试耗尽 RetryTimesWhenSendFailed 次数用完,消息被丢弃 1.1.2 Broker 端丢失 场景 原因 异步刷盘 消息写入 PageCache 后返回成功,但尚未落盘,断电即丢 主从异步复制 Master 宕机时 Slave 未同步到最新数据 磁盘故障 物理损坏导致已落盘数据不可恢复 1.1.3 消费端丢失 场景 原因 自动提交 Offset consumeMessageBatchMaxSize 拉了一批消息,自动 ACK 后业务处理失败 并发消费异常 多线程中某条消息处理失败,但整体无法回滚 1.2 原理深度剖析 1.2.1 存储架构 RocketMQ 的存储核心是 CommitLog(顺序写文件)+ ConsumeQueue(按 Topic+Queue 建索引)+ IndexFile(按 Key 查询)。所有消息先追加到 CommitLog,再异步构建 ConsumeQueue 索引。 ...

十一月 4, 2023 · 6 分钟 · 1239 字 · yaomingye

日终对账系统设计:CSV 字段对照、两轮比对算法与数据库设计

对账系统的三张表、两轮比对和七种差异 对账系统是支付服务的最后一道防线——回调可能丢、消息可能漏、金额可能错,这些不会自己暴露。每天拿渠道的官方记录和自己数据库里的记录对一遍,丢钱多钱才能发现。 本文从零梳理一个日终对账系统的设计:数据表怎么建、两渠道 CSV 字段怎么映射、算法怎么做才能既快又不依赖 JOIN。 一、对账系统的心智模型 对账就一句话:渠道说每天收了多少钱,我们说每天收了多少钱,两边对一下,不一致就逐笔查。 flowchart TD cron["@Scheduled 次日 10:30"] --> download["下载渠道对账单 CSV"] download --> parse["解析 CSV → 批量写入 recon_temp"] parse --> total_check{"总额校验:渠道总额 = 我方总额?"} total_check -->|"相等"| done["对平 ✅ 关闭批次"] total_check -->|"不等"| detail["逐笔对比(HashMap 撮合)"] detail --> result["差异写入 recon_result"] classDef startEnd fill:#701a4c,stroke:#e11d48,stroke-width:2.5px,color:#fce7f3,font-weight:bold classDef process fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#e5e7eb classDef condition fill:#2a1147,stroke:#a855f7,stroke-width:2px,color:#ede9fe,font-weight:bold classDef data fill:#052e16,stroke:#16a34a,stroke-width:2px,color:#bbf7d0,font-weight:bold class cron startEnd class download,parse,detail process class total_check condition class done data class result process 选择次日 10:30 触发是因为两家渠道的对账单都在次日 10 点前生成完毕——去早了拿不到文件。 ...

十一月 2, 2023 · 4 分钟 · 759 字 · yaomingye

微信支付 vs 支付宝:聚合支付渠道集成中的十一处暗坑

渠道集成的痛:微信和支付宝处处不一样 聚合支付系统要同时对接支付宝和微信支付。初看两边的官方文档,觉得差不多——都是「下单→拿凭证→前端拉起→回调通知」这个流程。真到写代码的时候才发现,每一步都不一样,甚至同是微信生态,App 和小程序之间还有差异。 这篇文章把两渠道在 SDK 选型、下单参数、签名机制、回调处理、退款流程、对账单格式六个环节的具体差异整理出来,顺便也记录微信 App 和小程序之间那几处让人想砸键盘的细节。 一、SDK 选型和核心对象 先看 SDK 本身的差异,这决定了后面所有代码怎么组织。 支付宝 微信支付 Maven artifact alipay-sdk-java:4.40.308.ALL wechatpay-java:0.2.17 核心对象 DefaultAlipayClient (就是 HTTP 客户端) RSAAutoCertificateConfig (配置 + 签名 + 证书管理) HTTP 层 自带老版 HttpClient 自带 OkHttp,可注入自定义实例 证书管理 无(公钥手动配) AutoCertificateService 自动下载平台证书 + 后台线程轮换 Service 封装 无,裸调 client.execute(request) AppService / JsapiService / RefundService 封装请求-响应对映 ⚠️ 新手提示:支付宝的 DefaultAlipayClient 就是个 HTTP 客户端,一行 new 就行。微信的 RSAAutoCertificateConfig 是重量级对象——创建时会初始化证书下载、后台轮询线程,要通过工厂 + Caffeine 缓存复用,别每次请求都 new。 两者最大的思维差异:支付宝把 SDK 当 HTTP 工具用,微信把 SDK 当基础设施用。 ...

十月 31, 2023 · 4 分钟 · 641 字 · yaomingye
Cat Radio