[{"content":"Allocated 是“已经承诺/调度出去的容量”，Used 是“宿主机磁盘上实际已经被占用的容量”。 Allocated 主要受 Storage Over Provisioning Percentage 影响；Used / Available 主要受真实写入、快照、系统文件和 Storage Minimal Available Percentage 影响。\nLonghorn 在 UI 上会从多个角度展示存储量，数字之间的分母还不一样，第一次看很容易混。下面我按“先看 UI → 磁盘级别 → 节点级别 → 三个参数 → 完整例子”来讲，并配上一套真实集群（o11y，Longhorn v1.11.2）的实测图示。\n先看一眼 Node 页面的整体样子——三个节点，每个都有 Allocated、Used、Size 三列：\n图 1：o11y 集群 Nodes 页面三节点实测总览。注意 Allocated 与 Used 两条进度条的分母并不相同。\n1. 磁盘上的 Allocated 是怎么算的？ 在 Longhorn Node 页面展开某个节点后，每块 disk 上的 Allocated 通常显示为：\nAllocated Used / Allocated Max 它不是实际磁盘占用，而是 Longhorn 为 replica 调度时记录的“已调度容量”。\n公式可以理解为：\nDisk Allocated Used = 这块 disk 上所有 replica 的逻辑大小之和 Disk Allocated Max = (Storage Maximum - Storage Reserved) × Storage Over Provisioning Percentage Longhorn 官方文档说明，Node 页面的 Allocated 左边数字是已经用于 volume scheduling 的大小，不代表 Longhorn 数据实际占用；右边数字是 Size × Storage Over Provisioning Percentage。(Longhorn)\n其中：\nStorage Maximum = 这块磁盘文件系统总容量 Storage Reserved = Longhorn 不允许自己使用、预留给系统/其他用途的容量 Storage Maximum - Storage Reserved = Longhorn 认为这块盘可用于 volume 的 usable size 所以 Allocated 看的是“volume/replica 申请了多少容量”，不是实际写了多少数据。\n例如：一个 500Gi PVC，3 副本，如果 1 个副本落在这块盘上，那么这块盘的 Allocated Used 增加约 500Gi。即使业务实际只写了 20Gi，Allocated 仍然按 500Gi 算。\n2. 磁盘上的 Used 是怎么算的？ 磁盘上的 Used 通常显示为：\nUsed / Storage Maximum 它接近宿主机文件系统层面看到的真实占用。\n公式可以理解为：\nDisk Used = Storage Maximum - Storage Available 它包括：\nLonghorn replica 实际数据 Longhorn snapshot 数据 Longhorn metadata 该挂载点上其他文件 文件系统自身开销 Longhorn 文档说明，Dashboard 里的 Used 是 Longhorn、系统和其他应用实际已经使用的空间；Node 页面的 Used 左边表示当前 node 已用空间，整条 bar 表示 node 总空间。(Longhorn)\n所以 Used 不等于 Longhorn replica 的逻辑大小。它会受这些因素影响：\n业务实际写入量 snapshot 数量 是否执行过 snapshot purge guest filesystem 是否 discard / fstrim Longhorn 数据目录里是否有 orphaned data 宿主机上是否还有其他文件 把 Allocated 和 Used 放到同一块盘上看，最直观。下面这张图用 node22 的实测值，拆开一块盘的“容量构成”和两条分母不同的进度条：\n图 2：单块磁盘（node22，/var/lib/longhorn/）的容量构成与两种进度条。①容量 = Size + Reserved；②Allocated 的分母是 Size×超配比；③Used 的分母是 Storage Maximum。三者分母不同，别混着读。\n3. 节点上的 Allocated / Used 是怎么算的？ 节点级别基本就是把该节点下所有 Longhorn disk 汇总。\nNode Allocated Used = Σ 所有 disk 的 Allocated Used Node Allocated Max = Σ 所有 disk 的 Allocated Max Node Used = Σ 所有 disk 的 Used Node Total = Σ 所有 disk 的 Storage Maximum 节点的 Size 则是：\nNode Size = Σ (Storage Maximum - Storage Reserved) Longhorn 文档里也说，Node 页面的 Size 是 Longhorn volume 可使用的最大实际空间，等于节点总磁盘空间减去 reserved space。(Longhorn)\n上面图 1 的 o11y 集群里，每个节点只有 1 块盘，所以“节点级”数值与“磁盘级”完全一致：Size 101 Gi、Allocated 30 / 100.98 Gi、Used 各自约 23~36 / 144.26 Gi。多块盘时才需要按上面的公式求和。\n4. Storage Over Provisioning Percentage 的作用 这个参数控制的是 Allocated Max，也就是“最多允许调度多少逻辑容量”。\n公式：\nAllocated Max = (Storage Maximum - Storage Reserved) × OverProvisioning% 官方文档给出的定义是：StorageOverProvisioningPercentage 定义一块盘相对其 usable capacity 最多可以 schedule 多少存储，公式对应 ScheduledStorage / (MaximumStorage - ReservedStorage)。(Longhorn)\n实测提示：o11y 集群的超配比是 100%，所以图 1/图 2 里 Allocated Max ≈ Size（100.98 ≈ 101 Gi）。下面的例子为了体现“超配”效果用的是 200%，两者只是参数取值不同，公式一致。\n例如：\n磁盘总容量 Storage Maximum = 10 TiB Storage Reserved = 2 TiB Longhorn usable size = 8 TiB OverProvisioning = 200% 那么：\nAllocated Max = 8 TiB × 200% = 16 TiB 这表示 Longhorn 最多可以往这块盘上调度 16TiB 的 replica 逻辑容量，虽然真实 usable 只有 8TiB。\n这就是为什么你会看到：\nAllocated 可能大于真实磁盘容量 这是正常的，因为 Longhorn 是 thin provisioning / sparse file 思路：不是所有 PVC 一创建就真的写满。\n5. Storage Minimal Available Percentage 的作用 这个参数控制的是 真实可用空间下限。它不是控制 Allocated Max，而是防止真实磁盘太满。\nLonghorn/SUSE 文档说明，Storage Minimal Available Percentage 控制在调度新 replica 前，磁盘上必须保留的最小空闲比例；如果新增 replica 会让 available space 低于限制，Longhorn 会暂时把该 disk 标记为不可调度。(SUSE 文档)\n可以理解为：\n必须满足： Storage Available \u0026gt;= Storage Maximum × MinimalAvailablePercentage 在一些文档/版本示例里也会按 usable capacity 解释，但你实际排障时以 Longhorn 事件里的字段为准。报错事件里通常已经直接打印了：\nStorageAvailable StorageMaximum StorageReserved StorageScheduled OverProvisioningPercentage MinimalAvailablePercentage 所以判断时可以直接套事件里的值。\n举例：\nStorage Maximum = 10 TiB Minimal Available Percentage = 25% 那么 Longhorn 希望至少保留：\n10 TiB × 25% = 2.5 TiB 如果真实可用空间低于 2.5TiB，即使 Allocated 还没达到上限，Longhorn 也可能不再接受新 replica 或扩容。\n这就是 PVC 扩容失败的一个常见核心原因：不是 Allocated Max 一定满了，而是 Storage Available 没有达到 Minimal Available 的要求。\n6. Storage Reserved Percentage For Default Disk 的作用 这个参数只影响 默认磁盘的初始 reserved space。\nLonghorn/SUSE 文档说明，Storage Reserved Percentage For Default Disk 表示每个新 Longhorn 节点上的 default disk 有多少比例不会分配给 Longhorn；默认值是 30，并且它只影响安装时或新增节点时创建的 default disk。(SUSE 文档)\n公式：\nStorage Reserved = Storage Maximum × Storage Reserved Percentage For Default Disk 图 1/图 2 的 o11y 集群正好用的是默认 30%：Reserved 43.3 Gi ÷ Storage Maximum 144.26 Gi ≈ 30%，于是 Size = 144.26 − 43.3 ≈ 101 Gi。\n例如：\n新节点 default disk 总容量 = 10 TiB Storage Reserved Percentage For Default Disk = 30% 那么新 default disk 会自动预留：\n10 TiB × 30% = 3 TiB Longhorn usable size 变成：\n10 TiB - 3 TiB = 7 TiB 重要区别：Storage Reserved Percentage For Default Disk 只是在创建 default disk 时帮你生成一个 Storage Reserved 值。它不会持续动态调整已有磁盘的 reserved space。已有磁盘要改 reserved，需要在 Node → Edit Disks 或修改 nodes.longhorn.io 里的 disk storageReserved。\n7. 用一个完整例子说明 假设一个节点上有 1 块 Longhorn disk：\nStorage Maximum = 10 TiB Storage Reserved Percentage For Default Disk = 30% Storage Over Provisioning Percentage = 200% Storage Minimal Available Percentage = 25% 第一步：计算 Reserved 和 Size Storage Reserved = 10 TiB × 30% = 3 TiB Longhorn Size / Usable = 10 TiB - 3 TiB = 7 TiB UI 上可能看到：\nSize: 7 TiB +3 TiB Reserved 第二步：计算 Allocated Max Allocated Max = 7 TiB × 200% = 14 TiB 也就是说，Longhorn 最多允许在这块盘上调度 14TiB 的 replica 逻辑容量。\n第三步：调度几个 PVC 假设有这些 volume replica 被调度到这块盘：\nPVC A: 2 TiB PVC B: 1 TiB PVC C: 4 TiB 那么：\nAllocated Used = 2 + 1 + 4 = 7 TiB Allocated Max = 14 TiB UI 上看到：\nAllocated: 7 TiB / 14 TiB 这不代表真实已经用了 7TiB，只代表 Longhorn 已经承诺了 7TiB 逻辑容量。\n第四步：真实写入量 假设实际写入和快照占用如下：\nPVC A 实际占用 + snapshot = 1.2 TiB PVC B 实际占用 + snapshot = 0.3 TiB PVC C 实际占用 + snapshot = 2.5 TiB 系统/其他文件 = 0.5 TiB 那么：\nUsed = 1.2 + 0.3 + 2.5 + 0.5 = 4.5 TiB Available = 10 TiB - 4.5 TiB = 5.5 TiB UI 上看到：\nUsed: 4.5 TiB / 10 TiB 第五步：Minimal Available 检查 Minimal required free = 10 TiB × 25% = 2.5 TiB 当前：\nAvailable = 5.5 TiB 满足：\n5.5 TiB \u0026gt; 2.5 TiB 所以这块盘还能继续调度。\n第六步：什么时候会停止调度？ 有两个常见停止条件。\n条件 A：Allocated 达到 OverProvisioning 上限\nAllocated Used + 新 replica size \u0026gt; Allocated Max 例如当前：\nAllocated Used = 13.8 TiB Allocated Max = 14 TiB 再调度一个 500Gi replica：\n13.8 TiB + 0.5 TiB = 14.3 TiB \u0026gt; 14 TiB 失败。\n条件 B：真实 available 低于 Minimal Available 下限\n例如：\nUsed = 8 TiB Available = 2 TiB Minimal required free = 2.5 TiB 此时：\n2 TiB \u0026lt; 2.5 TiB 即使 Allocated 还没满，也会停止调度或扩容失败。\n8. 套到一块真实满盘上 再看一块真实的满盘 cf1cb878...（来自另一处更大的磁盘，不是上面 o11y 的 144Gi 盘），它大概是：\nSize: 4.04 TiB Reserved: +1.73 TiB Used: 5374.87 / 5913.54 Gi Allocated: 7644.9 / 8278.97 Gi OverProvisioning: 200% 反推：\nStorage Maximum ≈ 5913.54 Gi ≈ 5.77 TiB Storage Reserved ≈ 1.73 TiB Usable Size ≈ 4.04 TiB Allocated Max ≈ 4.04 TiB × 200% ≈ 8.08 TiB ≈ 8278.97 Gi 这就解释了为什么 Allocated Max 是 8278.97Gi：它不是物理盘大小，而是 Longhorn usable size × 200%。\n这块盘同时面临 Allocated 逻辑调度接近上限、真实 Used 又太高两股压力。下面这张图把两个上限画在一起：\n图 3：满盘案例的两个上限。限制 A 是 Allocated 逼近超配上限（剩 ~634 Gi）；限制 B 是真实可用（538.67 Gi）已低于 Max×25% ≈ 1478 Gi 的下限，于是磁盘变 Unschedulable。\n拆开看，当前 Allocated：\nAllocated Used = 7644.9 Gi Allocated Max = 8278.97 Gi 剩余可调度 ≈ 8278.97 - 7644.9 ≈ 634.07 Gi 再看真实空间：\nUsed = 5374.87 Gi Storage Maximum = 5913.54 Gi Available ≈ 5913.54 - 5374.87 = 538.67 Gi 如果 Storage Minimal Available Percentage = 25%，那么至少要保留的真实空闲空间大约是：\n5913.54 Gi × 25% ≈ 1478.39 Gi 但当前只有 538.67 Gi，所以这块盘会变成 Unschedulable。也就是说，它同时面临两个压力：\nAllocated 逻辑调度接近上限 真实 Used 已经太高，Available 低于 Minimal Available 要求 这也是为什么其他盘还空，但这个盘上的某些 replica 扩容会失败：扩容检查是针对当前 replica 所在 disk 做的。\n9. 最重要的关系总结 项目 表示什么 主要受什么影响 Storage Maximum 磁盘文件系统总容量 宿主机磁盘大小 Storage Reserved Longhorn 不使用的预留空间 手动设置或 Storage Reserved Percentage For Default Disk 初始生成 Size Longhorn 可用真实容量 Storage Maximum - Storage Reserved Allocated Used 已经调度出去的 replica 逻辑容量 PVC/Volume size、replica 数、调度位置 Allocated Max 最多允许调度多少逻辑容量 Size × Storage Over Provisioning Percentage Used 磁盘真实已用空间 真实写入、snapshot、系统文件、orphaned data Available 磁盘真实剩余空间 Storage Maximum - Used Storage Minimal Available Percentage 调度时必须保留的真实空闲空间比例 防止磁盘真实写满 Storage Over Provisioning Percentage 允许逻辑调度超过真实 usable 的比例 控制 Allocated Max Storage Reserved Percentage For Default Disk 新 default disk 初始预留比例 只影响 default disk 创建时的 Storage Reserved 一句话：\nAllocated 解决“Longhorn 承诺了多少容量”的问题；Used 解决“宿主机磁盘真实用了多少”的问题；Over Provisioning 限制 Allocated；Minimal Available 限制真实剩余空间；Reserved Percentage 只是在 default disk 创建时决定预留多少空间。\n参考 Longhorn 官方文档 · Node Space Usage：https://longhorn.io/docs/latest/nodes-and-volumes/nodes/node-space-usage/ Longhorn 官方文档 · Multiple Disk Support：https://longhorn.io/docs/1.11.0/nodes-and-volumes/nodes/multidisk/ SUSE 文档 · Longhorn Settings：https://documentation.suse.com/cloudnative/storage/1.11/en/longhorn-system/settings.html ","date":"2026-07-04T00:00:00Z","permalink":"/posts/posts/longhorn/longhorn-node-space-usage/","title":"Longhorn 节点存储用量详解：Allocated 与 Used 到底怎么算"},{"content":"NeuVector 的所有功能都可以通过 REST API 完成——从查询容器、扫描镜像，到管理网络策略、导出配置。当我们需要批量处理网络规则、把安全操作接入 CI/CD，或者做一些控制台里点起来很繁琐的重复动作时，直接调 API 往往是最高效的方式。\n本文聚焦三件事：如何在 Kubernetes 中把 REST API 暴露出来、如何用 API Key 完成认证，以及通过两个实用脚本（列出网络规则、批量清理 learned 规则）演示 API 的真实调用。\n一、开启（暴露）REST API NeuVector 的 REST API 由 Controller 提供，监听端口为 10443（HTTPS）。在 Kubernetes 中，Controller 默认只在集群内部可达。如果要从集群外调用 API，需要单独为 Controller 暴露一个 Service。\n官方推荐的做法是新建一个指向 neuvector-controller-pod 的 Service，开放 10443 端口。用 LoadBalancer 类型：\napiVersion: v1 kind: Service metadata: name: neuvector-svc-controller-api namespace: neuvector spec: ports: - port: 10443 name: controller-api protocol: TCP type: LoadBalancer selector: app: neuvector-controller-pod 如果集群没有 LoadBalancer，可以把 type 改成 NodePort，通过「节点 IP + 分配到的 NodePort」访问：\napiVersion: v1 kind: Service metadata: name: neuvector-svc-controller-api namespace: neuvector spec: ports: - port: 10443 name: controller-api protocol: TCP type: NodePort selector: app: neuvector-controller-pod 应用后确认 Service 的访问地址：\nkubectl get svc -n neuvector neuvector-svc-controller-api LoadBalancer：使用 EXTERNAL-IP 加端口 10443，即 https://\u0026lt;EXTERNAL-IP\u0026gt;:10443。 NodePort：使用任意节点 IP 加分配到的高位端口，例如 https://\u0026lt;节点IP\u0026gt;:30443。 说明：Controller 默认使用自签名证书，所以后面所有 curl 示例都带 -k 跳过证书校验。生产环境建议替换为受信任证书，并去掉 -k。多 Controller 部署时，涉及长任务状态轮询的请求应固定发往同一个 Controller IP。\n二、创建并使用 API Key REST API 支持两种认证方式：\n认证方式 请求头 特点 用户名/密码（Token） X-Auth-Token 先调用 /v1/auth 换取 token 再使用；每个用户并发会话数有限（最多 32），用完需 DELETE /v1/auth 释放 API Key（Token-based） X-Auth-Apikey 直接在每个请求里携带，无并发会话限制；按创建时设定的有效期过期，适合脚本与自动化 对脚本和自动化场景，API Key 更合适：它不需要先登录换 token，也没有并发会话数的限制。\n创建 API Key 在 NeuVector 控制台进入 Settings → Users, API Keys \u0026amp; Roles，新建一个 API Key：\n为 Key 绑定一个角色（内置角色或自定义角色），按最小权限原则限制它能访问的范围； 设置有效期； 创建后立即复制 Name 和 Secret——弹窗关闭后 Secret 将无法再次查看。 API Key 在请求中的用法是把 名称:密钥 放进 X-Auth-Apikey 请求头。一个最小的调用示例——获取所有网络规则：\ncurl -k -sS \\ -H \u0026#34;X-Auth-Apikey: \u0026lt;你的APIKey名称\u0026gt;:\u0026lt;你的APIKey密钥\u0026gt;\u0026#34; \\ -H \u0026#34;Accept: application/json\u0026#34; \\ \u0026#34;https://\u0026lt;controller-ip\u0026gt;:10443/v1/policy/rule\u0026#34; 小提醒：API Key 的密钥里可能包含 $、*、@、# 等特殊字符。在 Shell 里赋值时务必用单引号包裹，否则 Bash 会把 $xxx 当变量解析，导致认证失败：\nX_AUTH_APIKEY=\u0026#39;myapikey:cgmv3...*^dYBVy...@#Bfm...\u0026#39; 三、案例：网络规则的查询与清理 下面两个脚本演示 API Key 在真实场景中的用法：先只读地列出所有网络规则，再有选择地批量删除。两者都依赖 curl 和 jq（用于解析 JSON 返回），并用 -w '\\n%{http_code}' 捕获 HTTP 状态码方便排错。涉及的接口：\nGET /v1/policy/rule：获取全部网络规则； DELETE /v1/policy/rule/{id}：按 ID 删除单条规则。 脚本一：列出所有网络规则 ID（只读） 第一步先做只读操作，把规则列出来、心里有数，脚本本身不做任何修改：\n#!/usr/bin/env bash set -euo pipefail # Controller API 地址，格式示例：https://127.0.0.1:10443 CONTROLLER_API=\u0026#39;https://\u0026lt;controller-ip\u0026gt;:10443\u0026#39; # NeuVector API Key：名称:密钥。含特殊字符必须用单引号 X_AUTH_APIKEY=\u0026#39;\u0026lt;你的APIKey名称\u0026gt;:\u0026lt;你的APIKey密钥\u0026gt;\u0026#39; # 依赖检查：curl / jq command -v curl \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 || { echo \u0026#34;错误：未找到 curl\u0026#34;; exit 1; } command -v jq \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 || { echo \u0026#34;错误：未找到 jq\u0026#34;; exit 1; } echo \u0026#34;正在获取 NeuVector Network Rule：${CONTROLLER_API}/v1/policy/rule\u0026#34; # -k 跳过自签证书校验；-w 附带 HTTP 状态码 RESPONSE=\u0026#34;$( curl -k -sS \\ -w $\u0026#39;\\n%{http_code}\u0026#39; \\ -H \u0026#34;X-Auth-Apikey: ${X_AUTH_APIKEY}\u0026#34; \\ -H \u0026#34;Accept: application/json\u0026#34; \\ \u0026#34;${CONTROLLER_API}/v1/policy/rule\u0026#34; )\u0026#34; HTTP_STATUS=\u0026#34;${RESPONSE##*$\u0026#39;\\n\u0026#39;}\u0026#34; RESPONSE_BODY=\u0026#34;${RESPONSE%$\u0026#39;\\n\u0026#39;*}\u0026#34; echo \u0026#34;HTTP 状态码：${HTTP_STATUS}\u0026#34; # 非 2xx 视为失败，打印返回体 if [[ ! \u0026#34;${HTTP_STATUS}\u0026#34; =~ ^2[0-9][0-9]$ ]]; then echo \u0026#34;错误：API 请求失败\u0026#34;; echo \u0026#34;${RESPONSE_BODY}\u0026#34; | jq . 2\u0026gt;/dev/null || echo \u0026#34;${RESPONSE_BODY}\u0026#34; exit 1 fi RULE_COUNT=\u0026#34;$(echo \u0026#34;${RESPONSE_BODY}\u0026#34; | jq \u0026#39;.rules | length // 0\u0026#39;)\u0026#34; echo \u0026#34;rules 数量：${RULE_COUNT}\u0026#34; echo \u0026#34;Network Rule ID 列表：\u0026#34; echo \u0026#34;${RESPONSE_BODY}\u0026#34; | jq -r \u0026#39;.rules[] | \u0026#34; - \\(.id)\u0026#34;\u0026#39; echo \u0026#34;Network Rule 简要信息：\u0026#34; echo \u0026#34;${RESPONSE_BODY}\u0026#34; | jq -r \u0026#39;.rules[] | [.id, .from, .to, .ports, .action, .cfg_type] | @tsv\u0026#39; | awk \u0026#39;BEGIN { printf \u0026#34;%-10s %-30s %-30s %-15s %-10s %-12s\\n\u0026#34;, \u0026#34;ID\u0026#34;,\u0026#34;FROM\u0026#34;,\u0026#34;TO\u0026#34;,\u0026#34;PORTS\u0026#34;,\u0026#34;ACTION\u0026#34;,\u0026#34;CFG_TYPE\u0026#34; } { printf \u0026#34;%-10s %-30s %-30s %-15s %-10s %-12s\\n\u0026#34;, $1,$2,$3,$4,$5,$6 }\u0026#39; 关键点：\n用 X-Auth-Apikey 头完成认证，无需先登录换 token； 先校验 HTTP 状态码，再校验返回是否为合法 JSON，出错时把响应体打印出来，便于定位权限或接口问题； 网络规则在返回 JSON 的 .rules 数组里，每条规则包含 id、from、to、ports、action、cfg_type 等字段； 用 jq + awk 把结果整理成表格，一眼就能看清每条规则的来源和动作。 其中 cfg_type 字段很关键：它标识规则的来源。learned 表示 NeuVector 在学习模式下自动学习生成的规则，user_created 表示人工创建的规则。清理时通常只想删掉自动学习的那部分。\n脚本二：批量删除 learned 规则（带二次确认） 第二个脚本在第一个的基础上，筛选出 cfg_type == learned 的规则并批量删除。删除不可逆，所以脚本加了多重保护：\n#!/usr/bin/env bash set -euo pipefail CONTROLLER_API=\u0026#39;https://\u0026lt;controller-ip\u0026gt;:10443\u0026#39; X_AUTH_APIKEY=\u0026#39;\u0026lt;你的APIKey名称\u0026gt;:\u0026lt;你的APIKey密钥\u0026gt;\u0026#39; CONFIRM_TEXT=\u0026#39;DELETE\u0026#39; command -v curl \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 || { echo \u0026#34;错误：未找到 curl\u0026#34;; exit 1; } command -v jq \u0026gt;/dev/null 2\u0026gt;\u0026amp;1 || { echo \u0026#34;错误：未找到 jq\u0026#34;; exit 1; } # 1) 先获取全部规则 LIST_RESPONSE=\u0026#34;$( curl -k -sS -w $\u0026#39;\\n%{http_code}\u0026#39; \\ -H \u0026#34;X-Auth-Apikey: ${X_AUTH_APIKEY}\u0026#34; \\ -H \u0026#34;Accept: application/json\u0026#34; \\ \u0026#34;${CONTROLLER_API}/v1/policy/rule\u0026#34; )\u0026#34; LIST_HTTP_STATUS=\u0026#34;${LIST_RESPONSE##*$\u0026#39;\\n\u0026#39;}\u0026#34; LIST_RESPONSE_BODY=\u0026#34;${LIST_RESPONSE%$\u0026#39;\\n\u0026#39;*}\u0026#34; if [[ ! \u0026#34;${LIST_HTTP_STATUS}\u0026#34; =~ ^2[0-9][0-9]$ ]]; then echo \u0026#34;错误：获取 Network Rule 失败\u0026#34;; echo \u0026#34;${LIST_RESPONSE_BODY}\u0026#34; | jq . 2\u0026gt;/dev/null || echo \u0026#34;${LIST_RESPONSE_BODY}\u0026#34; exit 1 fi # 2) 只挑出 cfg_type == learned 的规则 ID，排序去重 mapfile -t RULE_IDS \u0026lt; \u0026lt;( echo \u0026#34;${LIST_RESPONSE_BODY}\u0026#34; | jq -r \u0026#39;.rules[]? | select(.cfg_type == \u0026#34;learned\u0026#34;) | .id // empty\u0026#39; | sort -n -u ) [[ \u0026#34;${#RULE_IDS[@]}\u0026#34; -eq 0 ]] \u0026amp;\u0026amp; { echo \u0026#34;没有 learned 规则可删。\u0026#34;; exit 0; } # 3) 安全校验：所有 ID 必须是数字 for RULE_ID in \u0026#34;${RULE_IDS[@]}\u0026#34;; do [[ \u0026#34;${RULE_ID}\u0026#34; =~ ^[0-9]+$ ]] || { echo \u0026#34;发现非数字 Rule ID，已中止：${RULE_ID}\u0026#34;; exit 1; } done echo \u0026#34;即将删除 ${#RULE_IDS[@]} 条 learned 规则，此操作不可逆。\u0026#34; # 4) 二次确认：必须手动输入 DELETE 才继续 read -r -p \u0026#34;如确认删除，请输入 ${CONFIRM_TEXT}: \u0026#34; USER_CONFIRM [[ \u0026#34;${USER_CONFIRM}\u0026#34; == \u0026#34;${CONFIRM_TEXT}\u0026#34; ]] || { echo \u0026#34;已取消删除。\u0026#34;; exit 0; } # 5) 逐条删除 for RULE_ID in \u0026#34;${RULE_IDS[@]}\u0026#34;; do echo \u0026#34;正在删除 Network Rule ID：${RULE_ID}\u0026#34; DELETE_RESPONSE=\u0026#34;$( curl -k -sS -w $\u0026#39;\\n%{http_code}\u0026#39; \\ -X DELETE \\ -H \u0026#34;X-Auth-Apikey: ${X_AUTH_APIKEY}\u0026#34; \\ -H \u0026#34;Accept: application/json\u0026#34; \\ -H \u0026#34;Content-Type: application/json\u0026#34; \\ \u0026#34;${CONTROLLER_API}/v1/policy/rule/${RULE_ID}\u0026#34; )\u0026#34; DELETE_HTTP_STATUS=\u0026#34;${DELETE_RESPONSE##*$\u0026#39;\\n\u0026#39;}\u0026#34; if [[ ! \u0026#34;${DELETE_HTTP_STATUS}\u0026#34; =~ ^2[0-9][0-9]$ ]]; then echo \u0026#34;错误：删除 ${RULE_ID} 失败\u0026#34;; echo \u0026#34;${DELETE_RESPONSE%$\u0026#39;\\n\u0026#39;*}\u0026#34; | jq . 2\u0026gt;/dev/null exit 1 fi echo \u0026#34;已删除：${RULE_ID}\u0026#34; done echo \u0026#34;所有 learned 规则删除完成。\u0026#34; 关键点：\n只删 learned：用 jq 的 select(.cfg_type == \u0026quot;learned\u0026quot;) 精确筛选，避免误删人工创建的规则； 数字校验：删除前逐个确认 Rule ID 都是数字，杜绝把异常值拼进删除 URL； 二次确认：必须手动输入 DELETE 才会真正执行，给不可逆操作加一道人工闸门； 逐条删除并检查状态码：每次 DELETE /v1/policy/rule/{id} 都单独判断 HTTP 状态，一旦失败立即停止并打印原因（常见于权限不足或规则已被占用）。 四、小结与注意事项 用 API Key 调用 NeuVector REST API 的完整链路很清晰：暴露 Controller 的 10443 端口 → 控制台创建带最小权限的 API Key → 请求里携带 X-Auth-Apikey 头。剩下的就是按 apis.yaml 里的接口定义去拼请求。\n几点建议：\n最小权限：给 API Key 绑定刚好够用的角色，尤其是涉及删除等写操作的场景； 妥善保管 Secret：创建时就复制保存，泄露或丢失都只能重建；并注意有效期； 特殊字符用单引号：Shell 里给 API Key 赋值一定用单引号，避免被当变量解析； 证书：-k 只适合测试；生产环境应配置受信任证书； 先只读再修改：批量操作前先用只读脚本确认范围，删除类操作务必保留二次确认。 完整的接口定义（各版本的 apis.yaml）建议以 Swagger 阅读器打开查看。\n参考 NeuVector 官方文档 · Kubernetes 部署与暴露 REST API：https://open-docs.neuvector.com/next/deploying/kubernetes#expose-rest-api-in-kubernetes NeuVector 官方文档 · REST API 与自动化：https://open-docs.neuvector.com/next/automation/automation REST API 接口定义 apis.yaml：https://github.com/neuvector/neuvector/blob/main/controller/api/apis.yaml ","date":"2026-07-04T00:00:00Z","permalink":"/posts/posts/neuvector/neuvector-api-with-apikey/","title":"NeuVector REST API 实战：开启 API 并用 API Key 管理网络规则"},{"content":"以下是关于 Kubernetes 中 Evicted、Failed、CrashLoopBackOff 和 Error 四种 Pod 状态的详细对比说明：\n一、状态区别与触发原因 状态 触发原因 典型场景 Evicted 节点资源不足（内存/磁盘压力） 节点 OOM、磁盘空间不足、超过资源配额 Failed Pod 内所有容器终止，且至少一个容器以非零状态退出 容器执行失败、应用崩溃、启动命令错误 CrashLoopBackOff 容器反复崩溃，Kubernetes 在重启之间增加延迟 应用持续崩溃、配置错误、依赖服务不可用 Error 容器无法启动（镜像问题/配置错误） 镜像拉取失败、启动命令错误、Volume 挂载失败 二、Kubernetes 处理逻辑对比 状态 Kubernetes 行为 是否尝试恢复 Evicted - 立即终止 Pod\n- 不会重新调度\n- 保留元数据用于诊断 ❌ 不会自动恢复 Failed - 根据 restartPolicy 决定行为\n- Never：保持状态\n- OnFailure：重启容器 ✅ 按策略可能重启 CrashLoopBackOff - 指数退避重启（延迟：10s→20s→40s\u0026hellip;上限 5min）\n- 持续监控容器状态 ✅ 持续尝试恢复 Error - 记录错误事件\n- 根据策略决定是否重启\n- 不会退避延迟 ✅ 立即尝试重启 重启策略说明 (spec.restartPolicy)：\nAlways：总是重启（默认） OnFailure：非零退出时重启 Never：不重启 三、自动清理机制对比 状态 是否自动清理 清理条件 Evicted ❌ 默认不清理 需手动或通过外部机制清理 Failed ⚠️ 有条件清理 - Job：达到 backoffLimit 后清理\n- 其他控制器：通常保留旧 Pod CrashLoopBackOff ❌ 不会自动清理 持续尝试恢复，需手动干预或设置自动清理 Error ❌ 不会自动清理 通常保留用于诊断 四、关键机制详解 1. Evicted 处理流程 graph TD A[节点资源压力] --\u003e B{kubelet 决策} B --\u003e|内存/磁盘不足| C[驱逐优先级最低的 Pod] C --\u003e D[标记 Pod 为 Evicted] D --\u003e E[保留元数据但释放资源] E --\u003e F[需外部清理]2. CrashLoopBackOff 退避算法 # 伪代码：指数退避重启 delay = 10 # 初始延迟（秒） max_delay = 300 # 最大延迟（5分钟） while pod_in_crashloop: if container_crashed: wait(delay) restart_container() delay = min(delay * 2, max_delay) # 指数退避 else: delay = 10 # 重置延迟 3. 控制器差异处理 Deployment/ReplicaSet\n创建新 Pod 替换故障 Pod，但保留旧 Pod（需设置 revisionHistoryLimit 清理） Job\nspec.backoffLimit 控制重试次数，超过后标记 Job 失败并清理 Pod 裸 Pod（无控制器）\n永不自动清理 五、最佳实践建议 Evicted 设置节点自动缩放（Cluster Autoscaler） 定期清理脚本（每日执行） kubectl get pods -A -o jsonpath=\u0026#39;{range .items[?(@.status.reason==\u0026#34;Evicted\u0026#34;)]}{.metadata.name}{\u0026#34;\\n\u0026#34;}{end}\u0026#39; | xargs -I{} kubectl delete pod {} --ignore-not-found CrashLoopBackOff 诊断命令： kubectl describe pod \u0026lt;pod-name\u0026gt; | grep -A 10 \u0026#34;Events:\u0026#34; kubectl logs \u0026lt;pod-name\u0026gt; --previous # 查看上次崩溃日志 Failed/Error 检查容器退出码： kubectl get pod \u0026lt;pod-name\u0026gt; -o jsonpath=\u0026#39;{.status.containerStatuses[].state.terminated.exitCode}\u0026#39; 常见退出码： 0：成功退出 1：应用错误 137：OOM 杀死 143：优雅终止 全局自动清理方案\n使用 ttlSecondsAfterFinished (仅限 Job) 或第三方控制器： apiVersion: batch/v1 kind: Job metadata: name: cleanup-job spec: ttlSecondsAfterFinished: 3600 # 1小时后自动删除 template: spec: containers: [...] 六、核心结论 状态本质区别：\nEvicted = 资源不足强制驱逐 Failed = 容器执行失败终止 CrashLoopBackOff = 崩溃循环恢复中 Error = 启动阶段致命错误 K8s 自动清理规则：\ngraph LR A[Pod状态] --\u003e B{是否有控制器} B --\u003e|无控制器| C[永不清理] B --\u003e|有控制器| D{控制器类型} D --\u003e|Job| E[达到 backoffLimit 后清理] D --\u003e|其他| F[保留旧Pod\n仅创建新副本] 生产环境建议： 为所有工作负载配置控制器（Deployment/StatefulSet/Job） 设置资源请求/限制防止 Evicted 实现自动化清理流水线（如 CronJob + 清理脚本） 监控关键事件：kubectl get events --field-selector type=Warning 通过理解这些状态背后的机制，您可以更有效地诊断集群问题并优化资源管理策略。\n","date":"2026-06-22T00:00:00Z","permalink":"/posts/posts/k8s/pod-status/","title":"pod状态解析"},{"content":"Linux 故障排查的第一步不是立刻修改配置，而是先建立足够清晰的观察面。CPU、内存、磁盘和网络通常能解释大多数系统层面的异常。\nCPU 使用 top 或 htop 可以快速判断系统是否存在 CPU 饱和。\ntop uptime mpstat 1 重点关注 load average、用户态 CPU、系统态 CPU、iowait 和上下文切换。如果 load 很高但 CPU 使用率不高，需要进一步判断是否存在 IO 阻塞。\n内存 内存排查可以先看整体，再看进程。\nfree -h vmstat 1 ps aux --sort=-%mem | head Linux 会把空闲内存用于缓存，因此不能只看 free 数值。更重要的是 available、swap 使用量和持续增长的内存占用。\n磁盘 磁盘问题常见表现是服务延迟升高。\ndf -h iostat -xz 1 du -sh /var/log/* 如果 await、util、iowait 长时间偏高，需要进一步定位是哪个进程产生了大量读写。\n网络 网络排查先确认连通性，再看端口和连接状态。\nip addr ss -tunlp curl -I https://example.com 生产环境中还需要关注 DNS、路由、防火墙、安全组和负载均衡配置。\n总结 性能排查要先观察，再假设，最后验证。稳定的命令组合能减少盲目操作，也能让故障复盘更容易。\n","date":"2026-06-19T00:00:00Z","permalink":"/posts/posts/linux/linux-observability-basics/","title":"Linux 性能排查的第一组命令"},{"content":"一、文档说明 本文档用于说明 install-rancher-server.sh 的使用方法。\n脚本功能：\n自动安装 Helm 自动配置 RKE2 Ingress Nginx Forward Header 自动添加 Rancher Helm Repo 支持 Rancher Prim 支持 Rancher Prime GC 支持指定 Rancher 版本 支持指定 Rancher 域名 支持 Harbor 私有镜像仓库 支持 Helm Upgrade/Install 二、前置条件 Kubernetes 集群 已安装并运行RKE2 验证：\nkubectl get nodes 示例：\nNAME STATUS ROLES node41 Ready control-plane,etcd,master 域名准备 确保 Rancher 域名已解析到负载均衡或 Ingress 地址。 例如：\nrancher.rancherlsp.com 外部 TLS 当前环境使用Nginx + TLS Rancher 配置：\ntls=external 脚本会自动配置：\ndata: use-forwarded-headers: \u0026#34;true\u0026#34; 三、脚本功能 脚本执行过程：\n安装 Helm ↓ 配置 ingress-nginx ↓ 添加 Rancher Helm Repo ↓ 更新 Repo ↓ 部署 Rancher ↓ 输出状态信息 四、默认参数 参数 默认值 RANCHER_EDITION prime-gc RANCHER_VERSION 2.13.0 RANCHER_GC_MINOR_VERSION 2.13 MY_HOSTNAME rancher.rancherlsp.com PRIVATE_REGISTRY harbor.rancherlsp.com RANCHER_IMAGE harbor.rancherlsp.com/prime/rancher HELM_VERSION v3.16.2 NAMESPACE cattle-system REPLICAS 1 BOOTSTRAP_PASSWORD Rancher12345 TLS_MODE external RELEASE_NAME rancher 五、Rancher install 脚本 拉取脚本命令 curl -fsSL https://raw.githubusercontent.com/wangzheivan/rancher-tools/refs/heads/main/rancher-install.sh -o rancher-install.sh chmod +x rancher-install.sh 脚本内容 #!/usr/bin/env bash set -euo pipefail # ========================= # 可配置变量 # ========================= # prime 或 prime-gc RANCHER_EDITION=\u0026#34;${RANCHER_EDITION:-prime-gc}\u0026#34; # Rancher Chart 版本，例如：2.13.0、2.12.3 RANCHER_VERSION=\u0026#34;${RANCHER_VERSION:-2.13.0}\u0026#34; # 仅 prime-gc 使用，用于拼接 charts.rancher.cn 仓库地址 # 例如：2.13 -\u0026gt; https://charts.rancher.cn/2.13-prime/latest RANCHER_GC_MINOR_VERSION=\u0026#34;${RANCHER_GC_MINOR_VERSION:-2.13}\u0026#34; # Rancher 访问域名 MY_HOSTNAME=\u0026#34;${MY_HOSTNAME:-rancher.rancherlsp.com}\u0026#34; # Harbor 地址，仅 prime-gc 使用 PRIVATE_REGISTRY=\u0026#34;${PRIVATE_REGISTRY:-harbor.rancherlsp.com}\u0026#34; # Rancher 镜像，仅 prime-gc 使用 RANCHER_IMAGE=\u0026#34;${RANCHER_IMAGE:-${PRIVATE_REGISTRY}/prime/rancher}\u0026#34; # Helm 版本 HELM_VERSION=\u0026#34;${HELM_VERSION:-v3.16.2}\u0026#34; # Kubernetes Namespace NAMESPACE=\u0026#34;${NAMESPACE:-cattle-system}\u0026#34; # Rancher 副本数 REPLICAS=\u0026#34;${REPLICAS:-1}\u0026#34; # 初始密码 BOOTSTRAP_PASSWORD=\u0026#34;${BOOTSTRAP_PASSWORD:-Rancher12345}\u0026#34; # TLS 模式 TLS_MODE=\u0026#34;${TLS_MODE:-external}\u0026#34; # Release 名称 RELEASE_NAME=\u0026#34;${RELEASE_NAME:-rancher}\u0026#34; # ========================= # 基础检查 # ========================= if [[ \u0026#34;$(id -u)\u0026#34; -ne 0 ]]; then echo \u0026#34;[ERROR] 请使用 root 用户执行\u0026#34; exit 1 fi if [[ \u0026#34;${RANCHER_EDITION}\u0026#34; != \u0026#34;prime\u0026#34; \u0026amp;\u0026amp; \u0026#34;${RANCHER_EDITION}\u0026#34; != \u0026#34;prime-gc\u0026#34; ]]; then echo \u0026#34;[ERROR] RANCHER_EDITION 只能是 prime 或 prime-gc\u0026#34; exit 1 fi if ! command -v kubectl \u0026gt;/dev/null 2\u0026gt;\u0026amp;1; then echo \u0026#34;[ERROR] 未找到 kubectl，请先安装并配置好 RKE2 集群\u0026#34; exit 1 fi if ! kubectl get nodes \u0026gt;/dev/null 2\u0026gt;\u0026amp;1; then echo \u0026#34;[ERROR] kubectl 无法访问当前 Kubernetes 集群\u0026#34; exit 1 fi # ========================= # 配置 RKE2 Ingress Nginx 支持外部 TLS / X-Forwarded-* 头 # ========================= echo \u0026#34;[INFO] 配置 rke2-ingress-nginx-controller ConfigMap...\u0026#34; kubectl -n kube-system patch configmap rke2-ingress-nginx-controller \\ --type merge \\ -p \u0026#39;{\u0026#34;data\u0026#34;:{\u0026#34;use-forwarded-headers\u0026#34;:\u0026#34;true\u0026#34;}}\u0026#39; # ========================= # 安装 Helm # ========================= if ! command -v helm \u0026gt;/dev/null 2\u0026gt;\u0026amp;1; then echo \u0026#34;[INFO] 安装 Helm ${HELM_VERSION}...\u0026#34; curl https://rancher-mirror.rancher.cn/helm/get-helm-3.sh | \\ INSTALL_HELM_MIRROR=cn \\ bash -s -- --version \u0026#34;${HELM_VERSION}\u0026#34; else echo \u0026#34;[INFO] Helm 已存在：$(helm version --short)\u0026#34; fi # ========================= # 添加 Rancher Helm Repo # ========================= if [[ \u0026#34;${RANCHER_EDITION}\u0026#34; == \u0026#34;prime\u0026#34; ]]; then RANCHER_REPO_URL=\u0026#34;https://charts.rancher.com/server-charts/prime\u0026#34; else RANCHER_REPO_URL=\u0026#34;https://charts.rancher.cn/${RANCHER_GC_MINOR_VERSION}-prime/latest\u0026#34; fi echo \u0026#34;[INFO] Rancher Edition : ${RANCHER_EDITION}\u0026#34; echo \u0026#34;[INFO] Rancher Version : ${RANCHER_VERSION}\u0026#34; echo \u0026#34;[INFO] Rancher Repo : ${RANCHER_REPO_URL}\u0026#34; echo \u0026#34;[INFO] Hostname : ${MY_HOSTNAME}\u0026#34; helm repo add rancher-prime \u0026#34;${RANCHER_REPO_URL}\u0026#34; --force-update helm repo update # ========================= # 部署 Rancher # ========================= if [[ \u0026#34;${RANCHER_EDITION}\u0026#34; == \u0026#34;prime\u0026#34; ]]; then echo \u0026#34;[INFO] 开始部署 Rancher Prime...\u0026#34; helm upgrade --install \u0026#34;${RELEASE_NAME}\u0026#34; rancher-prime/rancher \\ --namespace \u0026#34;${NAMESPACE}\u0026#34; \\ --create-namespace \\ --set hostname=\u0026#34;${MY_HOSTNAME}\u0026#34; \\ --set replicas=\u0026#34;${REPLICAS}\u0026#34; \\ --set global.cattle.psp.enabled=false \\ --set bootstrapPassword=\u0026#34;${BOOTSTRAP_PASSWORD}\u0026#34; \\ --set tls=\u0026#34;${TLS_MODE}\u0026#34; \\ --version \u0026#34;${RANCHER_VERSION}\u0026#34; else echo \u0026#34;[INFO] 开始部署 Rancher Prime GC...\u0026#34; echo \u0026#34;[INFO] Private Registry : ${PRIVATE_REGISTRY}\u0026#34; echo \u0026#34;[INFO] Rancher Image : ${RANCHER_IMAGE}\u0026#34; helm upgrade --install \u0026#34;${RELEASE_NAME}\u0026#34; rancher-prime/rancher \\ --namespace \u0026#34;${NAMESPACE}\u0026#34; \\ --create-namespace \\ --set hostname=\u0026#34;${MY_HOSTNAME}\u0026#34; \\ --set replicas=\u0026#34;${REPLICAS}\u0026#34; \\ --set global.cattle.psp.enabled=false \\ --set bootstrapPassword=\u0026#34;${BOOTSTRAP_PASSWORD}\u0026#34; \\ --set rancherImage=\u0026#34;${RANCHER_IMAGE}\u0026#34; \\ --set systemDefaultRegistry=\u0026#34;${PRIVATE_REGISTRY}\u0026#34; \\ --set tls=\u0026#34;${TLS_MODE}\u0026#34; \\ --version \u0026#34;${RANCHER_VERSION}\u0026#34; fi # ========================= # 输出状态 # ========================= echo echo \u0026#34;=======================================\u0026#34; echo \u0026#34;Rancher Server 部署完成\u0026#34; echo \u0026#34;=======================================\u0026#34; echo \u0026#34;Edition : ${RANCHER_EDITION}\u0026#34; echo \u0026#34;Version : ${RANCHER_VERSION}\u0026#34; echo \u0026#34;Namespace : ${NAMESPACE}\u0026#34; echo \u0026#34;Hostname : ${MY_HOSTNAME}\u0026#34; echo \u0026#34;TLS : ${TLS_MODE}\u0026#34; echo \u0026#34;=======================================\u0026#34; echo echo \u0026#34;查看 Pod：\u0026#34; echo \u0026#34;kubectl -n ${NAMESPACE} get pods\u0026#34; echo echo \u0026#34;查看 Helm Release：\u0026#34; echo \u0026#34;helm -n ${NAMESPACE} list\u0026#34; 创建脚本赋予权限：\nvi install-rancher-server.sh chmod +x install-rancher-server.sh 六、Prime GC 安装 默认执行：\n./install-rancher-server.sh 等价于：\nRANCHER_EDITION=prime-gc \\ RANCHER_VERSION=2.13.0 \\ RANCHER_GC_MINOR_VERSION=2.13 \\ MY_HOSTNAME=rancher.rancherlsp.com \\ ./install-rancher-server.sh 脚本内部将执行：\nhelm repo add rancher-prime \\ https://charts.rancher.cn/2.13-prime/latest helm upgrade --install rancher \\ rancher-prime/rancher rancherImage=harbor.rancherlsp.com/prime/rancher systemDefaultRegistry=harbor.rancherlsp.com 七、Prime 安装 执行：\nRANCHER_EDITION=prime \\ MY_HOSTNAME=rancher.rancherlsp.com \\ RANCHER_VERSION=2.13.0 \\ ./install-rancher-server.sh 脚本将使用：\nhelm repo add rancher-prime \\ https://charts.rancher.com/server-charts/prime helm upgrade --install rancher Prime 版本不会配置：\nrancherImage systemDefaultRegistry 八、自定义 Harbor 默认：\nharbor.rancherlsp.com 如果 Harbor 地址发生变化：\nPRIVATE_REGISTRY=harbor.example.com \\ ./install-rancher-server.sh 同时会自动更新：\nsystemDefaultRegistry 以及：\nrancherImage 九、自定义管理员密码 修改：\nBOOTSTRAP_PASSWORD=\u0026#39;MyPassword@123\u0026#39; \\ ./install-rancher-server.sh 十、卸载 Rancher 卸载 Release：\nhelm uninstall rancher -n cattle-system 删除 Namespace：\nkubectl delete ns cattle-system ","date":"2026-06-19T00:00:00Z","permalink":"/posts/posts/rancher/rancher-install-shell/","title":"Rancher Server一键安装脚本使用说明"},{"content":"文档说明 本文档用于通过 Harbor Proxy Cache 部署 RKE2 集群。\n当前环境：\n项目 值 Harbor地址 harbor.rancherlsp.com Harbor版本 2.14.4 RKE2安装方式 官方安装脚本 镜像加速方式 Harbor Proxy Cache 容器运行时 containerd kubectl安装方式 RKE2内置 crictl安装方式 RKE2内置 一、Harbor准备工作 1、创建Registry Endpoint 进入：\nAdministration └── Registries 创建以下 Endpoint：\nName Provider Endpoint docker.io Docker Hub 默认 registry.rancher.com Docker Registry https://registry.rancher.com registry.k8s.io Docker Registry https://registry.k8s.io quay.io Docker Registry https://quay.io ghcr.io Docker Registry https://ghcr.io gcr.io Docker Registry https://gcr.io 全部测试通过：\nHealthy 2、创建 Proxy Cache 项目 进入：\nProjects └── New Project 勾选：\nProxy Cache 创建：\ndocker.io registry.rancher.com registry.k8s.io quay.io ghcr.io gcr.io 并关联对应 Endpoint。\n二、一键安装脚本 保存如下脚本：\nvi install-rke2.sh 内容如下：\n#!/usr/bin/env bash set -euo pipefail # ========================= # 可配置变量 # ========================= RKE2_VERSION=\u0026#34;${RKE2_VERSION:-v1.34.7+rke2r1}\u0026#34; HARBOR_REGISTRY=\u0026#34;${HARBOR_REGISTRY:-harbor.rancherlsp.com}\u0026#34; INSTALL_TYPE=\u0026#34;${INSTALL_TYPE:-server}\u0026#34; # Agent节点需要 RKE2_SERVER_URL=\u0026#34;${RKE2_SERVER_URL:-}\u0026#34; RKE2_TOKEN=\u0026#34;${RKE2_TOKEN:-}\u0026#34; # ========================= # 基础检查 # ========================= if [[ \u0026#34;$(id -u)\u0026#34; -ne 0 ]]; then echo \u0026#34;请使用root用户执行\u0026#34; exit 1 fi if [[ \u0026#34;${INSTALL_TYPE}\u0026#34; != \u0026#34;server\u0026#34; \u0026amp;\u0026amp; \u0026#34;${INSTALL_TYPE}\u0026#34; != \u0026#34;agent\u0026#34; ]]; then echo \u0026#34;INSTALL_TYPE只能是server或agent\u0026#34; exit 1 fi if [[ \u0026#34;${INSTALL_TYPE}\u0026#34; == \u0026#34;agent\u0026#34; ]]; then if [[ -z \u0026#34;${RKE2_SERVER_URL}\u0026#34; || -z \u0026#34;${RKE2_TOKEN}\u0026#34; ]]; then echo \u0026#34;agent模式必须指定RKE2_SERVER_URL和RKE2_TOKEN\u0026#34; exit 1 fi fi mkdir -p /etc/rancher/rke2 # ========================= # 配置 Harbor 镜像代理 # ========================= cat \u0026gt; /etc/rancher/rke2/registries.yaml \u0026lt;\u0026lt;EOF mirrors: docker.io: endpoint: - https://${HARBOR_REGISTRY} rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;docker.io/\\\\\\$1\u0026#34; quay.io: endpoint: - https://${HARBOR_REGISTRY} rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;quay.io/\\\\\\$1\u0026#34; gcr.io: endpoint: - https://${HARBOR_REGISTRY} rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;gcr.io/\\\\\\$1\u0026#34; ghcr.io: endpoint: - https://${HARBOR_REGISTRY} rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;ghcr.io/\\\\\\$1\u0026#34; registry.k8s.io: endpoint: - https://${HARBOR_REGISTRY} rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;registry.k8s.io/\\\\\\$1\u0026#34; registry.rancher.com: endpoint: - https://${HARBOR_REGISTRY} rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;registry.rancher.com/\\\\\\$1\u0026#34; EOF # ========================= # Agent配置 # ========================= if [[ \u0026#34;${INSTALL_TYPE}\u0026#34; == \u0026#34;agent\u0026#34; ]]; then cat \u0026gt; /etc/rancher/rke2/config.yaml \u0026lt;\u0026lt;EOF server: ${RKE2_SERVER_URL} token: ${RKE2_TOKEN} EOF fi # ========================= # 安装RKE2 # ========================= curl -sfL https://get.rke2.io | \\ INSTALL_RKE2_VERSION=\u0026#34;${RKE2_VERSION}\u0026#34; \\ INSTALL_RKE2_TYPE=\u0026#34;${INSTALL_TYPE}\u0026#34; \\ sh - # ========================= # 启动服务 # ========================= if [[ \u0026#34;${INSTALL_TYPE}\u0026#34; == \u0026#34;server\u0026#34; ]]; then systemctl enable rke2-server systemctl start rke2-server else systemctl enable rke2-agent systemctl start rke2-agent fi # ========================= # 配置命令 # ========================= ln -sf /var/lib/rancher/rke2/bin/kubectl /usr/bin/kubectl ln -sf /var/lib/rancher/rke2/bin/ctr /usr/bin/ctr ln -sf /var/lib/rancher/rke2/bin/crictl /usr/bin/crictl # ========================= # 配置crictl # ========================= crictl config runtime-endpoint unix:///run/k3s/containerd/containerd.sock crictl config image-endpoint unix:///run/k3s/containerd/containerd.sock # ========================= # 配置 kubeconfig # ========================= if [[ \u0026#34;${INSTALL_TYPE}\u0026#34; == \u0026#34;server\u0026#34; ]]; then mkdir -p /root/.kube cp /etc/rancher/rke2/rke2.yaml /root/.kube/config chmod 600 /root/.kube/config fi echo echo \u0026#34;=======================================\u0026#34; echo \u0026#34;RKE2 安装完成\u0026#34; echo \u0026#34;=======================================\u0026#34; echo \u0026#34;Version : ${RKE2_VERSION}\u0026#34; echo \u0026#34;Type : ${INSTALL_TYPE}\u0026#34; echo \u0026#34;Harbor : ${HARBOR_REGISTRY}\u0026#34; echo \u0026#34;=======================================\u0026#34; 三、安装 Server 节点 赋予权限安装：\nchmod +x install-rke2.sh ./install-rke2.sh 指定版本：\nRKE2_VERSION=v1.34.7+rke2r1 ./install-rke2.sh 四、安装 Agent 节点 执行：\nINSTALL_TYPE=agent \\ RKE2_SERVER_URL=https://192.168.1.100:9345 \\ RKE2_TOKEN=K10c0f4d5a4e3...... \\ ./install-rke2.sh ","date":"2026-06-19T00:00:00Z","permalink":"/posts/posts/rke2/rke2-install-shell/","title":"RKE2集群一键安装脚本使用说明"},{"content":"环境信息 项目 信息 Harbor版本 2.14.4 Harbor地址 harbor.rancherlsp.com RKE2版本 v1.34.7+rke2r1 镜像代理方式 Harbor Proxy Cache 容器运行时 containerd 一、Harbor配置 创建Registry Endpoint 进入：\nAdministration └── Registries 创建以下 Endpoint：\nName Provider Endpoint docker.io Docker Hub 默认 registry.rancher.com Docker Registry https://registry.rancher.com registry.k8s.io Docker Registry https://registry.k8s.io quay.io Docker Registry https://quay.io ghcr.io Docker Registry https://ghcr.io gcr.io Docker Registry https://gcr.io 测试连接均应显示：\nHealthy 创建 Proxy Cache 项目 进入：\nProjects └── New Project 勾选：\nProxy Cache 分别创建：\ndocker.io registry.rancher.com registry.k8s.io quay.io ghcr.io gcr.io 并关联对应 Endpoint。\n最终效果：\ndocker.io registry.rancher.com registry.k8s.io quay.io ghcr.io gcr.io 均为：\nProxy Cache 类型项目。\n二、RKE2节点配置 创建目录：\nmkdir -p /etc/rancher/rke2 创建 registries.yaml\n文件：\nvi /etc/rancher/rke2/registries.yaml 内容：\nmirrors: docker.io: endpoint: - https://harbor.rancherlsp.com rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;docker.io/$1\u0026#34; quay.io: endpoint: - https://harbor.rancherlsp.com rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;quay.io/$1\u0026#34; gcr.io: endpoint: - https://harbor.rancherlsp.com rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;gcr.io/$1\u0026#34; ghcr.io: endpoint: - https://harbor.rancherlsp.com rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;ghcr.io/$1\u0026#34; registry.k8s.io: endpoint: - https://harbor.rancherlsp.com rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;registry.k8s.io/$1\u0026#34; registry.rancher.com: endpoint: - https://harbor.rancherlsp.com rewrite: \u0026#34;(^.+$)\u0026#34;: \u0026#34;registry.rancher.com/$1\u0026#34; configs: harbor.rancherlsp.com: auth: username: admin password: HarborPassword 如果 Harbor 使用自签证书：\nconfigs: harbor.rancherlsp.com: auth: username: admin password: HarborPassword tls: insecure_skip_verify: true 三、安装RKE2 Server 执行：\ncurl -sfL https://get.rke2.io | \\ INSTALL_RKE2_VERSION=v1.34.7+rke2r1 \\ INSTALL_RKE2_TYPE=server \\ sh - 启动服务：\nsystemctl enable rke2-server systemctl start rke2-server 查看状态：\nsystemctl status rke2-server 查看日志：\njournalctl -u rke2-server -f 四、验证镜像代理 测试拉取：\n/var/lib/rancher/rke2/bin/crictl pull \\ registry.rancher.com/rancher/rke2-runtime:v1.34.7-rke2r1 成功后进入 Harbor：\nProjects └── registry.rancher.com 可以看到：\nrancher/rke2-runtime 镜像已经自动缓存。\n五、后续扩展 当安装以下组件时：\nRancher Longhorn Cert-Manager Monitoring Logging Istio Cilium 涉及：\ndocker.io quay.io ghcr.io registry.k8s.io registry.rancher.com 镜像会自动经过 Harbor Proxy Cache，无需再修改 Helm Chart 镜像地址。 实现效果： Node ↓ RKE2/containerd ↓ Harbor Proxy Cache ↓ Internet Registry\n首次拉取缓存，后续全部走 Harbor 本地镜像。\n","date":"2026-06-19T00:00:00Z","permalink":"/posts/posts/rke2/rke2-install-with-harborproxy/","title":"RKE2通过 Harbor镜像代理部署指南"},{"content":"1. 文档说明 本文档用于指导在 RKE2 Kubernetes 集群中安装 SUSE Observability。安装过程包含 Longhorn 存储环境准备、离线/私有镜像仓库镜像准备、证书准备、Helm values 配置以及 SUSE Observability 安装。\n说明：本文中的域名、IP、Harbor 地址、用户名、密码、License Key 等均为示例或现场环境值。生产环境中请根据实际情况替换，并避免将明文密码提交到代码仓库或共享文档中。\n2. 环境信息 项目 示例值 Kubernetes 发行版 RKE2 存储方案 Longhorn SUSE Observability Chart 版本 2.10.1 SUSE Observability Namespace suse-observability Longhorn Namespace longhorn-system 私有镜像仓库 harbor.rancherlsp.com SUSE Observability 访问域名 o11y.rancherlsp.com OTLP gRPC 域名 o11y-otlp.rancherlsp.com OTLP HTTP 域名 o11y-otlp-http.rancherlsp.com TLS Secret 名称 suse-o11y-tls 3. 前置条件 安装前请确认以下条件已满足：\nRKE2 集群已正常运行。 kubectl 可正常访问目标集群。 Helm 已安装并可正常使用。 Rancher UI 可访问，用于部署 Longhorn。 Harbor 私有镜像仓库已部署完成，并可从集群节点访问。 已准备 SUSE Observability License Key。 已准备 DNS 解析或本地 hosts 解析，例如： 192.168.50.22 o11y.rancherlsp.com 192.168.50.22 o11y-otlp.rancherlsp.com 192.168.50.22 o11y-otlp-http.rancherlsp.com 4. 准备 Longhorn 环境 在可访问 Kubernetes 集群的节点上执行以下命令：\n# 获取longhornctl工具 curl -L https://github.com/longhorn/cli/releases/download/v1.12.0/longhornctl-linux-amd64 -o longhornctl chmod +x longhornctl mv ./longhornctl /usr/local/bin/longhornctl # 创建 Longhorn Namespace kubectl create namespace longhorn-system #如 namespace 已存在，可忽略相关提示。 #执行 Longhorn 预检查 longhornctl install preflight longhornctl check preflight #请确认预检查结果无阻断性错误。如存在缺失依赖、内核模块或系统配置问题，请先根据提示修复。 # 通过 Rancher UI 部署 Longhorn #完成预检查后，在 Rancher UI 中部署 Longhorn： #确认存在 Longhorn StorageClass，并且 Longhorn 组件运行正常。 5. 镜像准备 本步骤建议在 Harbor 节点或可同时访问互联网与 Harbor 的节点上操作。\n#添加 SUSE Observability Helm 仓库 helm repo add suse-observability https://charts.rancher.com/server-charts/prime/suse-observability helm repo update 下载 SUSE Observability Chart helm fetch suse-observability/suse-observability --version 2.10.1 #下载完成后，当前目录下会生成类似文件： #suse-observability-2.10.1.tgz #下载 values helper chart helm fetch suse-observability/suse-observability-values --version 2.10.1 #下载完成后，当前目录下会生成类似文件： suse-observability-values-2.10.1.tgz #下载镜像处理脚本 curl -LO https://raw.githubusercontent.com/StackVista/helm-charts/master/stable/suse-observability/installation/o11y-get-images.sh curl -LO https://raw.githubusercontent.com/StackVista/helm-charts/master/stable/suse-observability/installation/o11y-save-images.sh curl -LO https://raw.githubusercontent.com/StackVista/helm-charts/master/stable/suse-observability/installation/o11y-load-images.sh #添加脚本执行权限 chmod a+x o11y-get-images.sh o11y-save-images.sh o11y-load-images.sh #提取镜像列表 ./o11y-get-images.sh -f suse-observability-2.10.1.tgz \u0026gt; o11y-images.txt #检查镜像列表： cat o11y-images.txt #配置 Harbor 认证信息 export DST_REGISTRY_USERNAME=\u0026#34;admin\u0026#34; export DST_REGISTRY_PASSWORD=\u0026#34;\u0026lt;Harbor 管理员密码\u0026gt;\u0026#34; #推送镜像到 Harbor ./o11y-save-images.sh ./o11y-load-images.sh 6. 安装 SUSE Observability 以下步骤在 RKE2 集群管理节点上执行。\n添加 Helm 仓库 helm repo add suse-observability https://charts.rancher.com/server-charts/prime/suse-observability helm repo update kubectl create namespace suse-observability 如 namespace 已存在，可忽略相关提示。 --- ## 7. 准备 TLS 证书 执行以下命令生成自签名证书： ```bash ./create_self-signed-cert.sh \\ --ssl-domain=o11y.rancherlsp.com \\ --ssl-trusted-domain=o11y-otlp.rancherlsp.com,o11y-otlp-http.rancherlsp.com \\ --ssl-trusted-ip=192.168.50.22,192.168.50.23,192.168.50.24 \\ --ssl-size=2048 \\ --ssl-date=3650 生成后应得到以下文件：\ntls.crt tls.key 创建 Kubernetes TLS Secret\nkubectl -n suse-observability create secret tls suse-o11y-tls \\ --cert=tls.crt \\ --key=tls.key 验证 Secret：\nkubectl -n suse-observability get secret suse-o11y-tls 7. 准备 Helm Values 创建 values.yaml 文件：\nglobal: # 可选：覆盖默认镜像仓库。 # 默认镜像仓库为 registry.rancher.com。 # 离线环境或使用私有镜像仓库时需要配置该参数。 imageRegistry: \u0026#34;harbor.rancherlsp.com\u0026#34; suseObservability: # 必填：SUSE Observability License Key license: \u0026#34;\u0026lt;SUSE Observability License Key\u0026gt;\u0026#34; # 必填：SUSE Observability 访问地址 baseUrl: \u0026#34;https://o11y.rancherlsp.com\u0026#34; # 必填：规格配置 # 可选值：trial, 10-nonha, 20-nonha, 50-nonha, 100-nonha, # 150-ha, 250-ha, 500-ha, 4000-ha sizing: profile: \u0026#34;trial\u0026#34; # 必填：管理员明文密码 # 生产环境建议使用 adminPasswordBcrypt 替代明文密码 adminPassword: \u0026#34;\u0026lt;Admin Password\u0026gt;\u0026#34; # 如需使用 bcrypt 加密密码，可使用以下方式生成： # htpasswd -bnBC 10 \u0026#34;\u0026#34; \u0026#34;your-password\u0026#34; | tr -d \u0026#39;:\\n\u0026#39; # adminPasswordBcrypt: \u0026#34;$2a$10$...\u0026#34; # 可选：Receiver API Key，不配置时自动生成 # receiverApiKey: \u0026#34;your-receiver-api-key\u0026#34; # 可选：Pod 调度亲和性配置 # affinity: # nodeAffinity: ... # podAntiAffinity: # requiredDuringSchedulingIgnoredDuringExecution: true 请将 \u0026lt;SUSE Observability License Key\u0026gt; 与 \u0026lt;Admin Password\u0026gt; 替换为实际值\n创建 ingress_values.yaml 文件：\ningress: enabled: true annotations: nginx.ingress.kubernetes.io/proxy-body-size: \u0026#34;50m\u0026#34; nginx.ingress.kubernetes.io/ssl-redirect: \u0026#34;true\u0026#34; hosts: - host: o11y.rancherlsp.com tls: - hosts: - o11y.rancherlsp.com secretName: suse-o11y-tls 8. 执行 Helm 安装 执行以下命令安装 SUSE Observability：\nhelm upgrade \\ --install \\ --version 2.10.1 \\ --namespace suse-observability \\ --values values.yaml \\ --values ingress_values.yaml \\ suse-observability \\ suse-observability/suse-observability 9. 安装流程汇总 # 1. 准备 Longhorn curl -L https://github.com/longhorn/cli/releases/download/v1.12.0/longhornctl-linux-amd64 -o longhornctl chmod +x longhornctl mv ./longhornctl /usr/local/bin/longhornctl kubectl create namespace longhorn-system export KUBECONFIG=/root/.kube/config longhornctl install preflight longhornctl check preflight # 2. 在 Rancher UI 中部署 Longhorn，配置保持默认 # 3. 下载 SUSE Observability Chart 与镜像脚本 helm repo add suse-observability https://charts.rancher.com/server-charts/prime/suse-observability helm repo update helm fetch suse-observability/suse-observability --version 2.10.1 helm fetch suse-observability/suse-observability-values --version 2.10.1 curl -LO https://raw.githubusercontent.com/StackVista/helm-charts/master/stable/suse-observability/installation/o11y-get-images.sh curl -LO https://raw.githubusercontent.com/StackVista/helm-charts/master/stable/suse-observability/installation/o11y-save-images.sh curl -LO https://raw.githubusercontent.com/StackVista/helm-charts/master/stable/suse-observability/installation/o11y-load-images.sh chmod a+x o11y-get-images.sh o11y-save-images.sh o11y-load-images.sh ./o11y-get-images.sh -f suse-observability-2.10.1.tgz \u0026gt; o11y-images.txt # 4. 创建 SUSE Observability namespace kubectl create namespace suse-observability # 5. 创建 TLS Secret kubectl -n suse-observability create secret tls suse-o11y-tls \\ --cert=tls.crt \\ --key=tls.key # 6. 安装 SUSE Observability helm upgrade \\ --install \\ --version 2.10.1 \\ --namespace suse-observability \\ --values values.yaml \\ --values ingress_values.yaml \\ suse-observability \\ suse-observability/suse-observability ","date":"2026-06-19T00:00:00Z","permalink":"/posts/posts/observability/o11y-install/","title":"SUSE Observability 安装部署文档"},{"content":"Kubernetes 的对象很多，但初学时可以先把应用发布理解成几个核心对象之间的协作。\nDeployment Deployment 描述应用副本、镜像版本和滚动更新策略。它负责把期望状态持续同步到集群中。\napiVersion: apps/v1 kind: Deployment metadata: name: demo-api spec: replicas: 2 selector: matchLabels: app: demo-api template: metadata: labels: app: demo-api spec: containers: - name: api image: nginx:1.27 Service Pod 会变化，Service 提供稳定访问入口。应用之间通常不直接访问 Pod IP，而是访问 Service。\nConfigMap ConfigMap 用于保存非敏感配置，例如日志级别、开关项、普通配置文件。敏感信息应使用 Secret 或外部密钥系统。\nIngress Ingress 把集群外部流量转发到集群内部服务，通常和 Nginx Ingress Controller、Traefik 或云厂商网关配合使用。\n总结 第一阶段可以记住一条主线：Deployment 运行应用，Service 暴露稳定入口，ConfigMap 注入配置，Ingress 接入外部流量。\n","date":"2026-06-18T00:00:00Z","permalink":"/posts/posts/cloud-native/kubernetes-workload-overview/","title":"Kubernetes 工作负载的最小理解模型"},{"content":"RAG 是把外部知识接入大模型的常见方式。它并不神秘，本质上是一条从文档到答案的工程链路。\n文档切分 文档需要被切成适合检索的片段。切分太大，召回不精准；切分太小，上下文容易丢失。常见做法是按标题、段落和固定 token 数组合切分。\n向量化 每个片段通过 embedding 模型转换为向量，并写入向量数据库。元数据需要保留来源、标题、时间、权限等信息。\n检索 用户问题也会被向量化，然后在向量库中查找相似片段。工程上经常会结合关键词搜索，形成混合检索。\n重排 初步召回的结果不一定最适合回答问题，可以通过 rerank 模型重新排序，把更相关的片段放到前面。\n生成 最后把问题和检索结果拼成 prompt，交给大模型生成答案。输出需要包含引用来源，降低幻觉风险。\n总结 RAG 的质量来自每个环节的稳定性。比起只调 prompt，更重要的是文档治理、检索评估和可观测性。\n","date":"2026-06-17T00:00:00Z","permalink":"/posts/posts/ai/llm-rag-starter/","title":"RAG 应用的基础架构拆解"},{"content":"静态博客的运维成本很低，适合个人技术博客。Hugo 负责生成页面，Pagefind 负责生成本地搜索索引，Cloudflare Pages 负责自动构建和分发。\n构建命令 项目中的 package.json 提供了生产构建命令：\nnpm run build 它会执行 Hugo 构建，然后对 public 目录生成 Pagefind 索引。\nCloudflare Pages 配置 推荐配置如下：\n配置项 值 Build command npm run build Build output directory public Environment variable HUGO_VERSION=0.163.3 Node.js version 20 搜索索引 Pagefind 会把搜索资源输出到 public/pagefind。搜索页通过 /pagefind/pagefind-ui.js 和 /pagefind/pagefind-ui.css 加载搜索组件，不需要数据库或后端服务。\n总结 这种架构把复杂度放在构建阶段，线上只托管静态资源。对于技术博客来说，性能、成本和可维护性都比较均衡。\n","date":"2026-06-16T00:00:00Z","permalink":"/posts/posts/devops/cloudflare-pages-hugo-pagefind/","title":"用 Cloudflare Pages 部署 Hugo 与 Pagefind"}]