Spring Boot 容器化与配置注入:多阶段构建 + ConfigMap/Secret 实战

Spring Boot 上 K8s 的第一课:打包镜像,注入配置 前面三篇用 nginx 把集群、Deployment、Service/Ingress 都打通了,但从这一篇开始,画风要变——主角换成真实的 Spring Boot 应用。毕竟我们是 Java 开发者,最终上云(ACK/AWS)跑的是自己的微服务,不是 nginx。这篇完成两件事:把 Spring Boot 应用容器化(多阶段构建 + 瘦身),再把配置从代码里搬到集群里(ConfigMap/Secret 注入)。学完你就掌握了"镜像一份,配置到处变"的核心玩法。 📌 前置知识:建议先读本系列前三篇(kind 集群搭建、Deployment 实战、Service/Ingress 实战),本文的操作都在同一套 kind 集群上进行,镜像预载( kind load )的原理不再展开。 这次要做什么 目标:把一个真实 Spring Boot 应用部署进 kind 集群,配置由集群注入 产出:多阶段构建的镜像 + ConfigMap/Secret 注入的配置 + 验证"配置覆盖代码默认值" 主角:k8s-demo-app(Spring Boot 3.3.5 / Java 17) 主角应用很小但五脏俱全:/api/hello 返回配置值和当前 Pod 名,Actuator 暴露健康检查端点(为下篇探针做准备),内置优雅停机配置(为下下篇做准备)。 前置条件 项 本次实测 集群 kind learn (1 主 2 从,K8s v1.36.1) 工具 docker + kubectl,宿主机 Docker 已配代理 网络 国内环境:构建期依赖下载走代理,镜像预载用 kind load 第1步:一个真实的 Spring Boot 应用 工程结构: ...

十一月 22, 2023 · 4 分钟 · 683 字 · yaomingye

Kubernetes Service 与 Ingress 实战:四种暴露方式从内到外全打通

让集群里的应用被外面访问到:Service 与 Ingress 四连击 应用部署进集群只是第一步——怎么让"别人"访问到它才是日常。这个"别人"可能是集群里的另一个服务(微服务互调),可能是集群外的机器,也可能是互联网上的用户。K8s 用四种递进的暴露方式回答这个问题:ClusterIP → NodePort → LoadBalancer → Ingress。 这篇文章完整记录在 kind 一主二从集群上把这四种方式逐一打通的实战过程:每个阶段的命令、预期输出、原理,以及真实踩过的五个坑。跟着做一遍,你对"服务发现和流量入口"的理解就成型了——这也是日后上阿里云 ACK 时每天都要面对的东西。 📌 前置知识:需要已有一个 kind 集群,并且集群里有一个跑着的 Deployment(本文沿用上一篇实战部署的 nginx-demo ,5 副本,镜像 nginx:1.27)。国内网络环境需要宿主机 Docker 配好代理(见本系列第一篇)。 这次要做什么 目标:把 nginx-demo 从"只有集群内可见"逐步暴露到"域名可访问" 阶段:ClusterIP(集群内) → NodePort(节点) → LoadBalancer(模拟公网) → Ingress(域名路由) 收获:理解 Service 的选择器/Endpoints/负载均衡,以及 Ingress 的 L7 路由 概念热身:四种方式各解决什么(先建立直觉再看图) 读者此刻一定会问:ClusterIP、NodePort 是什么?为什么要四种方式?——一句话:一个服务从"集群内可见"到"公网域名可访问",每向外暴露一层,就多一种方式。顺着"我想让谁访问"这个需求递进,四个概念就都有了: 需求递进 方式 一句话(它是干嘛的) ① 服务在 Pod 里,Pod IP 会变(重启就换),集群内其他服务怎么稳定找到它? ClusterIP 给一组 Pod 一个集群内固定"虚拟 IP"(VIP)+ 名字,别人用名字访问,不关心 Pod 换没换 ② 我想从集群外访问(浏览器、外部系统)? NodePort 在每个节点上开一个端口(如 32613),外部访问 节点IP:端口 就能打到 Service ③ 生产流量大,想要一个统一的公网入口? LoadBalancer 云负载均衡器(本文用 metallb 模拟),分配一个对外 IP,流量先到它再进集群 ④ 有多个服务,想按域名/路径分发? Ingress L7 网关:按 域名 + 路径 路由到不同 Service(如 api.xxx.com → A 服务,www.xxx.com → B 服务) 记住递进关系:ClusterIP 是基础(所有方式最终都打到它)→ NodePort 是"集群外访问"的最简实现 → LoadBalancer 是"统一对外入口" → Ingress 是"按域名路由"。后面每个阶段都会细讲原理和实操。 ...

