fix: fixup multi problem
This commit is contained in:
@@ -104,7 +104,15 @@ func main() {
|
||||
log.Fatalf("k8s client: %v", err)
|
||||
}
|
||||
|
||||
helmProv, err := demos.NewHelmProvisioner(&cfg, k8sClient, "/charts", "helm")
|
||||
// Client metrics.k8s.io (usage CPU/mémoire live) : optionnel, ne bloque
|
||||
// pas le démarrage si metrics-server n'est pas déployé sur le cluster.
|
||||
metricsClient, err := k8s.NewMetricsClient(&cfg)
|
||||
if err != nil {
|
||||
log.Printf("metrics client indisponible (usage CPU/mémoire désactivé): %v", err)
|
||||
metricsClient = nil
|
||||
}
|
||||
|
||||
helmProv, err := demos.NewHelmProvisioner(&cfg, k8sClient, metricsClient, "/charts", "helm")
|
||||
if err != nil {
|
||||
log.Fatalf("helm provisioner: %v", err)
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ require (
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/klog/v2 v2.140.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect
|
||||
k8s.io/metrics v0.36.3 // indirect
|
||||
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
|
||||
@@ -181,6 +181,8 @@ k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
|
||||
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
|
||||
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg=
|
||||
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0=
|
||||
k8s.io/metrics v0.36.3 h1:NDKceAgWS8CJCdDtM5kFACkBOa9Lxia1jUiibJfvUgQ=
|
||||
k8s.io/metrics v0.36.3/go.mod h1:NTLS8ybwn+zYGwKqYublWPvmnNp8N4pV3etjtx7XWaM=
|
||||
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=
|
||||
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
metricsclient "k8s.io/metrics/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
// HelmProvisioner : implémente Provisioner en appelant l'exécutable Helm.
|
||||
@@ -24,7 +25,8 @@ import (
|
||||
type HelmProvisioner struct {
|
||||
cfg *config.Config
|
||||
k8sClient *kubernetes.Clientset
|
||||
chartsDir string // chemin vers le dossier des charts (ex: /charts)
|
||||
metricsClient *metricsclient.Clientset // optionnel : nil si metrics-server indisponible
|
||||
chartsDir string // chemin vers le dossier des charts (ex: /charts)
|
||||
frontendImage string
|
||||
backendImage string
|
||||
baseDomain string
|
||||
@@ -34,9 +36,11 @@ type HelmProvisioner struct {
|
||||
// NewHelmProvisioner crée un nouveau provisioner Helm.
|
||||
// chartsDir : chemin absolu vers le dossier contenant les charts (backend/, frontend/)
|
||||
// helmPath : chemin vers l'exécutable helm (optionnel, default: "helm")
|
||||
// metricsClient : client metrics.k8s.io pour l'usage CPU/mémoire live (optionnel, peut être nil).
|
||||
func NewHelmProvisioner(
|
||||
cfg *config.Config,
|
||||
k8sClient *kubernetes.Clientset,
|
||||
metricsClient *metricsclient.Clientset,
|
||||
chartsDir string,
|
||||
helmPath string,
|
||||
) (*HelmProvisioner, error) {
|
||||
@@ -55,6 +59,7 @@ func NewHelmProvisioner(
|
||||
return &HelmProvisioner{
|
||||
cfg: cfg,
|
||||
k8sClient: k8sClient,
|
||||
metricsClient: metricsClient,
|
||||
chartsDir: chartsDir,
|
||||
frontendImage: cfg.FrontendImage,
|
||||
backendImage: cfg.BackendImage,
|
||||
@@ -336,6 +341,38 @@ func (h *HelmProvisioner) waitForRollout(namespace string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// componentResourceLimits : limites CPU/mémoire configurées dans chaque chart
|
||||
// (deploy/chart-gestion/*/values.yaml), utilisées pour calculer un % d'usage.
|
||||
var componentResourceLimits = map[string]struct {
|
||||
cpuMilli int64
|
||||
memMi int64
|
||||
}{
|
||||
"backend": {cpuMilli: 500, memMi: 256},
|
||||
"frontend": {cpuMilli: 200, memMi: 128},
|
||||
"postgresql": {cpuMilli: 1000, memMi: 1024},
|
||||
"redis": {cpuMilli: 500, memMi: 512},
|
||||
}
|
||||
|
||||
// componentKey identifie le composant (backend/frontend/postgresql/redis) à
|
||||
// partir du nom de pod généré par Helm (ex: "demo-xxx-backend-...-6d59f4-abcde").
|
||||
func componentKey(podName string) string {
|
||||
switch {
|
||||
case strings.Contains(podName, "backend"):
|
||||
return "backend"
|
||||
case strings.Contains(podName, "frontend"):
|
||||
return "frontend"
|
||||
case strings.Contains(podName, "postgresql"):
|
||||
return "postgresql"
|
||||
case strings.Contains(podName, "redis"):
|
||||
return "redis"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// GetResourceState : phase + usage CPU/mémoire live de chaque pod d'une démo.
|
||||
// L'usage (metrics-server) est best-effort : s'il est indisponible, seule la
|
||||
// phase du pod est renseignée plutôt que de faire échouer tout l'appel.
|
||||
func (h *HelmProvisioner) GetResourceState(
|
||||
ctx context.Context,
|
||||
namespace string,
|
||||
@@ -349,23 +386,47 @@ func (h *HelmProvisioner) GetResourceState(
|
||||
return ResourceState{}, err
|
||||
}
|
||||
|
||||
usage := map[string][2]int64{} // pod name -> [cpuMilli, memMi]
|
||||
if h.metricsClient != nil {
|
||||
if list, err := h.metricsClient.MetricsV1beta1().PodMetricses(namespace).List(ctx, metav1.ListOptions{}); err == nil {
|
||||
for _, m := range list.Items {
|
||||
var cpu, mem int64
|
||||
for _, c := range m.Containers {
|
||||
cpu += c.Usage.Cpu().MilliValue()
|
||||
mem += c.Usage.Memory().Value() / (1024 * 1024)
|
||||
}
|
||||
usage[m.Name] = [2]int64{cpu, mem}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var state ResourceState
|
||||
|
||||
for _, pod := range pods.Items {
|
||||
status := string(pod.Status.Phase)
|
||||
key := componentKey(pod.Name)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.Contains(pod.Name, "backend"):
|
||||
state.APIState = status
|
||||
cs := ComponentState{Phase: string(pod.Status.Phase)}
|
||||
if limits, ok := componentResourceLimits[key]; ok {
|
||||
cs.CPULimitMilli = limits.cpuMilli
|
||||
cs.MemoryLimitMi = limits.memMi
|
||||
}
|
||||
if u, ok := usage[pod.Name]; ok {
|
||||
cs.CPUMilli = u[0]
|
||||
cs.MemoryMi = u[1]
|
||||
}
|
||||
|
||||
case strings.Contains(pod.Name, "frontend"):
|
||||
state.WebState = status
|
||||
|
||||
case strings.Contains(pod.Name, "postgresql"):
|
||||
state.DBState = status
|
||||
|
||||
case strings.Contains(pod.Name, "redis"):
|
||||
state.DBMemoryState = status
|
||||
switch key {
|
||||
case "backend":
|
||||
state.API = cs
|
||||
case "frontend":
|
||||
state.Web = cs
|
||||
case "postgresql":
|
||||
state.DB = cs
|
||||
case "redis":
|
||||
state.DBM = cs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,11 +27,21 @@ type ExternalResource struct {
|
||||
|
||||
func (ExternalResource) TableName() string { return "external_pool" }
|
||||
|
||||
type ResourceState struct {
|
||||
APIState string `gorm:"size:20;not null" json:"api_state"`
|
||||
WebState string `gorm:"size:20;not null" json:"web_state"`
|
||||
DBState string `gorm:"size:20;not null" json:"db_state"`
|
||||
DBMemoryState string `gorm:"size:20;not null" json:"dbm_state"`
|
||||
// ComponentState : état live d'un composant (pod) d'une démo — phase k8s +
|
||||
// usage CPU/mémoire actuel rapporté par metrics-server, avec les limites
|
||||
// configurées dans le chart Helm correspondant (pour calculer un pourcentage).
|
||||
type ComponentState struct {
|
||||
Phase string `json:"phase"` // Running, Pending, Failed, Unknown, "" si pod introuvable
|
||||
CPUMilli int64 `json:"cpu_milli"` // usage CPU actuel, en millicores
|
||||
CPULimitMilli int64 `json:"cpu_limit_milli"` // limite CPU configurée, en millicores
|
||||
MemoryMi int64 `json:"memory_mi"` // usage mémoire actuel, en Mi
|
||||
MemoryLimitMi int64 `json:"memory_limit_mi"` // limite mémoire configurée, en Mi
|
||||
}
|
||||
|
||||
func (ResourceState) TableName() string { return "ressource_state" }
|
||||
// ResourceState : état live des 4 composants d'une démo.
|
||||
type ResourceState struct {
|
||||
API ComponentState `json:"api"`
|
||||
Web ComponentState `json:"web"`
|
||||
DB ComponentState `json:"db"`
|
||||
DBM ComponentState `json:"dbm"`
|
||||
}
|
||||
|
||||
@@ -8,19 +8,18 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
metricsclient "k8s.io/metrics/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
func NewClient(cfg *config.Config) (*kubernetes.Clientset, error) {
|
||||
var (
|
||||
k8sCfg *rest.Config
|
||||
err error
|
||||
)
|
||||
|
||||
func restConfig(cfg *config.Config) (*rest.Config, error) {
|
||||
if cfg.Kubeconfig != "" {
|
||||
k8sCfg, err = clientcmd.BuildConfigFromFlags("", cfg.Kubeconfig)
|
||||
} else {
|
||||
k8sCfg, err = rest.InClusterConfig()
|
||||
return clientcmd.BuildConfigFromFlags("", cfg.Kubeconfig)
|
||||
}
|
||||
return rest.InClusterConfig()
|
||||
}
|
||||
|
||||
func NewClient(cfg *config.Config) (*kubernetes.Clientset, error) {
|
||||
k8sCfg, err := restConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("k8s config: %w", err)
|
||||
}
|
||||
@@ -32,3 +31,19 @@ func NewClient(cfg *config.Config) (*kubernetes.Clientset, error) {
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// NewMetricsClient crée un client pour l'API metrics.k8s.io (metrics-server),
|
||||
// utilisée pour lire l'usage CPU/mémoire en direct des pods.
|
||||
func NewMetricsClient(cfg *config.Config) (*metricsclient.Clientset, error) {
|
||||
k8sCfg, err := restConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("k8s config: %w", err)
|
||||
}
|
||||
|
||||
client, err := metricsclient.NewForConfig(k8sCfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("metrics clientset: %w", err)
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user