KOPS
type: channel
link: https://www.kops.cc/
description: 一个专注于记录技术成长与实战经验的个人技术博客，涵盖 Java/Spring Boot 开发实战、Kubernetes 和云原生架构、数据库与性能调优、DevOps 工具链等方向的技术解析与干货分享。 宗旨是：好记性不如烂笔头。https://www.kops.cc。技术交流加微 haxicc
items: 基于 LVScare 的 Kubernetes 高可用方案
items: GitLab OAuth Plugin + Matrix Authorization Strategy 子群组授权报错问题分析与修复
items: Jenkins GitLab 单点登录、项目矩阵授权策略
items: 如何修改容器时间而不影响宿主机
items: 浏览器后台 Tab 导致 WebSocket 断连问题排查与解决
items: 一次 Calico socket FD 泄漏问题的排查
items: 一次由 Maven 可重复构建引发的 Spring Boot 运行时类加载问题排查
items: Gateway API：Kubernetes 流量管理的未来，Ingress的接班者
items: 野草助手分享码口令，最新最全口令
items: MySQL误删数据不慌，还有的救

基于 LVScare 的 Kubernetes 高可用方案
type: item
date: 2026-02-06T09:05:00+00:00
description: 在云环境中，Kubernetes 控制面的高可用通常交给云厂商的 LoadBalancer 来解决。但在以下场景中，这条路并不成立：私有 IDC / 裸金属集群边缘计算、离线环境公有云迁回自建机房（缺少云 LB、云 SLB）希望减少组件复杂度、避免引入 keepalived / VRRP我之前有了解过 sealos，它提供了一种非常“反常规但优雅”的方案：不做 VIP，不做 VRRP，而是用 IPVS + LVScare 在每个节点本地维护 kube-apiserver 的高可用访问能力。本文就是在这一思路启发下，对 LVScare 作为 Kubernetes 高可用组件 的一次整理与实践总结。传统 Kubernetes API Server 高可用方案回顾方案一：云 LoadBalancer优点：简单、稳定对使用者透明缺点：强依赖云厂商私有化 / IDC 场景不可用方案二：VRRP + keepalived（VIP） VIP:6443 | +----------+------------+ | | Nginx <-keepalived-> Nginx(Backup) | +---+--------------------------+ | | | apiserver apiserver apiserver问题在于：需要额外的 LB 节点需要维护 VRRP / VIP架构组件偏重sealos 的思路：去中心化的 API Server 高可用sealos 提出的核心思路是：不再提供一个“中心入口”，而是让每个节点都具备访问“所有 API Server 的能力”。hosts 配置假设节点主机名和 IP 如下，在每个节点上配置 hosts。10.0.0.1 apiserver.cluster.local # 临时解析到第一个master的ip，集群搭建完成后会改掉 10.0.0.1 master1 10.0.0.2 master2 10.0.0.3 master3 10.0.0.11 node1安装软件配置 Kubernetes 软件源：cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.33/rpm/ enabled=1 gpgcheck=1 gpgkey=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.33/rpm/repodata/repomd.xml.key exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni EOF安装所需软件：yum install -y runc ipset ipvsadm yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes安装containerd：从 containerd 发布页面（https://github.com/containerd/containerd/releases）根据芯片架构下载最新的版本即可。比如 x86_64 平台，下载 containerd-2.x.x-linux-amd64.tar.gz解压 tar 包到 /usr/localtar xf containerd-2.x.x-linux-amd64.tar.gz -C /usr/local配置systemd服务cat > /usr/local/lib/systemd/system/containerd.service << "EOF" [Unit] Description=containerd container runtime Documentation=https://containerd.io After=network.target [Service] ExecStartPre=-/sbin/modprobe overlay ExecStart=/usr/local/bin/containerd Type=notify Delegate=yes KillMode=process Restart=always RestartSec=5 LimitNPROC=infinity LimitCORE=infinity TasksMax=infinity OOMScoreAdjust=-999 [Install] WantedBy=multi-user.target EOF设置服务开机自启sy…

