restructure: console→client-console, add admin-console skeleton, move docs to doc/
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
package cloud
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
)
|
||||
|
||||
var (
|
||||
quotaGVR = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "resourcequotas"}
|
||||
limitRangeGVR = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "limitranges"}
|
||||
)
|
||||
|
||||
// ApplyResourceQuota создаёт ResourceQuota и LimitRange в namespace ns.
|
||||
// Параметры берутся из env vars (см. ниже) — можно тюнить без пересборки.
|
||||
// Идемпотентно: если объекты уже существуют — пропускается без ошибки.
|
||||
//
|
||||
// ResourceQuota ограничивает суммарные ресурсы пользователя:
|
||||
// - CPU / memory requests и limits
|
||||
// - Количество подов, функций, пакетов, triggers
|
||||
//
|
||||
// LimitRange задаёт дефолтные limits/requests на контейнер:
|
||||
// поды без явных limits получают defaults автоматически → нет unbounded containers.
|
||||
//
|
||||
// Env vars (все опциональны, defaults указаны ниже):
|
||||
//
|
||||
// QUOTA_REQ_CPU — суммарный CPU requests (default: "1")
|
||||
// QUOTA_REQ_MEM — суммарная memory requests (default: "2Gi")
|
||||
// QUOTA_LIM_CPU — суммарный CPU limits (default: "12")
|
||||
// QUOTA_LIM_MEM — суммарная memory limits (default: "6Gi")
|
||||
// QUOTA_PODS — макс. количество подов (default: "30")
|
||||
// QUOTA_FUNCTIONS — макс. количество функций (default: "20")
|
||||
// QUOTA_PACKAGES — макс. количество пакетов (default: "40")
|
||||
// QUOTA_HTTPTRIGGERS — макс. количество HTTP triggers (default: "20")
|
||||
// LIMIT_DEFAULT_CPU — дефолтный CPU limit на контейнер (default: "500m")
|
||||
// LIMIT_DEFAULT_MEM — дефолтная memory limit на контейнер (default: "256Mi")
|
||||
// LIMIT_REQ_CPU — дефолтный CPU request на контейнер (default: "50m")
|
||||
// LIMIT_REQ_MEM — дефолтный memory request на контейнер (default: "64Mi")
|
||||
// LIMIT_MAX_CPU — максимальный CPU limit на контейнер (default: "2")
|
||||
// LIMIT_MAX_MEM — максимальная memory limit на контейнер (default: "1Gi")
|
||||
func ApplyResourceQuota(ctx context.Context, dyn dynamic.Interface, ns string) {
|
||||
quotaObj := &unstructured.Unstructured{Object: map[string]any{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ResourceQuota",
|
||||
"metadata": map[string]any{"name": "user-quota", "namespace": ns},
|
||||
"spec": map[string]any{
|
||||
"hard": map[string]any{
|
||||
"requests.cpu": envDefault("QUOTA_REQ_CPU", "1"),
|
||||
"requests.memory": envDefault("QUOTA_REQ_MEM", "2Gi"),
|
||||
"limits.cpu": envDefault("QUOTA_LIM_CPU", "12"),
|
||||
"limits.memory": envDefault("QUOTA_LIM_MEM", "6Gi"),
|
||||
"pods": envDefault("QUOTA_PODS", "30"),
|
||||
"count/functions.fission.io": envDefault("QUOTA_FUNCTIONS", "20"),
|
||||
"count/packages.fission.io": envDefault("QUOTA_PACKAGES", "40"),
|
||||
"count/httptriggers.fission.io": envDefault("QUOTA_HTTPTRIGGERS", "20"),
|
||||
},
|
||||
},
|
||||
}}
|
||||
_, err := dyn.Resource(quotaGVR).Namespace(ns).Create(ctx, quotaObj, metav1.CreateOptions{})
|
||||
if err != nil && !apierrors.IsAlreadyExists(err) {
|
||||
log.Printf("cloud.ApplyResourceQuota: %s: %v", ns, err)
|
||||
}
|
||||
|
||||
limitRangeObj := &unstructured.Unstructured{Object: map[string]any{
|
||||
"apiVersion": "v1",
|
||||
"kind": "LimitRange",
|
||||
"metadata": map[string]any{"name": "user-limits", "namespace": ns},
|
||||
"spec": map[string]any{
|
||||
"limits": []any{
|
||||
map[string]any{
|
||||
"type": "Container",
|
||||
"default": map[string]any{
|
||||
"cpu": envDefault("LIMIT_DEFAULT_CPU", "500m"),
|
||||
"memory": envDefault("LIMIT_DEFAULT_MEM", "256Mi"),
|
||||
},
|
||||
"defaultRequest": map[string]any{
|
||||
"cpu": envDefault("LIMIT_REQ_CPU", "50m"),
|
||||
"memory": envDefault("LIMIT_REQ_MEM", "64Mi"),
|
||||
},
|
||||
"max": map[string]any{
|
||||
"cpu": envDefault("LIMIT_MAX_CPU", "2"),
|
||||
"memory": envDefault("LIMIT_MAX_MEM", "1Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
_, err = dyn.Resource(limitRangeGVR).Namespace(ns).Create(ctx, limitRangeObj, metav1.CreateOptions{})
|
||||
if err != nil && !apierrors.IsAlreadyExists(err) {
|
||||
log.Printf("cloud.ApplyResourceQuota LimitRange: %s: %v", ns, err)
|
||||
}
|
||||
}
|
||||
|
||||
// envDefault читает env переменную или возвращает fallback.
|
||||
func envDefault(key, fallback string) string {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
return v
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
Reference in New Issue
Block a user