Go K8s資源配額治理實戰:多租戶資源隔離的6個關鍵實踐
當一個團隊吃掉整個叢集:多租戶資源隔離的至暗時刻
凌晨2點,資料團隊跑了一個全量ETL Job,CPU和記憶體瞬間佔滿叢集。API服務Pod被驅逐,前端閘道器OOM Kill,整個平臺癱瘓90分鐘。更糟的是,事後發現該團隊佔用了叢集70%資源,但成本分攤記錄為零——沒人知道誰用了多少。
這不是個例。資源爭搶導致雪崩、命名空間無限制、CPU/記憶體被個別團隊佔滿、成本無法分攤,已成為K8s多租戶環境的四大痛點。ResourceQuota限制命名空間資源總量,LimitRange約束單個Pod資源範圍,PriorityClass保障關鍵服務優先——三者協同才能實現真正的多租戶資源隔離。本文將從6個關鍵實踐出發,帶你構建生產級K8s資源配額治理體系。
核心概念速查
| 概念 | 全稱 | 作用 | 關鍵參數 |
|---|---|---|---|
| ResourceQuota | — | 限制命名空間資源總量 | hard.limits.cpu/memory/pods |
| LimitRange | — | 約束單個Pod/容器資源範圍 | default/defaultRequest/max/min |
| 多租戶 | Multi-Tenancy | 多團隊共享叢集資源 | 命名空間隔離、RBAC |
| 命名空間隔離 | Namespace Isolation | 邏輯隔離不同團隊資源 | NetworkPolicy + ResourceQuota |
| 請求與限制 | Requests & Limits | Pod資源申請與上限 | resources.requests/limits |
| QoS等級 | Quality of Service | Pod服務品質分級 | Guaranteed/Burstable/BestEffort |
| 優先級 | PriorityClass | Pod排程優先級定義 | value/preemptionPolicy |
| 搶佔 | Preemption | 高優先級Pod驅逐低優先級Pod | PreemptLowerPriority |
問題分析:多租戶資源治理的5大挑戰
挑戰1:資源爭搶與雪崩。某團隊部署無資源限制的Job,瞬間耗盡節點CPU/記憶體,導致其他團隊Pod被驅逐或OOM Kill,引發連鎖故障。
挑戰2:配額設定粒度。ResourceQuota設太嚴導致團隊無法正常部署,設太鬆形同虛設。不同團隊負載特徵差異大,統一配額無法適配。
挑戰3:優先級與搶佔。關鍵服務與批次處理任務混部時,批次處理任務可能佔滿資源,關鍵服務無法排程。缺乏優先級機制導致「誰先部署誰佔資源」。
挑戰4:成本歸因。多個團隊共享叢集,但缺乏按命名空間的資源使用計量,無法準確分攤雲成本,財務團隊只能「拍腦袋」分攤。
挑戰5:資源碎片化。各命名空間配額之和超過叢集實際容量,導致資源超賣。節點上零散的空閒資源無法滿足新Pod排程,形成資源碎片。
實踐1:ResourceQuota命名空間配額
apiVersion: v1
kind: Namespace
metadata:
name: team-data
labels:
tenant: data-team
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-data-quota
namespace: team-data
spec:
hard:
requests.cpu: "16"
requests.memory: 32Gi
limits.cpu: "32"
limits.memory: 64Gi
pods: "50"
services: "10"
persistentvolumeclaims: "20"
scopes:
- Terminating
- NotTerminating
package main
import (
"context"
"fmt"
"os"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func createNamespaceQuota(ctx context.Context, clientset *kubernetes.Clientset, nsName string, cpuReq, memReq, cpuLimit, memLimit string) error {
ns := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: nsName,
Labels: map[string]string{"tenant": nsName},
},
}
_, err := clientset.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("create namespace: %w", err)
}
quota := &corev1.ResourceQuota{
ObjectMeta: metav1.ObjectMeta{
Name: nsName + "-quota",
Namespace: nsName,
},
Spec: corev1.ResourceQuotaSpec{
Hard: corev1.ResourceList{
corev1.ResourceRequestsCPU: resource.MustParse(cpuReq),
corev1.ResourceRequestsMemory: resource.MustParse(memReq),
corev1.ResourceLimitsCPU: resource.MustParse(cpuLimit),
corev1.ResourceLimitsMemory: resource.MustParse(memLimit),
corev1.ResourcePods: resource.MustParse("50"),
corev1.ResourceServices: resource.MustParse("10"),
corev1.ResourcePersistentVolumeClaims: resource.MustParse("20"),
},
},
}
_, err = clientset.CoreV1().ResourceQuotas(nsName).Create(ctx, quota, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("create quota: %w", err)
}
fmt.Printf("Created quota for namespace %s\n", nsName)
return nil
}
func main() {
config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
if err != nil {
fmt.Fprintf(os.Stderr, "build config: %v\n", err)
os.Exit(1)
}
cs, err := kubernetes.NewForConfig(config)
if err != nil {
fmt.Fprintf(os.Stderr, "create clientset: %v\n", err)
os.Exit(1)
}
ctx := context.Background()
teams := []struct {
name, cpuReq, memReq, cpuLimit, memLimit string
}{
{"team-data", "16", "32Gi", "32", "64Gi"},
{"team-api", "8", "16Gi", "16", "32Gi"},
{"team-frontend", "4", "8Gi", "8", "16Gi"},
}
for _, t := range teams {
if err := createNamespaceQuota(ctx, cs, t.name, t.cpuReq, t.memReq, t.cpuLimit, t.memLimit); err != nil {
fmt.Fprintf(os.Stderr, "failed for %s: %v\n", t.name, err)
}
}
}
ResourceQuota限制命名空間資源總量,hard欄位定義CPU/記憶體/Pod數等上限。關鍵原則:requests控制排程保障,limits控制實際消耗上限,兩者必須同時設定。scopes可針對Terminating/NotTerminating型別分別配額。
實踐2:LimitRange預設資源限制
apiVersion: v1
kind: LimitRange
metadata:
name: team-data-limits
namespace: team-data
spec:
limits:
- type: Container
default:
cpu: "1"
memory: 1Gi
defaultRequest:
cpu: 200m
memory: 256Mi
max:
cpu: "4"
memory: 8Gi
min:
cpu: 50m
memory: 64Mi
maxLimitRequestRatio:
cpu: "5"
memory: "4"
- type: Pod
max:
cpu: "8"
memory: 16Gi
- type: PersistentVolumeClaim
max:
storage: 50Gi
min:
storage: 1Gi
LimitRange為未設定資源的容器自動注入default和defaultRequest,max/min約束資源範圍,maxLimitRequestRatio防止limit遠大於request造成超賣。關鍵:沒有LimitRange,未設資源的Pod預設BestEffort,可能無限佔用資源。
實踐3:QoS等級與保障策略
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-service
namespace: team-api
spec:
replicas: 3
selector:
matchLabels:
app: api-service
template:
metadata:
labels:
app: api-service
spec:
containers:
- name: api-service
image: api-service:latest
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: batch-job-runner
namespace: team-data
spec:
replicas: 2
selector:
matchLabels:
app: batch-job-runner
template:
metadata:
labels:
app: batch-job-runner
spec:
containers:
- name: runner
image: batch-runner:latest
resources:
requests:
cpu: 100m
memory: 128Mi
package main
import (
"fmt"
corev1 "k8s.io/api/core/v1"
)
func classifyQoS(pod *corev1.Pod) string {
hasRequests := false
hasLimits := false
for _, c := range pod.Spec.Containers {
if c.Resources.Requests.Cpu().IsZero() || c.Resources.Requests.Memory().IsZero() {
return "BestEffort"
}
hasRequests = true
if c.Resources.Limits.Cpu().IsZero() || c.Resources.Limits.Memory().IsZero() {
hasLimits = false
} else {
hasLimits = true
}
}
if hasRequests && hasLimits {
requestsEqualLimits := true
for _, c := range pod.Spec.Containers {
if !c.Resources.Requests.Cpu().Equal(*c.Resources.Limits.Cpu()) ||
!c.Resources.Requests.Memory().Equal(*c.Resources.Limits.Memory()) {
requestsEqualLimits = false
break
}
}
if requestsEqualLimits {
return "Guaranteed"
}
}
return "Burstable"
}
func main() {
pods := []struct {
name string
pod *corev1.Pod
}{
{"Guaranteed", &corev1.Pod{}},
{"Burstable", &corev1.Pod{}},
{"BestEffort", &corev1.Pod{}},
}
for _, p := range pods {
fmt.Printf("Pod %s: QoS=%s\n", p.name, classifyQoS(p.pod))
}
}
K8s將Pod分為三個QoS等級:Guaranteed(requests=limits,最後被驅逐)、Burstable(有requests但limits>requests,中等保障)、BestEffort(無requests/limits,最先被驅逐)。生產鐵律:關鍵服務必須設Guaranteed,批次處理任務用Burstable,測試環境可用BestEffort。
實踐4:PriorityClass優先級與搶佔
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: critical-service
value: 1000000
globalDefault: false
preemptionPolicy: PreemptLowerPriority
description: "Critical production services"
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: normal-service
value: 100000
globalDefault: true
preemptionPolicy: PreemptLowerPriority
description: "Normal production services"
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: batch-job
value: 10000
preemptionPolicy: Never
description: "Batch jobs, can be preempted"
package main
import (
"context"
"fmt"
"os"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
func checkPreemptionRisk(ctx context.Context, clientset *kubernetes.Clientset, namespace string) error {
pods, err := clientset.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{})
if err != nil {
return fmt.Errorf("list pods: %w", err)
}
lowPriority := int64(50000)
for _, pod := range pods.Items {
if pod.Spec.Priority != nil && *pod.Spec.Priority < lowPriority {
fmt.Printf("WARNING: Pod %s has low priority (%d), at preemption risk\n",
pod.Name, *pod.Spec.Priority)
}
}
return nil
}
func main() {
config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
if err != nil {
fmt.Fprintf(os.Stderr, "build config: %v\n", err)
os.Exit(1)
}
cs, err := kubernetes.NewForConfig(config)
if err != nil {
fmt.Fprintf(os.Stderr, "create clientset: %v\n", err)
os.Exit(1)
}
ctx := context.Background()
namespaces := []string{"team-api", "team-data", "team-frontend"}
for _, ns := range namespaces {
fmt.Printf("=== Checking namespace: %s ===\n", ns)
if err := checkPreemptionRisk(ctx, cs, ns); err != nil {
fmt.Fprintf(os.Stderr, "check %s: %v\n", ns, err)
}
}
}
PriorityClass定義Pod排程優先級,value越大優先級越高。當叢集資源不足時,高優先級Pod會搶佔低優先級Pod的資源。關鍵:preemptionPolicy: Never表示該優先級Pod不會主動搶佔,適合批次處理任務;globalDefault: true設定預設優先級。
實踐5:多租戶成本分攤與計量
package main
import (
"context"
"fmt"
"os"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
type TenantUsage struct {
Namespace string
CPURequests float64
CPULimits float64
MemoryRequest float64
MemoryLimits float64
PodCount int
}
func collectTenantUsage(ctx context.Context, clientset *kubernetes.Clientset) ([]TenantUsage, error) {
namespaces, err := clientset.CoreV1().Namespaces().List(ctx, metav1.ListOptions{
LabelSelector: "tenant",
})
if err != nil {
return nil, fmt.Errorf("list namespaces: %w", err)
}
var usages []TenantUsage
for _, ns := range namespaces.Items {
pods, err := clientset.CoreV1().Pods(ns.Name).List(ctx, metav1.ListOptions{})
if err != nil {
continue
}
usage := TenantUsage{Namespace: ns.Name}
for _, pod := range pods.Items {
if pod.Status.Phase != corev1.PodRunning {
continue
}
usage.PodCount++
for _, c := range pod.Spec.Containers {
if req := c.Resources.Requests; req != nil {
usage.CPURequests += req.Cpu().AsApproximateFloat64()
usage.MemoryRequest += req.Memory().AsApproximateFloat64() / 1024 / 1024 / 1024
}
if lim := c.Resources.Limits; lim != nil {
usage.CPULimits += lim.Cpu().AsApproximateFloat64()
usage.MemoryLimits += lim.Memory().AsApproximateFloat64() / 1024 / 1024 / 1024
}
}
}
usages = append(usages, usage)
}
return usages, nil
}
func main() {
config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
if err != nil {
fmt.Fprintf(os.Stderr, "build config: %v\n", err)
os.Exit(1)
}
cs, err := kubernetes.NewForConfig(config)
if err != nil {
fmt.Fprintf(os.Stderr, "create clientset: %v\n", err)
os.Exit(1)
}
ctx := context.Background()
usages, err := collectTenantUsage(ctx, cs)
if err != nil {
fmt.Fprintf(os.Stderr, "collect usage: %v\n", err)
os.Exit(1)
}
nodePricePerCPU := 50.0
nodePricePerGBMem := 5.0
fmt.Printf("\n=== Tenant Cost Report (%s) ===\n", time.Now().Format("2006-01-02"))
fmt.Printf("%-15s %8s %8s %10s %10s %6s %10s\n",
"Namespace", "CPU Req", "CPU Lim", "Mem Req(G)", "Mem Lim(G)", "Pods", "Est.Cost($)")
for _, u := range usages {
cost := u.CPURequests*nodePricePerCPU + u.MemoryRequest*nodePricePerGBMem
fmt.Printf("%-15s %8.2f %8.2f %10.2f %10.2f %6d %10.2f\n",
u.Namespace, u.CPURequests, u.CPULimits, u.MemoryRequest, u.MemoryLimits, u.PodCount, cost)
}
}
透過client-go收集每個命名空間的CPU/記憶體使用量,按定價模型計算成本分攤。關鍵:成本分攤應基於requests而非actual usage,因為requests佔用了排程承諾。結合Prometheus的kube_resourcequota指標可實現更精確的即時計量。
實踐6:資源治理自動化Controller
package main
import (
"context"
"fmt"
"os"
"time"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
)
type QuotaController struct {
clientset *kubernetes.Clientset
}
func (c *QuotaController) ensureLimitRange(ns string) error {
lrs, err := c.clientset.CoreV1().LimitRanges(ns).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return fmt.Errorf("list limitranges: %w", err)
}
if len(lrs.Items) > 0 {
return nil
}
lr := &corev1.LimitRange{
ObjectMeta: metav1.ObjectMeta{Name: "default-limits"},
Spec: corev1.LimitRangeSpec{
Limits: []corev1.LimitRangeItem{
{
Type: corev1.LimitTypeContainer,
Default: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
},
DefaultRequest: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("200m"),
corev1.ResourceMemory: resource.MustParse("256Mi"),
},
Max: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("4"),
corev1.ResourceMemory: resource.MustParse("8Gi"),
},
Min: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("50m"),
corev1.ResourceMemory: resource.MustParse("64Mi"),
},
},
},
},
}
_, err = c.clientset.CoreV1().LimitRanges(ns).Create(context.TODO(), lr, metav1.CreateOptions{})
if err != nil {
return fmt.Errorf("create limitrange: %w", err)
}
fmt.Printf("Auto-created LimitRange for namespace %s\n", ns)
return nil
}
func (c *QuotaController) Run(stopCh <-chan struct{}) {
factory := informers.NewSharedInformerFactory(c.clientset, 30*time.Second)
nsInformer := factory.Core().V1().Namespaces().Informer()
nsInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
ns := obj.(*corev1.Namespace)
if ns.Labels["tenant"] != "" {
if err := c.ensureLimitRange(ns.Name); err != nil {
fmt.Fprintf(os.Stderr, "ensure limitrange for %s: %v\n", ns.Name, err)
}
}
},
})
factory.Start(stopCh)
factory.WaitForCacheSync(stopCh)
wait.Until(func() {}, time.Minute, stopCh)
}
func main() {
config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))
if err != nil {
fmt.Fprintf(os.Stderr, "build config: %v\n", err)
os.Exit(1)
}
cs, err := kubernetes.NewForConfig(config)
if err != nil {
fmt.Fprintf(os.Stderr, "create clientset: %v\n", err)
os.Exit(1)
}
ctrl := &QuotaController{clientset: cs}
stopCh := make(chan struct{})
defer close(stopCh)
fmt.Println("Starting Quota Governance Controller...")
ctrl.Run(stopCh)
}
自動化Controller監聽Namespace建立事件,為帶tenant標籤的命名空間自動注入LimitRange,確保每個租戶命名空間都有預設資源約束。關鍵:生產環境應擴展為同時自動建立ResourceQuota、NetworkPolicy和RBAC,實現租戶Onboarding全自動化。
5大避坑指南
❌ 坑1:只設ResourceQuota不設LimitRange ✅ ResourceQuota限制總量,但單個Pod仍可佔滿配額。LimitRange約束單個容器資源範圍,兩者必須配合使用。
❌ 坑2:requests和limits設成一樣 ✅ 所有Pod設Guaranteed(requests=limits)會導致資源嚴重浪費。關鍵服務用Guaranteed,普通服務用Burstable,批次處理用BestEffort。
❌ 坑3:忽略ResourceQuota的scopes ✅ 不區分Terminating/NotTerminating,批次處理Job和長期服務共享配額,Job可能耗盡配額導致服務無法部署。
❌ 坑4:PriorityClass搶佔導致迴圈驅逐
✅ 兩個同優先級Pod互相搶佔會形成驅逐迴圈。設定不同的優先級值,批次處理任務用preemptionPolicy: Never。
❌ 坑5:成本分攤基於實際使用量而非requests ✅ requests佔用了排程承諾,即使Pod空閒,這些資源也無法分配給其他Pod。成本分攤應基於requests,而非actual usage。
10大報錯排查
| 錯誤現象 | 可能原因 | 排查指令 | 解決方案 |
|---|---|---|---|
| Pod建立報Forbidden exceeded quota | 命名空間配額已滿 | kubectl describe quota -n <ns> |
增加配額或減少已有Pod資源 |
| Pod狀態Pending | 命名空間配額不足或節點資源不足 | kubectl describe pod <pod> |
檢查quota和節點可用資源 |
| LimitRange注入資源後Pod OOM | default值設定過高/過低 | kubectl get limitrange -n <ns> -o yaml |
調整default和defaultRequest |
| ResourceQuota不生效 | scopes與Pod型別不匹配 | kubectl describe quota -n <ns> |
檢查scopes是否包含Pod型別 |
| BestEffort Pod耗盡資源 | 未配置LimitRange | kubectl get limitrange -A |
為所有租戶命名空間建立LimitRange |
| 高優先級Pod無法搶佔 | preemptionPolicy設為Never | kubectl get priorityclass -o yaml |
修改preemptionPolicy |
| 命名空間配額超賣 | 各NS配額之和超過叢集容量 | kubectl get quota -A |
預留20%緩衝,配額總和≤叢集80% |
| 成本分攤資料缺失 | 未按命名空間標記tenant | kubectl get ns --show-labels |
為所有租戶NS新增tenant標籤 |
| Pod被驅逐後無法重新排程 | 優先級低於執行中Pod | kubectl describe pod <pod> |
提高PriorityClass或釋放資源 |
| LimitRange maxLimitRequestRatio報錯 | limit/request比例超限 | kubectl describe limitrange -n <ns> |
調整Pod的limit/request比例 |
進階優化
1. 層級配額管理。使用K8s Hierarchical Namespace Controller實現父子命名空間配額繼承,父NS配額自動分配給子NS,避免手動配額分配。
2. 動態配額調整。基於Prometheus監控的kube_resourcequota_usage指標,當配額使用率持續>85%時自動擴容配額,<30%時建議縮容。
3. 策略即程式碼。結合OPA/Kyverno實現配額策略自動化審計,拒絕不符合資源規範的Deployment建立,從源頭杜絕資源濫用。
4. 多叢集配額聯邦。使用Karmada/KubeFed實現跨叢集配額排程,當單叢集配額不足時自動排程到有容量的叢集。
5. FinOps儀表盤。結合Prometheus+Grafana構建租戶成本儀表盤,即時展示各團隊資源使用和成本趨勢,推動成本意識文化。
對比分析:K8s原生 vs OPA vs Kyverno vs 自建Controller
| 特性 | K8s原生ResourceQuota | OpenPolicyAgent | Kyverno | 自建Controller |
|---|---|---|---|---|
| 學習成本 | ⭐ 低 | ⭐⭐⭐ 高 | ⭐⭐ 中 | ⭐⭐⭐ 高 |
| 配額限制 | ✅ 原生支援 | ⚠️ 需自定義策略 | ✅ 透過Policy支援 | ✅ 完全自定義 |
| 預設值注入 | ✅ LimitRange | ⚠️ 需Mutation | ✅ Mutation Policy | ✅ 完全自定義 |
| 策略靈活性 | ⭐⭐ 有限 | ⭐⭐⭐⭐⭐ 極高 | ⭐⭐⭐⭐ 高 | ⭐⭐⭐⭐⭐ 極高 |
| 成本計量 | ❌ 不支援 | ⚠️ 需整合 | ⚠️ 需整合 | ✅ 可內建 |
| 維運複雜度 | ⭐ 低 | ⭐⭐⭐⭐ 高 | ⭐⭐⭐ 中 | ⭐⭐⭐⭐ 高 |
| 生產成熟度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 推薦場景 | 基礎配額隔離 | 複雜策略合規 | 策略+Mutation | 定製化治理 |
總結展望
K8s多租戶資源治理不是設一個ResourceQuota就完事,而是ResourceQuota限制總量、LimitRange約束單體、QoS分級保障、PriorityClass優先排程、成本計量分攤、自動化Controller兜底的六位一體體系。6個關鍵實踐涵蓋了從配額定義到成本分攤的完整治理鏈路。記住:配額必設、限制必配、優先級必分、成本必算,才能實現真正的多租戶資源隔離。未來,基於AI的智慧配額推薦和Serverless化資源排程將進一步降低治理複雜度。
線上工具推薦
- JSON格式化工具 — 格式化ResourceQuota/LimitRange的YAML/JSON配置,快速排查配額定義問題
- YAML轉JSON工具 — 將K8s YAML配置轉為JSON,便於程式化處理配額策略
- 雜湊計算工具 — 計算ConfigMap和Secret校驗值,確保配額配置資料完整性
延伸閱讀
本站提供瀏覽器本地工具,免註冊即可試用 →