added this labels:

kompose.hpa.minreplicas
kompose.hpa.maxreplicas
kompose.hpa.cpu
kompose.hpa.memory

documentated labels user_guide.md

generate custom metrics from cpu, memory and set min/max replicas

Signed-off-by: jose luis <2064537+sosan@users.noreply.github.com>
This commit is contained in:
jose luis 2024-03-26 20:58:57 +01:00
parent 14152d4a81
commit a38f7f9ea3
No known key found for this signature in database
GPG Key ID: 6D23FAD11F88081A
5 changed files with 792 additions and 0 deletions

View File

@ -211,6 +211,10 @@ The currently supported options are:
| kompose.cronjob.schedule | kubernetes cronjob schedule (for example: '1 * * * *') | | kompose.cronjob.schedule | kubernetes cronjob schedule (for example: '1 * * * *') |
| kompose.cronjob.concurrency_policy | 'Forbid' / 'Allow' / 'Never' / '' | | kompose.cronjob.concurrency_policy | 'Forbid' / 'Allow' / 'Never' / '' |
| kompose.cronjob.backoff_limit | kubernetes cronjob backoff limit (for example: '6') | | kompose.cronjob.backoff_limit | kubernetes cronjob backoff limit (for example: '6') |
| kompose.hpa.minreplicas | defines Horizontal Pod Autoscaler min pod replicas |
| kompose.hpa.maxreplicas | defines Horizontal Pod Autoscaler max pod replicas |
| kompose.hpa.cpu | defines Horizontal Pod Autoscaler cpu utilization trigger |
| kompose.hpa.memory | defines Horizontal Pod Autoscaler memory utilization trigger |
**Note**: `kompose.service.type` label should be defined with `ports` only (except for headless service), otherwise `kompose` will fail. **Note**: `kompose.service.type` label should be defined with `ports` only (except for headless service), otherwise `kompose` will fail.
@ -467,6 +471,63 @@ services:
labels: labels:
kompose.volume.sub-path: pg-data kompose.volume.sub-path: pg-data
``` ```
- `kompose.hpa.minreplicas` defines minimum replicas from Horizontal Pod Autoscaler. Default value 1 [HPA Min Replicas](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics).
For example:
```yaml
version: '3.8'
services:
pgadmin:
image: postgres
labels:
kompose.hpa.minreplicas: 1
```
- `kompose.hpa.maxreplicas` defines maximum replicas from Horizontal Pod Autoscaler. Default value 10 [HPA Max Replicas](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics).
For example:
```yaml
version: '3.8'
services:
pgadmin:
image: postgres
labels:
kompose.hpa.maxreplicas: 10
```
- `kompose.hpa.cpu` defines % cpu utilization trigger scale from Horizontal Pod Autoscaler. It is represented as a percentage of a resource. Default value: 50 [HPA CPU Utilization](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics).
For example:
```yaml
version: '3.8'
services:
pgadmin:
image: postgres
labels:
kompose.hpa.cpu: 50
```
- `kompose.hpa.memory` defines memory utilization trigger scale from Horizontal Pod Autoscaler. It is represented as a percentage of a resource. Default value: 70 [HPA Memory Utilization](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics).
For example:
```yaml
version: '3.8'
services:
pgadmin:
image: postgres
labels:
kompose.hpa.memory: 50
```
## Restart ## Restart
If you want to create normal pods without controller you can use `restart` construct of compose to define that. Follow table below to see what happens on the `restart` value. If you want to create normal pods without controller you can use `restart` construct of compose to define that. Follow table below to see what happens on the `restart` value.

View File

@ -87,6 +87,14 @@ const (
LabelCronJobConcurrencyPolicy = "kompose.cronjob.concurrency_policy" LabelCronJobConcurrencyPolicy = "kompose.cronjob.concurrency_policy"
// LabelCronJobBackoffLimit defines the job backoff limit // LabelCronJobBackoffLimit defines the job backoff limit
LabelCronJobBackoffLimit = "kompose.cronjob.backoff_limit" LabelCronJobBackoffLimit = "kompose.cronjob.backoff_limit"
// LabelHpaMinReplicas defines min pod replicas
LabelHpaMinReplicas = "kompose.hpa.minreplicas"
// LabelHpaMaxReplicas defines max pod replicas
LabelHpaMaxReplicas = "kompose.hpa.maxreplicas"
// LabelHpaCpu defines scaling decisions based on CPU utilization
LabelHpaCPU = "kompose.hpa.cpu"
// LabelHpaMemory defines scaling decisions based on memory utilization
LabelHpaMemory = "kompose.hpa.memory"
) )
// load environment variables from compose file // load environment variables from compose file