十一月 20, 2023 · 7 分钟 · 1336 字 · yaomingye

Kubernetes Deployment 实战:部署、滚动更新与回滚的完整演示

把应用跑上集群:Deployment 的一堂实战课 上一篇搭好了 kind 三节点集群,但这只是"系统盘"——真正的 K8s 学习从把应用跑上去才刚开始。这篇文章用一次完整的实战演示:部署 3 副本 nginx、观察调度器怎么分配节点、扩容、滚动更新发新版、故意发布坏版本看集群卡死、最后回滚救回来。全程真实操作和真实输出,每个环节都解释"为什么是这样"。 📌 前置知识:建议先读过本系列前一篇(kind 搭建一主二从集群),至少知道控制面/工作节点/kubelet 是什么。这篇文章的操作都在那个集群上进行。 这次要做什么 目标:在 kind 一主二从集群上,跑通 Deployment 的完整生命周期 流程:部署 → 观察调度 → 查看对象层级 → 扩容 → 滚动更新 → 坏版本发布 → 回滚 收获:亲眼验证"期望状态/控制器循环/调度器/滚动更新"这些概念 前置条件与环境准备 项 本次实测 集群 kind learn ,1 控制面 + 2 工作节点,K8s v1.36.1 工具 kubectl v1.36.4 镜像 nginx:1.25 与 nginx:1.27(预载入节点) 关键一步:镜像怎么进节点 kind 集群里拉镜像有个容易忽略的坑:节点内部的 containerd 不走宿主机 Docker 的代理配置,直接从 Docker Hub 拉。国内网络直连大概率超时。所以先把镜像拉到宿主机(走代理),再一次性导入所有节点: # 宿主机拉镜像(Docker daemon 已配代理) docker pull nginx:1.25 docker pull nginx:1.27 # 导入集群所有节点(等价于"把镜像送进每个节点") kind load docker-image nginx:1.25 nginx:1.27 --name learn “加载进入每个节点"到底是什么意思? kind 的"容器即节点"是嵌套结构:节点是一个 Docker 容器,容器内跑着 containerd(节点自己的容器运行时)——kubelet 只认 containerd。于是镜像存储有两层、互不相通: ...

十一月 18, 2023 · 6 分钟 · 1152 字 · yaomingye

内网穿透实战:SSH 反向隧道让外网随时随地访问家里的服务器

一条隧道,把 NAT 后的服务器接到公网 家里有台 debian 服务器,跑着 mihomo、Docker、kind 集群,人在公司或外地的时候想连上去干活——但它在家庭局域网后面,没有公网 IP,外面根本摸不到它。某开发者的解法:让它自己主动"爬"出去,在唯一有公网 IP 的阿里云 ECS 上挂一个隧道入口。从此不管在哪,一条命令直达家里的服务器,而且安全到脚本小子无从下手。 这篇文章完整记录这个方案:先讲透原理(NAT 为什么挡人、反向隧道为什么能钻出去),再对比工具选型,然后给出全部配置过程和真实踩过的三个坑。 这次要做什么 目标:通过公网 ECS 中转,实现在任意网络 SSH 访问位于家庭 NAT 后的 debian 服务器 产出:ssh debian-lan 一条命令直达;局域网内原有直连不受影响 安全:至少挡住脚本小子——不暴露额外公网端口、隧道账号无 shell、全链路密钥认证 原理:NAT 挡住了什么,隧道就钻什么 第一步:理解 NAT 的"单向门" NAT(Network Address Translation,网络地址转换)让内网设备共享一个公网出口,但它是一扇单向门:内网设备主动出站,路由器放行并记住映射;公网侧想主动连进来,路由器没有对应记录,直接丢弃。 flowchart TD subgraph WAI["公网侧"] U["笔记本\n(任意网络)"] S["ECS 公网 IP"] end subgraph LAN["家庭局域网 (NAT 后)"] D["debian 服务器\n192.168.x.x"] end U -->|"① 出站可达"| S S -.->|"② 入站被 NAT 丢弃"| D D -->|"③ 出站可达"| S style S fill:#0f172a,stroke:#3b82f6,stroke-width:2.5px,color:#ffffff,font-weight:bold style U fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#ffffff style D fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#ffffff 图中 ② 那条虚线就是死路:别人永远无法主动找到你。但注意 ① 和 ③——出站永远是通的。这就是全部突破口。 ...

