forked from LaconicNetwork/kompose
Merge branch 'main' into feature-1846-network_mode-service
This commit is contained in:
@@ -31,7 +31,7 @@ import (
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/kubernetes/kompose/pkg/kobject"
|
||||
"github.com/kubernetes/kompose/pkg/loader/compose"
|
||||
@@ -41,6 +41,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v3"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
hpa "k8s.io/api/autoscaling/v2beta2"
|
||||
api "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -48,6 +49,29 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// Default values for Horizontal Pod Autoscaler (HPA)
|
||||
const (
|
||||
DefaultMinReplicas = 1
|
||||
DefaultMaxReplicas = 3
|
||||
DefaultCPUUtilization = 50
|
||||
DefaultMemoryUtilization = 70
|
||||
)
|
||||
|
||||
// LabelKeys are the keys for HPA related labels in the service
|
||||
var LabelKeys = []string{
|
||||
compose.LabelHpaCPU,
|
||||
compose.LabelHpaMemory,
|
||||
compose.LabelHpaMinReplicas,
|
||||
compose.LabelHpaMaxReplicas,
|
||||
}
|
||||
|
||||
type HpaValues struct {
|
||||
MinReplicas int32
|
||||
MaxReplicas int32
|
||||
CPUtilization int32
|
||||
MemoryUtilization int32
|
||||
}
|
||||
|
||||
const (
|
||||
NetworkModeService = "service:"
|
||||
)
|
||||
@@ -1040,6 +1064,125 @@ func parseContainerCommandsFromStr(line string) []string {
|
||||
return commands
|
||||
}
|
||||
|
||||
// searchHPAValues is useful to check if labels
|
||||
// contains any labels related to Horizontal Pod Autoscaler
|
||||
func searchHPAValues(labels map[string]string) bool {
|
||||
for _, value := range LabelKeys {
|
||||
if _, ok := labels[value]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// createHPAResources creates a HorizontalPodAutoscaler (HPA) resource
|
||||
// It sets the number of replicas in the service to 0 because
|
||||
// the number of replicas will be managed by the HPA
|
||||
func createHPAResources(name string, service *kobject.ServiceConfig) hpa.HorizontalPodAutoscaler {
|
||||
valuesHpa := getResourceHpaValues(service)
|
||||
service.Replicas = 0
|
||||
metrics := getHpaMetricSpec(valuesHpa)
|
||||
scalerSpecs := hpa.HorizontalPodAutoscaler{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "HorizontalPodAutoscaler",
|
||||
APIVersion: "autoscaling/v2",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Spec: hpa.HorizontalPodAutoscalerSpec{
|
||||
ScaleTargetRef: hpa.CrossVersionObjectReference{
|
||||
Kind: "Deployment",
|
||||
Name: name,
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
MinReplicas: &valuesHpa.MinReplicas,
|
||||
MaxReplicas: valuesHpa.MaxReplicas,
|
||||
Metrics: metrics,
|
||||
},
|
||||
}
|
||||
|
||||
return scalerSpecs
|
||||
}
|
||||
|
||||
// getResourceHpaValues retrieves the min/max replicas and CPU/memory utilization values
|
||||
// control if maxReplicas is less than minReplicas
|
||||
func getResourceHpaValues(service *kobject.ServiceConfig) HpaValues {
|
||||
minReplicas := getHpaValue(service, compose.LabelHpaMinReplicas, DefaultMinReplicas)
|
||||
maxReplicas := getHpaValue(service, compose.LabelHpaMaxReplicas, DefaultMaxReplicas)
|
||||
|
||||
if maxReplicas < minReplicas {
|
||||
log.Warnf("maxReplicas %d is less than minReplicas %d. Using minReplicas value %d", maxReplicas, minReplicas, minReplicas)
|
||||
maxReplicas = minReplicas
|
||||
}
|
||||
|
||||
cpuUtilization := validatePercentageMetric(service, compose.LabelHpaCPU, DefaultCPUUtilization)
|
||||
memoryUtilization := validatePercentageMetric(service, compose.LabelHpaMemory, DefaultMemoryUtilization)
|
||||
|
||||
return HpaValues{
|
||||
MinReplicas: minReplicas,
|
||||
MaxReplicas: maxReplicas,
|
||||
CPUtilization: cpuUtilization,
|
||||
MemoryUtilization: memoryUtilization,
|
||||
}
|
||||
}
|
||||
|
||||
// validatePercentageMetric validates the CPU or memory metrics value
|
||||
// ensuring that it falls within the acceptable range [1, 100].
|
||||
func validatePercentageMetric(service *kobject.ServiceConfig, metricLabel string, defaultValue int32) int32 {
|
||||
metricValue := getHpaValue(service, metricLabel, defaultValue)
|
||||
if metricValue > 100 || metricValue < 1 {
|
||||
log.Warnf("Metric value %d is not within the acceptable range [1, 100]. Using default value %d", metricValue, defaultValue)
|
||||
return defaultValue
|
||||
}
|
||||
return metricValue
|
||||
}
|
||||
|
||||
// getHpaValue convert the label value to integer
|
||||
// If the label is not present or the conversion fails
|
||||
// it returns the provided default value
|
||||
func getHpaValue(service *kobject.ServiceConfig, label string, defaultValue int32) int32 {
|
||||
valueFromLabel, err := strconv.Atoi(service.Labels[label])
|
||||
if err != nil || valueFromLabel < 0 {
|
||||
log.Warnf("Error converting label %s. Using default value %d", label, defaultValue)
|
||||
return defaultValue
|
||||
}
|
||||
return int32(valueFromLabel)
|
||||
}
|
||||
|
||||
// getHpaMetricSpec returns a list of metric specs for the HPA resource
|
||||
// Target type is hardcoded to hpa.UtilizationMetricType
|
||||
// Each MetricSpec specifies the type metric CPU/memory and average utilization value
|
||||
// to trigger scaling
|
||||
func getHpaMetricSpec(hpaValues HpaValues) []hpa.MetricSpec {
|
||||
var metrics []hpa.MetricSpec
|
||||
if hpaValues.CPUtilization > 0 {
|
||||
metrics = append(metrics, hpa.MetricSpec{
|
||||
Type: hpa.ResourceMetricSourceType,
|
||||
Resource: &hpa.ResourceMetricSource{
|
||||
Name: api.ResourceCPU,
|
||||
Target: hpa.MetricTarget{
|
||||
Type: hpa.UtilizationMetricType,
|
||||
AverageUtilization: &hpaValues.CPUtilization,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
if hpaValues.MemoryUtilization > 0 {
|
||||
metrics = append(metrics, hpa.MetricSpec{
|
||||
Type: hpa.ResourceMetricSourceType,
|
||||
Resource: &hpa.ResourceMetricSource{
|
||||
Name: api.ResourceMemory,
|
||||
Target: hpa.MetricTarget{
|
||||
Type: hpa.UtilizationMetricType,
|
||||
AverageUtilization: &hpaValues.MemoryUtilization,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return metrics
|
||||
}
|
||||
|
||||
// fixNetworkModeToService is responsible for adjusting the network mode of services in docker compose (services:)
|
||||
// generate a mapping of deployments based on the network mode of each service
|
||||
// merging containers into the destination deployment, and removing transferred deployments
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/fatih/structs"
|
||||
"github.com/kubernetes/kompose/pkg/kobject"
|
||||
"github.com/kubernetes/kompose/pkg/loader/compose"
|
||||
@@ -1314,7 +1314,7 @@ func (k *Kubernetes) createConfigMapFromComposeConfig(name string, service kobje
|
||||
for _, config := range service.Configs {
|
||||
currentConfigName := config.Source
|
||||
currentConfigObj := service.ConfigsMetaData[currentConfigName]
|
||||
if currentConfigObj.External.External {
|
||||
if currentConfigObj.External {
|
||||
continue
|
||||
}
|
||||
currentFileName := currentConfigObj.File
|
||||
@@ -1654,6 +1654,10 @@ func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject.
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
err = k.configHorizontalPodScaler(name, service, opt, &objects)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error creating Kubernetes HPA")
|
||||
}
|
||||
allobjects = append(allobjects, objects...)
|
||||
}
|
||||
|
||||
@@ -1719,3 +1723,16 @@ func (k *Kubernetes) UpdateController(obj runtime.Object, updateTemplate func(*a
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// configHorizontalPodScaler create Hpa resource also append to the objects
|
||||
// first checks if the service labels contain any HPA labels using the searchHPAValues
|
||||
func (k *Kubernetes) configHorizontalPodScaler(name string, service kobject.ServiceConfig, opt kobject.ConvertOptions, objects *[]runtime.Object) (err error) {
|
||||
found := searchHPAValues(service.Labels)
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
||||
hpa := createHPAResources(name, &service)
|
||||
*objects = append(*objects, &hpa)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/compose-spec/compose-go/types"
|
||||
"github.com/compose-spec/compose-go/v2/types"
|
||||
|
||||
"github.com/kubernetes/kompose/pkg/kobject"
|
||||
"github.com/kubernetes/kompose/pkg/loader/compose"
|
||||
|
||||
@@ -121,7 +121,7 @@ func parseVolume(volume string) (name, host, container, mode string, err error)
|
||||
return
|
||||
}
|
||||
|
||||
// parseVolume parses window volume.
|
||||
// parseWindowsVolume parses window volume.
|
||||
// example: windows host mount to windows container
|
||||
// volume = dataVolumeName:C:\Users\Data:D:\config:rw
|
||||
// it can be parsed:
|
||||
|
||||
Reference in New Issue
Block a user