View File

@ -41,6 +41,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
hpa "k8s.io/api/autoscaling/v2beta2"
api "k8s.io/api/core/v1" api "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -48,6 +49,29 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
) )
// Default values for Horizontal Pod Autoscaler (HPA)
const (
DefaultMinReplicas = 1
DefaultMaxReplicas = 10
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
}
/** /**
* Generate Helm Chart configuration * Generate Helm Chart configuration
*/ */
@ -985,3 +1009,107 @@ func reformatSecretConfigUnderscoreWithDash(secretConfig types.ServiceSecretConf
return newSecretConfig return newSecretConfig
} }
// searchHPAValues is useful to check if labels
// contains any labels related to Horizontal Pod Autoscaler
func searchHPAValues(labels map[string]string) bool {
found := true
for _, value := range LabelKeys {
if _, ok := labels[value]; ok {
return found
}
}
return !found
}
// 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 {
maxReplicas = minReplicas
}
return HpaValues{
MinReplicas: minReplicas,
MaxReplicas: maxReplicas,
CPUtilization: getHpaValue(service, compose.LabelHpaCPU, DefaultCpuUtilization),
MemoryUtilization: getHpaValue(service, compose.LabelHpaMemory, DefaultMemoryUtilization),
}
}
// 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 {
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
}

View File