十一月 16, 2023 · 4 分钟 · 735 字 · yaomingye

kind 一主二从集群搭建全记录:代理配置、多集群切换与踩坑实录

一主二从的 K8s,kind 半小时就位 想学 Kubernetes,第一道坎不是概念,是环境:三台物理机?买不起。云厂商的托管集群?按小时计费,练手都心疼。直到某开发者把 kind(Kubernetes IN Docker)跑起来——一条命令,一台普通服务器,1 主 2 从三节点集群直接立起来,用完 kind delete cluster 一键销毁,成本几乎为零。 这篇文章完整记录这次实操:硬件要什么配置、国内网络怎么绕过、kind / kubectl / k9s 怎么装、那个 9 行的 YAML 到底在说什么、以及集群里跑起来的每个组件是什么。跟着走一遍,你也能拥有一套属于自己的 K8s 练手环境。 这次要做什么 目标:在一台 Linux 服务器上,用 kind 创建一个 1 控制面 + 2 工作节点的 Kubernetes 集群 产出:kind + kubectl + k9s 三件套,集群可通过 kubectl 正常管理 用途:本地化学习 K8s,为日后云 ECS(阿里云等)快速上手打底 📌 前置知识:需要会用 Linux 基础命令(curl、systemctl、docker)、知道容器是什么。K8s 概念零基础也可以,本文会讲清楚每个装好的组件是干嘛的。 开始之前,先把丑话说在前头——kind 的边界: flowchart LR A["kind 能学"] --> A1["API 对象 / 编排逻辑"] A --> A2["多节点调度 / 污点亲和"] A --> A3["Service / Ingress / 存储抽象"] B["kind 学不到"] --> B1["kubeadm 安装流程"] B --> B2["CNI 插件选型与安装"] B --> B3["证书 / etcd 集群 / HA 高可用"] style A fill:#1e1e24,stroke:#9ca3af,stroke-width:2px,color:#ffffff style A1 fill:#1e1e24,stroke:#9ca3af,stroke-width:2px,color:#ffffff style A2 fill:#1e1e24,stroke:#9ca3af,stroke-width:2px,color:#ffffff style A3 fill:#1e1e24,stroke:#9ca3af,stroke-width:2px,color:#ffffff style B fill:#450a0a,stroke:#dc2626,stroke-width:2px,color:#ffffff,font-weight:bold style B1 fill:#450a0a,stroke:#dc2626,stroke-width:2px,color:#ffffff,font-weight:bold style B2 fill:#450a0a,stroke:#dc2626,stroke-width:2px,color:#ffffff,font-weight:bold style B3 fill:#450a0a,stroke:#dc2626,stroke-width:2px,color:#ffffff,font-weight:bold style startEnd fill:#701a4c,stroke:#e11d48,stroke-width:2.5px,color:#ffffff,font-weight:bold kind 是用 Docker 模拟节点(每个"节点"是一个跑着完整 Linux 的容器),所以它教不会你"怎么在裸机上装出 K8s"——那些是上云前的功课,本文不展开。先把 kind 能教的部分学扎实。 ...

十一月 14, 2023 · 10 分钟 · 2068 字 · yaomingye

小程序支付后端从零构建:wx.pay 全流程、幂等实践与客户端定位

