在云环境中,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 的能力”。

- 阅读剩余部分 -

背景

在统一发布平台中,Jenkins 通过 GitLab OAuth Plugin 实现单点登录,并结合 Matrix Authorization Strategy Plugin 在 Folder 级别启用 Enable project-based security,实现项目矩阵授权。

在实际使用中,发现一个明显的问题:

GitLab 子群组(subgroup)无法作为授权主体使用

具体表现为:

  • GitLab 中存在如下群组结构:
group1
└── subgroup1
  • 在 Jenkins Folder → 权限配置中添加群组:
group1/subgroup1
  • Jenkins 校验时报错:
java.lang.NullPointerException: Cannot invoke "org.gitlab4j.api.models.Group.getName()" because "this.gitlabGroup" is null

添加子群组报错:

image-20260121161110286.png

- 阅读剩余部分 -

建设目标

构建一个 统一、规范、安全、可扩展 的发布平台,满足以下目标:

  • 支持多项目并行使用,项目之间权限严格隔离
  • 通过 GitLab 单点登录,避免用户双重维护
  • 权限最小化,授权清晰
  • 项目自治,减少平台管理员日常介入成本
  • 支持项目规模扩展(用户 200+、项目数持续增长)

总体架构

核心组件

组件作用
GitLab用户身份源、组管理、代码仓库
Jenkins统一发布平台
Jenkins插件:GitLab Authentication plugin实现 GitLab SSO 登录
Jenkins插件:Matrix Authorization Strategy Plugin实现细粒度授权(全局 / 文件夹 / Job)
Jenkins插件:Folder Plugin按项目文件夹隔离,方便权限管理

认证与用户管理设计

GitLab 单点登录(SSO)

  • Jenkins 不本地维护任何用户
  • 所有用户通过 GitLab OAuth 登录 Jenkins
  • Jenkins 用户名 = GitLab username(保持唯一性)

- 阅读剩余部分 -

关键词:libfaketime、时间模拟

在测试时间相关逻辑(证书过期、订单超时、定时任务、跨年问题)时,很多人第一反应是:能不能只改一个程序/进程的时间,而不影响宿主机?

结论很明确:

不能直接改。

在容器/Pod 环境中也存在同样的需求,甚至需求更强烈,因为 Kubernetes 中,宿主机往往不会只运行一个业务程序,修改系统时间所造成的影响可能是无法预估的。

Linux 内核只有一份系统时间,容器共享内核,不存在所谓的 Time Namespace

于是,libfaketime 成为了容器环境中最常被提及的“替代方案”。本文将结合主流编程语言获取时间的 Demo 来验证 libfaketime 的实际效果:

  • libfaketime 能做什么、不能做什么
  • 为什么有的语言生效、有的完全无效
  • Java 为什么必须额外配置

libfaketime 是什么,它解决了什么问题

libfaketime 并不是修改系统时间,而是:

通过 LD_PRELOAD 劫持部分 libc 的时间函数,让进程“认为”时间发生了变化

- 阅读剩余部分 -

背景

在使用 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 场景下:

心跳不再发送,连接会逐渐变成“空闲连接”

- 阅读剩余部分 -