@ -29,7 +29,9 @@ import (
"github.com/kubernetes/kompose/pkg/testutils" "github.com/kubernetes/kompose/pkg/testutils"
"github.com/pkg/errors" "github.com/pkg/errors"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
hpa "k8s.io/api/autoscaling/v2beta2"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
/* /*
@ -738,3 +740,579 @@ func TestRemoveEmptyInterfaces(t *testing.T) {
}) })
} }
} }
func Test_getHpaValue(t *testing.T) {
type args struct {
service *kobject.ServiceConfig
label string
defaultValue int32
}
tests := []struct {
name string
args args
want int32
}{
// LabelHpaMinReplicas
{
name: "LabelHpaMinReplicas with 1 value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
label: compose.LabelHpaMinReplicas,
defaultValue: 1,
},
want: 1,
},
{
name: "LabelHpaMinReplicas with 0 value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "0",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
label: compose.LabelHpaMinReplicas,
defaultValue: 1,
},
want: 1,
},
{
name: "LabelHpaMinReplicas with error value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "cannot transform",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
label: compose.LabelHpaMinReplicas,
defaultValue: 1,
},
want: 1,
},
// LabelHpaMaxReplicas
{
name: "LabelHpaMaxReplicas with 10 value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
label: compose.LabelHpaMaxReplicas,
defaultValue: 30,
},
want: 10,
},
{
name: "LabelHpaMaxReplicas with 0 value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "0",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
label: compose.LabelHpaMaxReplicas,
defaultValue: 10,
},
want: 10,
},
{
name: "LabelHpaMaxReplicas with error value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "cannot transform",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
label: compose.LabelHpaMaxReplicas,
defaultValue: 10,
},
want: 10,
},
// LabelHpaCPU
{
name: "LabelHpaCPU with 50 value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
label: compose.LabelHpaCPU,
defaultValue: 30,
},
want: 50,
},
{
name: "LabelHpaCPU with 0 value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "0",
compose.LabelHpaMemory: "70",
},
},
label: compose.LabelHpaCPU,
defaultValue: 50,
},
want: 50,
},
{
name: "LabelHpaCPU with error value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "cannot transform",
compose.LabelHpaMemory: "70",
},
},
label: compose.LabelHpaCPU,
defaultValue: 50,
},
want: 50,
},
// LabelHpaMemory
{
name: "LabelHpaMemory with 70 value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
label: compose.LabelHpaMemory,
defaultValue: 30,
},
want: 70,
},
{
name: "LabelHpaMemory with 0 value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "0",
},
},
label: compose.LabelHpaMemory,
defaultValue: 70,
},
want: 70,
},
{
name: "LabelHpaMemory with error value",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "cannot transform",
},
},
label: compose.LabelHpaMemory,
defaultValue: 70,
},
want: 70,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getHpaValue(tt.args.service, tt.args.label, tt.args.defaultValue); got != tt.want {
t.Errorf("getHpaValue() = %v, want %v", got, tt.want)
}
})
}
}
func Test_getResourceHpaValues(t *testing.T) {
type args struct {
service *kobject.ServiceConfig
}
tests := []struct {
name string
args args
want HpaValues
}{
{
name: "check same values",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
},
want: HpaValues{
MinReplicas: 1,
MaxReplicas: 10,
CPUtilization: 50,
MemoryUtilization: 70,
},
},
{
name: "check same values",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "5",
compose.LabelHpaMaxReplicas: "3",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
},
want: HpaValues{
MinReplicas: 5,
MaxReplicas: 5,
CPUtilization: 50,
MemoryUtilization: 70,
},
},
{
name: "with error values and use default values from LabelHpaMinReplicas",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "cannot transform",
compose.LabelHpaMaxReplicas: "3",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
},
want: HpaValues{
MinReplicas: 1,
MaxReplicas: 3,
CPUtilization: 50,
MemoryUtilization: 70,
},
},
{
name: "LabelHpaMaxReplicas is minor to LabelHpaMinReplicas",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "6",
compose.LabelHpaMaxReplicas: "5",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
},
want: HpaValues{
MinReplicas: 6,
MaxReplicas: 6,
CPUtilization: 50,
MemoryUtilization: 70,
},
},
{
name: "error label and LabelHpaMaxReplicas is minor to LabelHpaMinReplicas",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "6",
compose.LabelHpaMaxReplicas: "5",
compose.LabelHpaCPU: "cannot transform",
compose.LabelHpaMemory: "70",
},
},
},
want: HpaValues{
MinReplicas: 6,
MaxReplicas: 6,
CPUtilization: 50,
MemoryUtilization: 70,
},
},
{
name: "error label and LabelHpaMaxReplicas is minor to LabelHpaMinReplicas",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "6",
compose.LabelHpaMaxReplicas: "5",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "cannot transform",
},
},
},
want: HpaValues{
MinReplicas: 6,
MaxReplicas: 6,
CPUtilization: 50,
MemoryUtilization: 70,
},
},
{
name: "all error label",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "cannot transform",
compose.LabelHpaMaxReplicas: "cannot transform",
compose.LabelHpaCPU: "cannot transform",
compose.LabelHpaMemory: "cannot transform",
},
},
},
want: HpaValues{
MinReplicas: 1,
MaxReplicas: 10,
CPUtilization: 50,
MemoryUtilization: 70,
},
},
{
name: "error label without some labels",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "cannot transform",
compose.LabelHpaMaxReplicas: "cannot transform",
},
},
},
want: HpaValues{
MinReplicas: 1,
MaxReplicas: 10,
CPUtilization: 50,
MemoryUtilization: 70,
},
},
{
name: "without labels, should return default values",
args: args{
service: &kobject.ServiceConfig{
Labels: map[string]string{},
},
},
want: HpaValues{
MinReplicas: 1,
MaxReplicas: 10,
CPUtilization: 50,
MemoryUtilization: 70,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getResourceHpaValues(tt.args.service); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getResourceHpaValues() = %v, want %v", got, tt.want)
}
})
}
}
func Test_getHpaMetricSpec(t *testing.T) {
valueCPUFixed := int32(50)
valueMemoryFixed := int32(70)
type args struct {
hpaValues HpaValues
}
tests := []struct {
name string
args args
want []hpa.MetricSpec
}{
{
name: "no values",
args: args{
hpaValues: HpaValues{},
},
want: nil,
},
{
name: "only cpu",
args: args{
hpaValues: HpaValues{
CPUtilization: 50,
},
},
want: []hpa.MetricSpec{
{
Type: hpa.ResourceMetricSourceType,
Resource: &hpa.ResourceMetricSource{
Name: "cpu",
Target: hpa.MetricTarget{
Type: hpa.UtilizationMetricType,
AverageUtilization: &valueCPUFixed,
},
},
},
},
},
{
name: "only memory",
args: args{
hpaValues: HpaValues{
MemoryUtilization: 70,
},
},
want: []hpa.MetricSpec{
{
Type: hpa.ResourceMetricSourceType,
Resource: &hpa.ResourceMetricSource{
Name: "memory",
Target: hpa.MetricTarget{
Type: hpa.UtilizationMetricType,
AverageUtilization: &valueMemoryFixed,
},
},
},
},
},
{
name: "cpu and memory",
args: args{
hpaValues: HpaValues{
CPUtilization: 50,
MemoryUtilization: 70,
},
},
want: []hpa.MetricSpec{
{
Type: hpa.ResourceMetricSourceType,
Resource: &hpa.ResourceMetricSource{
Name: "cpu",
Target: hpa.MetricTarget{
Type: hpa.UtilizationMetricType,
AverageUtilization: &valueCPUFixed,
},
},
},
{
Type: hpa.ResourceMetricSourceType,
Resource: &hpa.ResourceMetricSource{
Name: "memory",
Target: hpa.MetricTarget{
Type: hpa.UtilizationMetricType,
AverageUtilization: &valueMemoryFixed,
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getHpaMetricSpec(tt.args.hpaValues); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getHpaMetricSpec() = %v, want %v", got, tt.want)
}
})
}
}
func Test_createHPAResources(t *testing.T) {
valueCPUFixed := int32(50)
valueMemoryFixed := int32(70)
fixedMinReplicas := int32(1)
type args struct {
name string
service *kobject.ServiceConfig
}
tests := []struct {
name string
args args
want hpa.HorizontalPodAutoscaler
}{
{
name: "all labels",
args: args{
name: "web",
service: &kobject.ServiceConfig{
Labels: map[string]string{
compose.LabelHpaMinReplicas: "1",
compose.LabelHpaMaxReplicas: "10",
compose.LabelHpaCPU: "50",
compose.LabelHpaMemory: "70",
},
},
},
want: hpa.HorizontalPodAutoscaler{
TypeMeta: metav1.TypeMeta{
Kind: "HorizontalPodAutoscaler",
APIVersion: "autoscaling/v2",
},
ObjectMeta: metav1.ObjectMeta{
Name: "web",
},
Spec: hpa.HorizontalPodAutoscalerSpec{
ScaleTargetRef: hpa.CrossVersionObjectReference{
Kind: "Deployment",
Name: "web",
APIVersion: "apps/v1",
},
MinReplicas: &fixedMinReplicas,
MaxReplicas: 10,
Metrics: []hpa.MetricSpec{
{
Type: hpa.ResourceMetricSourceType,
Resource: &hpa.ResourceMetricSource{
Name: "cpu",
Target: hpa.MetricTarget{
Type: hpa.UtilizationMetricType,
AverageUtilization: &valueCPUFixed,
},
},
},
{
Type: hpa.ResourceMetricSourceType,
Resource: &hpa.ResourceMetricSource{
Name: "memory",
Target: hpa.MetricTarget{
Type: hpa.UtilizationMetricType,
AverageUtilization: &valueMemoryFixed,
},
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := createHPAResources(tt.args.name, tt.args.service); !reflect.DeepEqual(got, tt.want) {
t.Errorf("createHPAResources() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -1654,6 +1654,10 @@ func (k *Kubernetes) Transform(komposeObject kobject.KomposeObject, opt kobject.
return nil, err return nil, err
} }
} }
err = k.configHorizontalPodScaler(name, service, opt, &objects)
if err != nil {
return nil, errors.Wrap(err, "Error transforming Kubernetes objects")
}
allobjects = append(allobjects, objects...) allobjects = append(allobjects, objects...)
} }
@ -1718,3 +1722,16 @@ func (k *Kubernetes) UpdateController(obj runtime.Object, updateTemplate func(*a
} }
return nil 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
}