GitLab OAuth Plugin + Matrix Authorization Strategy 子群组授权报错问题分析与修复
type: item
date: 2026-01-21T08:23:53+00:00
description: 背景在统一发布平台中，Jenkins 通过 GitLab OAuth Plugin 实现单点登录，并结合 Matrix Authorization Strategy Plugin 在 Folder 级别启用 Enable project-based security，实现项目矩阵授权。在实际使用中，发现一个明显的问题：GitLab 子群组（subgroup）无法作为授权主体使用具体表现为：GitLab 中存在如下群组结构：group1 └── subgroup1在 Jenkins Folder → 权限配置中添加群组：group1/subgroup1Jenkins 校验时报错：java.lang.NullPointerException: Cannot invoke "org.gitlab4j.api.models.Group.getName()" because "this.gitlabGroup" is null添加子群组报错：点开显示详情，报错信息如下：问题影响需要特别说明的是：经过测试，该报错并不会影响 Jenkins 实际的权限生效逻辑，功能是可用的，只是前端报错了。即：即使页面校验报错子群组成员在实际访问 Job / Folder 时权限是生效的但该问题依然具有较大影响，主要体现在使用体验和认知层面：Jenkins 页面在添加子群组时直接报错，给人“配置失败”的强烈暗示管理员往往会误以为 Jenkins 不支持 GitLab 子群组容易导致误判为权限未生效，从而放弃子群组授权方案迫使平台退回到顶层群组授权，权限粒度被迫放大因此，这是一个：不影响核心功能，但严重影响可用性与可理解性的实现缺陷在多项目、多团队的 Jenkins 场景下，该问题依然会对平台治理产生明显负面影响。问题定位过程现象分析从异常栈可以看出，问题发生在：Matrix Authorization Strategy Plugin 校验群组名称时调用 GitLab OAuth Plugin 提供的群组解析逻辑关键异常信息：Cannot invoke Group.getName() because gitlabGroup is null说明：Jenkins 期望从 GitLab OAuth Plugin 中获取一个 Group但根据传入的 group1/subgroup1，插件返回了 null代码分析定位到 GitLab OAuth Plugin 中用于加载群组的方法：public Group loadOrganization(String organization)原始实现逻辑如下：public Group loadOrganization(String organization) { if (StringUtils.isEmpty(organization)) return null; try { if (gitLabAPI != null && isAuthenticated()) { List<Group> gitLabGroups = gitLabAPI.getGroupApi().getGroups(); if (!gitLabGroups.isEmpty()) { return gitLabGroups.stream() .filter(group -> group.getName().equalsIgnoreCase(organization)) .findFirst() .orElse(null); } } } catch (GitLabApiException e) { LOGGER.log(Level.FINEST, e.getMessage(), e); } return null; }关键问题点organization 实际上传入的是：group1/subgroup1但代码却使用：group.getName()而在 GitLab 中：字段示例说明namesubgroup1仅群组名称fullPathgroup1/subgroup1完整路径name 永远不可能匹配子群组的完整路径。因此：顶层群组（group1）可匹配子群组（group1/subgroup1）必然返回 null这是一个确定性的实现错误。修复方案修复思路将群组匹配逻辑从：name → fullPath使其与 Jenkins 中输入的 GitLab 群组标识保持一致。修复后的代码public Group loadOrganization(String organization) { if (StringUtils.isEmpty(organization)) return null; try { if (gitLabAPI != null && isAuthenticate…

Jenkins GitLab 单点登录、项目矩阵授权策略
type: item
date: 2026-01-15T09:21:41+00:00
description: 建设目标构建一个 统一、规范、安全、可扩展 的发布平台，满足以下目标：支持多项目并行使用，项目之间权限严格隔离通过 GitLab 单点登录，避免用户双重维护权限最小化，授权清晰项目自治，减少平台管理员日常介入成本支持项目规模扩展（用户 200+、项目数持续增长）总体架构核心组件组件作用GitLab用户身份源、组管理、代码仓库Jenkins统一发布平台Jenkins插件：GitLab Authentication plugin实现 GitLab SSO 登录Jenkins插件：Matrix Authorization Strategy Plugin实现细粒度授权（全局 / 文件夹 / Job）Jenkins插件：Folder Plugin按项目文件夹隔离，方便权限管理认证与用户管理设计GitLab 单点登录（SSO）Jenkins 不本地维护任何用户所有用户通过 GitLab OAuth 登录 JenkinsJenkins 用户名 = GitLab username（保持唯一性）收益：用户账号由 GitLab 统一管理避免 Jenkins 账号残留GitLab 的群组方便在 Jenkins 上分配权限GitLab 组作为权限载体不直接给个人授权，优先授权 GitLab 组Jenkins 权限配置中仅引用：GitLab Group少量特权用户（如项目管理员）项目与 Job 组织结构项目级文件夹模型设计原则：一个项目 = 一个 Jenkins FolderJenkins ├── project-a/ │ ├── app1 │ ├── app2 │ └── app3 ├── project-b/ │ ├── app1 │ └── app2文件夹的职责项目 Job 的唯一容器项目权限边界项目管理员的管理单元禁止：禁止在 Jenkins 根目录直接创建 Job禁止跨 Folder 复用 Job（避免权限穿透）权限模型设计授权策略配置Jenkins 全局授权策略：授权策略：项目矩阵授权策略对象权限匿名用户无Authenticated UsersOverall → Read平台管理员Overall → Administer⚠️ 普通用户 不允许 看到非授权项目项目级（文件夹）授权策略：启用：Enable project-based security项目基础用户组（GitLab Group）示例：crm适用对象：项目开发测试项目管理员示例：陈日志职责：维护项目 Job管理项目成员权限权限最小化原则落实方式默认：给项目组授予 Job 的 Read + Build + Cancel 等基础权限基础权限尽量授权给「组」升权：仅对明确职责人员授予更高的权限不允许：不允许直接授予 Overall → Administer不允许在 Global 级别开放 Job 管理权限项目管理员机制项目管理员来源通常为该项目的运维或项目开发负责人由平台管理员在项目初始化时指定项目管理员的权限边界仅限该项目 Folder无法影响其他项目无法修改 Jenkins 全局配置凭证与敏感信息管理Credentials 使用原则使用 Folder Scoped Credentials禁止使用 Global Credentials（除非全局凭证）权限控制项目管理员：授予凭证的创建、删除、更新、查看等权限普通项目成员：无凭证管理权限风险与注意事项常见风险风险对策项目管理员误删 Job开启 Job 配置备份权限配置混乱统一模板 + 规范初始化流程 + 平台管理员/安全员定期核查人员离职权限残留依赖 GitLab SSO初始化流程新项目接入流程：GitLab 创建项目组Jenkins 创建 Folder绑定 GitLab 组权限指定项目管理员

如何修改容器时间而不影响宿主机
type: item
date: 2026-01-14T03:36:59+00:00
description: 关键词：libfaketime、时间模拟在测试时间相关逻辑（证书过期、订单超时、定时任务、跨年问题）时，很多人第一反应是：能不能只改一个程序/进程的时间，而不影响宿主机？结论很明确：不能直接改。在容器/Pod 环境中也存在同样的需求，甚至需求更强烈，因为 Kubernetes 中，宿主机往往不会只运行一个业务程序，修改系统时间所造成的影响可能是无法预估的。Linux 内核只有一份系统时间，容器共享内核，不存在所谓的 Time Namespace。于是，libfaketime 成为了容器环境中最常被提及的“替代方案”。本文将结合主流编程语言获取时间的 Demo 来验证 libfaketime 的实际效果：libfaketime 能做什么、不能做什么为什么有的语言生效、有的完全无效Java 为什么必须额外配置libfaketime 是什么，它解决了什么问题libfaketime 并不是修改系统时间，而是：通过 LD_PRELOAD 劫持部分 libc 的时间函数，让进程“认为”时间发生了变化。典型被劫持的函数包括：time()gettimeofday()clock_gettime(CLOCK_REALTIME)这意味着：宿主机时间 不会变其他容器 不受影响只对当前进程有效这正好契合了容器 / Pod 级别的测试需求。环境准备export LD_PRELOAD=/usr/local/lib/faketime/libfaketime.so.1 export FAKETIME="2026-01-01 00:00:00" # FAKETIME 还支持很多模拟时间的表达式，请参考 https://github.com/wolfcw/libfaketime在 Java 应用中，必须额外加一句：export FAKETIME_DONT_FAKE_MONOTONIC=1后文会详细解释原因。主流编程语言行为对照1. Shelldate输出结果：Thu Jan 1 00:00:00 CST 2026✅ 生效2. C 语言#include <stdio.h> #include <time.h> #include <sys/time.h> int main() { time_t t = time(NULL); struct timeval tv; gettimeofday(&tv, NULL); struct tm *localTime; localTime = localtime(&t); printf("time(): %04d-%02d-%02d %02d:%02d:%02d\n", localTime->tm_year + 1900, localTime->tm_mon + 1, localTime->tm_mday, localTime->tm_hour, localTime->tm_min, localTime->tm_sec); localTime = localtime(&tv.tv_sec); printf("gettimeofday():%04d-%02d-%02d %02d:%02d:%02d\n", localTime->tm_year + 1900, localTime->tm_mon + 1, localTime->tm_mday, localTime->tm_hour, localTime->tm_min, localTime->tm_sec); return 0; }输出结果：time(): 2026-01-01 00:00:00 gettimeofday():2026-01-01 00:00:00✅ 生效3. Pythonimport time from datetime import datetime time_time = time.time() datetime_now = datetime.now() print("time.time():", time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(time_time))) print("datetime.now():", datetime_now.strftime("%Y-%m-%d %H:%M:%S"))输出结果：time.time(): 2026-01-01 00:00:00 datetime.now(): 2026-01-01 00:00:00✅ 生效4. Node.jsfunction formatWithNative(date = new Date()) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).p…

浏览器后台 Tab 导致 WebSocket 断连问题排查与解决
type: item
date: 2026-01-13T08:57:00+00:00
description: 背景在使用 gotty 这类基于 WebSocket 的 Web Terminal 工具时，遇到一个问题：浏览器打开页面后，WebSocket 连接一切正常切换到其他浏览器标签页（Tab），停留一段时间再切回原 Tab，发现 WebSocket 已断开gotty 日志：2026/01/13 01:06:16 New client connected: 10.42.2.8:41704, connections: 1/0 2026/01/13 01:12:18 Connection closed by client: 10.42.2.8:41704, connections: 0/0更有意思的是：本地调试（localhost / 内网）几乎不会复现通过公网访问时，问题稳定出现浏览器切换 Tab 的影响第一反应是怀疑浏览器行为。通过简单验证可以确认：浏览器会对后台页面进行 JS 执行节流 / 暂停（可以通过浏览器的开发者工具，查看WebSocket的数据交互）setInterval / setTimeout 的触发频率被大幅拉长，甚至完全暂停（取决于浏览器的行为）如果 WebSocket 的心跳依赖前端 JS 定时器，那么在后台 Tab 场景下：心跳不再发送，连接会逐渐变成“空闲连接”为什么本地不断，公网却会断？我发现浏览器JS节流/暂停之后，第一时间在电脑本地也跑一个gotty，验证的结果是本地连接，即使浏览器对JS节流/暂停，也不会导致连接中断。因此初步得出一个结论：问题出现在网络环境的差异上。本地 / 内网访问链路browser → localhost / LAN → server特点是：没有 NAT几乎不存在 TCP idle timeout即使连接长时间无数据，也不会被回收因此，本地连接时即使 JS 完全暂停，连接依然“看起来还活着”。公网访问的真实链路browser ↓ 路由器/防火墙 NAT ↓ 运营商 ↓ 云防火墙 / 负载均衡 ↓ server这条链路上的每一层设备，几乎都会对 空闲 TCP 连接设置超时回收机制。常见的 idle timeout：家用路由器：60–300 秒云负载均衡：60–600 秒移动网络：更短而这些回收行为通常是 silent drop：不发送 FIN不发送 RST双方都不知道连接已经被中间设备“忘记”半开连接（Half-open TCP）在后台 Tab 场景下，典型的故障链路是：浏览器切后台 ↓ JS 心跳暂停 ↓ WebSocket 无任何流量 ↓ TCP 连接空闲 ↓ NAT / 防火墙回收连接 ↓ 连接变成半开状态此时：浏览器认为连接仍然存在服务端认为连接仍然存在但中间网络设备已经不再转发数据只有在下一次写数据时，问题才会暴露。reconnect 有用吗？gotty 支持 reconnect 机制，使用 --reconnect 参数开启。经过测试，在这个场景下无效。我查找资料后，reconnect 是客户端重连，可能适用的场景：服务端主动close例如：服务端升级/重启超过最大会话时长服务端进程异常退出例如：panicOOMSIGKILL客户端网络短暂中断（可感知）例如：Wi-Fi断开又恢复VPN切换它解决的是：“断了怎么办”，而不是 “保持连接不断”。服务端 WebSocket Ping问题的根因可以归结为一句话：连接在后台 Tab 时没有任何网络流量，导致被中间网络设备回收因此，正确的解决方向是：不依赖前端 JS由服务端主动制造“最小但持续”的流量WebSocket 协议本身已经提供了标准答案：Ping / Pong（RFC 6455）服务端发送 Ping frame浏览器网络栈自动回复 Pong该过程 不依赖 JavaScript 执行即使页面 JS 被完全暂停，只要连接仍存在，Pong 也会被自动发送。改造方案在服务端 WebSocket 建立后，增加三点：定期发送 Ping（例如每 30 秒）设置 PongHandler，刷新 ReadDeadline在 Pong 超时后主动关闭连接，交给 reconnect 兜底这样可以同时达到：防止 NAT / 防火墙回收连接及时发现真正的死连接与现有 reconnect 机制完美配合因为 gotty 项目维护者已经不活跃，不管是提ISSUE或是PR，维护者也久久不回复，因此，我在我 fork 的版本中做了修改，修改的代码在这个提交：COMMIT：https://github.com/chenrizhi/gotty/commit/5578b76f535c9260c53c58907108a52a2994971e参数取值的取舍修改的代码有两个常量：serverSidePingInterval、serverSidePongWait，这两个值的…

一次 Calico socket FD 泄漏问题的排查
type: item
date: 2026-01-12T01:42:20+00:00
description: 背景近期在一套 Kubernetes 集群中，发现一个非常反常的现象：在节点上执行 netstat / ss 命令异常缓慢，甚至需要几分钟才能返回结果节点本身负载并不高，CPU、内存看起来都比较正常由于 netstat/ss 本质上只是读取内核和 /proc 信息，这种“卡死级别”的慢速，往往意味着 系统层面存在异常规模的数据结构。这篇文章记录了从一个看似普通的 netstat 慢问题，一步步定位到 Calico socket FD 泄漏 Bug，并最终通过升级版本彻底解决的完整过程。从 netstat/ss 变慢开始最初的直接表现是：time netstat -ntlpActive Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:10010 0.0.0.0:* LISTEN 1530975/cri-dockerd tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1165/sshd: /usr/sbi tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 164980/nginx: worke tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 1/systemd tcp 0 0 127.0.0.1:9099 0.0.0.0:* LISTEN 1171111/calico-node tcp 0 0 0.0.0.0:20048 0.0.0.0:* LISTEN 2503623/rpc.mountd tcp 0 0 0.0.0.0:2049 0.0.0.0:* LISTEN - tcp 0 0 127.0.0.1:10256 0.0.0.0:* LISTEN 623016/kube-proxy tcp 0 0 127.0.0.1:10248 0.0.0.0:* LISTEN 1531381/kubelet tcp 0 0 127.0.0.1:10249 0.0.0.0:* LISTEN 623016/kube-proxy tcp 0 0 0.0.0.0:57325 0.0.0.0:* LISTEN 2500368/rpc.statd tcp 0 0 0.0.0.0:46433 0.0.0.0:* LISTEN - tcp6 0 0 :::22 :::* LISTEN 1165/sshd: /usr/sbi tcp6 0 0 :::111 :::* LISTEN 1/systemd tcp6 0 0 :::20048 :::* LISTEN 2503623/rpc.mountd tcp6 0 0 :::2049 :::* LISTEN - tcp6 0 0 :::2380 :::* LISTEN 619966/etcd tcp6 0 0 :::2379 :::* LISTEN 619966/etcd tcp6 0 0 :::40007 :::* LISTEN - tcp6 0 0 :::6443 :::* LISTEN 621032/kube-apiserv tcp6 0 0 :::9369 :::* LISTEN 2484838/pushprox-cl tcp6 0 0 :::9796 :::* LISTEN 2485357/node_export tcp6 0 0 :::10250 :::* LISTEN 1531381/kubelet tcp6 0 0 :::10259 :::* LISTEN 621666/kube-schedul tcp6 0 0 :::10257 :::* LISTEN 621333/kube-control tcp6 0 0 :::48607 :::* LISTEN 2500368/rpc.statd real 3m21.534s user 3m9.634s sys 0m11.357s可见执行非常慢。这类问题通常有几种可能：系统中存在大量 socket / 连接/proc 下某些目录规模异常某个进程打开了极多的文件描述符（FD）为了确认 netstat 到底“卡”在什么地方，我使用了 strace 对其系统调用进行跟踪。使用 strace 定位卡顿原因执行：strace netstat -ntlp很快发现了异常点，大量重复的系统调用如下：... readlink("/proc/3698662/fd/77625", "socket:[837323590]", 63) = 18 getxattr("/proc/3698662/fd/77625…

一次由 Maven 可重复构建引发的 Spring Boot 运行时类加载问题排查
type: item
date: 2026-01-08T01:42:00+00:00
description: 背景在一个 Spring Boot 3.x 项目中，为了满足可重复构建（Reproducible Build）的要求(可查看我另一篇文章了解可重复构建)，我在 pom.xml 中新增了如下配置：<project.build.outputTimestamp>2026-01-01T00:00:00Z</project.build.outputTimestamp>该配置用于固定构建产物的时间戳，确保多次构建生成的 JAR 文件在字节级别保持一致。然而，加上该配置后，应用在运行时出现了异常：启动正常业务请求触发时抛出运行时错误错误与 okhttp 相关jakarta.servlet.ServletException: Handler dispatch failed: java.lang.NoClassDefFoundError: Could not initialize class com.xxx.common.util.HttpUtil ... Caused by: java.lang.NoClassDefFoundError: Could not initialize class com.xxx.common.util.HttpUtil ... Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.NoSuchFieldError: Companion [in thread "http-nio-80-exec-9"] at okhttp3.internal.Util.<clinit>(Util.kt:70) ~[okhttp-4.10.0.jar!/:?]而在未添加该配置时，应用运行完全正常。问题初步分析异常发生在运行期，而非编译期，表现为典型的 ABI 不兼容问题（如 NoSuchMethodError）。通过分析依赖树，发现 okhttp 4.10.0 是通过 com.huaweicloud:esdk-obs-java:jar 依赖间接引入：mvn dependency:tree[INFO] +- com.huaweicloud:esdk-obs-java:jar:3.20.6.1:compile[INFO] | +- com.jamesmurty.utils:java-xmlbuilder:jar:1.2:compile[INFO] | +- com.squareup.okhttp3:okhttp:jar:4.10.0:compile[INFO] | | +- com.squareup.okio:okio-jvm:jar:3.0.0:compile[INFO] | | | +- org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.7.22:compile[INFO] | | | | - org.jetbrains.kotlin:kotlin-stdlib-jdk7:jar:1.7.22:compile[INFO] | | | - org.jetbrains.kotlin:kotlin-stdlib-common:jar:1.7.22:compile[INFO] | | - org.jetbrains.kotlin:kotlin-stdlib:jar:1.7.22:compile[INFO] | | - org.jetbrains:annotations:jar:13.0:compile[INFO] | +- com.squareup.okio:okio:jar:1.17.2:compile同时，OBS SDK 又引入了一个较老版本的 okio：okio 1.17.2Fat Jar 中的实际情况通过查看 Spring Boot 打包后的 fat jar 内容：jar tf app.jar | grep -Ei "okio|okhttp"未开启 project.build.outputTimestamp 时BOOT-INF/lib/feign-okhttp-12.4.jar BOOT-INF/lib/okhttp-4.10.0.jar BOOT-INF/lib/okio-jvm-3.0.0.jar BOOT-INF/lib/okio-1.17.2.jar开启 project.build.outputTimestamp 后BOOT-INF/lib/feign-okhttp-12.4.jar BOOT-INF/lib/okhttp-4.10.0.jar BOOT-INF/lib/okio-1.17.2.jar BOOT-INF/lib/okio-jvm-3.0.0.jar可以看到，两个场景中 jar 的内容是…

Gateway API：Kubernetes 流量管理的未来，Ingress的接班者
type: item
date: 2025-11-26T07:38:00+00:00
description: 在很长一段时间里，Ingress 是 Kubernetes 集群的标准北向流量入口。但随着业务复杂度增加、微服务体系兴起、多协议需求增长，Ingress 的先天缺陷越来越明显。2024–2025 年，Kubernetes 官方与 CNCF 明确：Gateway API 是下一代流量管理标准，将逐步取代 Ingress 成为默认推荐方式。而随着 ingress-nginx 宣布在 2026 年 3 月停止维护，Gateway API 的迁移意义愈发明确。本文将从原理、对比、设计理念、CRD、部署与使用示例多个方面全面介绍 Gateway API。1. 什么是 Gateway API？Gateway API 是 Kubernetes SIG-Network 推出的新一代流量治理标准。核心目标：统一 L4/L7 流量管理取代 Ingress 的简陋模型提供可扩展、可观察、可分权协作的网关体系能适配云厂商、服务网格、Ingress 控制器等各种实现它不是一个控制器，而是一套标准 API（CRD）。控制器厂商（如 Envoy、Traefik、Istio、Kong）可以实现这套 API。Gateway API 主要提供以下能力：多协议支持：HTTP、HTTPS、gRPC、TCP、UDP、TLS更丰富的路由表达式多 listener、多端口、跨命名空间引用运维与开发分离可扩展策略（HTTPRouteFilter、Policy Attachment）统一的条件与状态反馈这些是 Ingress 无法做到的。2. 与 Ingress 的对比下表总结两者的核心差异：对比项IngressGateway API设计年代2015（Kubernetes 1.2）2022（现代网关能力需求）支持协议仅 HTTP/HTTPSHTTP、HTTPS、TCP、UDP、gRPC、TLS扩展方式annotation（混乱、不可维护）Policy Attachment、Filters（结构化扩展）资源模型IngressClass、IngressGatewayClass、Gateway、xRoute 多资源模型权限与分权不支持完整支持 Ops（Gateway）与 Dev（Route）分离可观察性状态简陋丰富的 Conditions多 Listener不支持支持多个端口、TLS、SNI团队协作困难一等公民能力行业支持ingress-nginx 等传统控制器Google、AWS、Azure、Envoy、Istio、Kong、Traefik核心结论Ingress 是简陋的 1.0 版本，而 Gateway API 是可扩展的现代化网关规范。3. 为什么 Kubernetes 官方不升级改造 Ingress，而是重做 Gateway API？这是很多人关心的问题。官方给出的根本原因：Ingress 模型太简陋，结构性无法扩展Ingress 的原始设计只包含：hostpathbackend没有 header、method、流量镜像、权重路由、重写规则、多 listener 等能力。为了加功能，各控制器全靠 annotation hack，最终变成：“同一能力不同 controller 语法不同，生态彻底碎片化。”Ingress 的设计已经补不动了。Ingress 是单资源模型，无法支持现代需求现代网关需要：LB 生命周期Listener多团队协作不同 protocol 的路由TLS 策略绑定多个 Route权限隔离Ingress 单一资源没办法表达这些需求。Ingress 只支持 HTTP，不支持多协议如今的需求包括：TCP 服务UDP 服务gRPCTLS PassthroughWebSocketMesh IngressIngress 无法扩展。厂商实现完全不兼容，社区无法统一标准Nginx、Traefik、Kong、云厂商的 Ingress 都不兼容，这让官方无法继续推进它作为标准。提升 Ingress = 大修 API → 这是破坏性变更Kubernetes 官方不允许破坏性 API 升级，这意味着：“想升级 Ingress，但升级后的 API 必须不破坏，不可能。”所以，只能重做一套更先进的网关模型。4. Gateway API 的资源模型（CRD）Gateway API 使用多层次模型，清晰分权：GatewayClass → Gateway → xRoute → BackendGatewayClass描述网关的“类型”，类似于 IngressClass。由运维团队创建，比如：Envoy GatewayNginx Gateway云厂商负载均衡器由集群管理员创建维护。Gateway实际的网关实例，例如：一个 VIP（load balancer）一个 Nginx/Envoy pod…

野草助手分享码口令，最新最全口令
type: item
date: 2025-10-31T02:07:00+00:00
description: 每天更新，请点击下载分享码-2026-07-17.xlsx更新日期：2026-07-17数据收集自互联网公开信息。

MySQL误删数据不慌，还有的救
type: item
date: 2025-10-24T09:12:33+00:00
description: 在软件开发与数据库管理的日常中，程序bug或误执行SQL语句导致的数据错误更新是一个不容忽视的问题。这类问题不仅可能导致业务数据的混乱，还可能对企业造成严重的经济损失。幸运的是，数据库系统为我们提供了一种强大的数据恢复机制——binlog（Binary Log），它能够记录所有修改数据的SQL语句，为我们在数据遭遇不测时提供了一线生机。本文将详细介绍如何通过解析binlog来恢复因程序bug或误执行SQL导致的数据错误更新或删除。binlog基础什么是binlog？binlog是MySQL数据库中的一种二进制日志文件，它记录了数据库中所有修改数据的SQL语句，包括增删改操作。binlog的主要作用是用于数据库的主从复制和数据恢复。binlog的类型MySQL的binlog有三种格式：STATEMENT、ROW和MIXED。STATEMENT：记录每一条会修改数据的SQL语句本身。ROW：记录每一行数据的变化，不记录SQL语句本身。MIXED：默认情况下使用STATEMENT格式，但在某些特殊情况下会自动切换为ROW格式。通过binlog恢复数据理论基础准备工作确认binlog已开启：确保MySQL的binlog功能已开启，且binlog类型为ROW。定位问题时间点：确定误执行的时间范围，以便在binlog中找到相关的记录。误执行的SQL语句：确定误执行的SQL语句，以便在binlog中找到相关的记录。备份当前数据：在进行数据恢复前，务必备份当前的数据状态，以防恢复过程中出现意外。恢复步骤查找binlog文件：根据问题时间点，定位到包含误操作的binlog文件。解析binlog：使用MySQL提供的mysqlbinlog工具解析binlog文件，找到异常的SQL语句。mysqlbinlog --no-defaults -v -v --base64-output=DECODE-ROWS mysql-bin.000001 > binlog.out在生成的SQL文件中搜索关键词，定位到误执行的SQL语句。编写恢复脚本：根据解析出的binlog内容，编写一个反向操作的SQL脚本，用于撤销误执行的SQL影响的数据修改。例如，如果错误地更新了某个字段的值，可以在恢复脚本中将其改回原来的值。执行恢复脚本：在确保备份了当前数据后，执行恢复脚本。验证恢复结果：检查恢复后的数据是否与预期一致，确保业务数据恢复正常。实战场景一：update语句不加where条件误操作数据恢复事件描述程序BUG导致一张表的所有数据被逻辑删除（is_deleted字段被更新为1），该程序BUG是由于执行了一条UPDATE语句，WHERE条件设置有误引起，如下：UPDATE `test`.`t1` SET is_deleted = 1;根据开发同事的反馈，该SQL是在2025-09-05 14:48左右执行的。诉求恢复程序BUG导致的错误更新is_deleted字段的值。解析binlog根据此前的理论知识，binlog记录每一行数据的变化。那么我们可以通过解析binlog，拿到这条SQL所影响的数据，它记录修改前、后的数据。获取binlog文件：如果是云数据，看不到最新的日志，需要执行：flush logs执行binlog解析命令：因为明确知道SQL的执行时间，我这里加了--start-datetime参数，减少数据量。2025-09-05 14:48左右执行的，我这里往前推了几分钟。因为时区问题，减去8小时。mysqlbinlog --no-defaults -v -v --base64-output=DECODE-ROWS --start-datetime="2025-09-05 06:40:00" mysqlbin.000391 > binlog.out查找关键字UPDATE `test`.`t1`# at 273068250 #250905 6:48:12 server id 414163 end_log_pos 273068548 CRC32 0x06b6ee0e Update_rows: table id 5546 flags: STMT_END_F ### UPDATE `test`.`t1` ### WHERE ### @1=5816 /* LONGINT meta=0 nullable=0 is_null=0 */ ### @2=4956 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @3=0 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @4=0 /* LONGINT meta=0 nullable=1 is_null=0 */ ### @5='风管机' /* …