支付后端从 0 到 1:流程、幂等和那位备胎 提起微信支付,不少后端新同学的第一反应是"这不就是调个 API 嘛"。真上手才发现,光一个异步回调就能把人折腾到怀疑人生:明明用户付了钱,订单状态却一直不更新;回调来了两次,积分发了双份;个人主体小程序连商户号都申请不下来,只能对着文档干瞪眼。 这篇文章把 wx.pay 的后端流程从头到尾拆开:登录拿 openid、统一下单换 prepay_id、二次签名、异步回调验签与解密,再到怎么用乐观锁把幂等做扎实。最后用一点篇幅聊聊"备胎信使"理论——搞明白客户端在支付里到底说了不算什么,很多困惑会迎刃而解。 📌 前置知识:会写 Spring Boot 接口,看得懂 SQL,理解基本的 HTTP 与 JSON。不需要任何支付经验,本文的代码保证从空项目能直接搭起来。 第 1 步 目标说明:这一篇到底讲什么 1.1 为什么写这篇文章 支付是少数几个"看起来简单、出错要命"的领域。某开发者的第一版支付代码只有一百多行,跑起来却发现三个大坑: 客户端调起支付后立刻回调了 success,后端却还没收到微信的异步通知,订单一直挂在"待支付"; 通知重试机制下同一个回调被处理了两次,用户积分翻倍; 本地调得好好的,上线后微信的回调根本进不来——因为内网地址微信访问不了。 这三件事分别对应流程、幂等、回调三个话题,也是本文的主线。提前把这些想明白,能省下大把试错时间。 1.2 小程序开发的"三驾马车" 一个完整的小程序业务,后端主要跟三样东西打交道: 能力 前端 API 后端职责 类比 身份识别 wx.login 用 code 换 openid,建立用户账号 进门刷脸 交易闭环 wx.requestPayment 统一下单、签名、回调处理 柜台结账 消息触达 wx.requestSubscribeMessage + 服务端发送 存 access_token,发订阅消息 售后电话 三者独立又协作:登录建立身份,支付产生交易,订阅消息把交易结果送达用户。 1.3 本文核心议题 围绕上面三驾马车,重点回答四个问题: wx.pay 的完整后端流程是什么?预支付、二次签名、异步回调各是干什么的。 如何保证支付幂等,防止重复扣款、重复加积分? 客户端在支付中到底扮演什么角色?哪些事它说了不算? 个人开发者没有商户资质,怎么照样把后端逻辑练熟? 1.4 阅读本文的收获 读完你会得到一份可以直接抄的 Java 实现:登录接口、统一下单、二次签名、回调处理器,以及一套幂等的三层防御。还会得到一个重要认知:支付后端的核心逻辑与商户号无关,没资质也能先把逻辑写对,拿到商户号只是替换一个 API 地址的事。 ...

十月 23, 2023 · 15 分钟 · 3017 字 · yaomingye

把 React + Vite 项目搬到 Electron 去:改造、踩坑与调试

把 React 项目搬到 Electron,顺便让 PDF 导出不再闹心 某开发者手头有个 Vite + React + TypeScript 的简历编辑器项目,浏览器里跑得好好的,但每次要导出 PDF 都得先开新窗口、再唤出浏览器打印对话框、再手动取消「页眉和页脚」——这套操作重复多了真的会烦躁。于是决定把它改成 Electron 桌面应用。 这篇文章记录了改造全过程,顺便解决了国内下载 Electron 二进制的问题,以及几个常用的调试命令。 第 1 步:先确认你从什么起点出发 这次改造的对象是一个标准的 Vite + React + TypeScript 前端项目,没有用任何奇怪的自定义配置。如果你也是类似的项目结构,可以直接照着操作。 改造前后的技术栈对比: 改造前 改造后 Vite 8 开发服务器 Vite 8 + Electron 43 React 18 + TypeScript 不变 MUI v9 组件库 不变 window.print() 导出 PDF webContents.printToPDF() 原生导出 浏览器 localStorage 持久化 不变 + 原生「另存为」对话框 验证入口: 项目根目录应该有一个 package.json,内含 "scripts": { "dev": "vite" },项目本身能通过 npm run dev 正常启动。 ...

四月 5, 2023 · 5 分钟 · 974 字 · yaomingye
Cat Radio